如何设计一个实时流计算系统?

运维 系统运维
实时流计算:业务系统根据实时的操作,不断生成事件(消息/调用),然后引起一系列的处理分析,这个过程是分散在多台计算机上并行完成的,看上去就像事件连续不断的流经多个计算节点处理,形成一个实时流计算系统。本文主要讲了做一个简单的流计算系统的方法。

实时流计算的场景归纳起来多半是:业务系统根据实时的操作,不断生成事件(消息/调用),然后引起一系列的处理分析,这个过程是分散在多台计算机上并行完成的,看上去就像事件连续不断的流经多个计算节点处理,形成一个实时流计算系统。

市场上流计算产品有很多,主要是通过消息中枢结合工人模式实现,大致过程如下:

1、开发者实现好流程输入输出节点逻辑,上传job到任务生产者

2、任务生产者将任务发送到zookeeper,然后监控任务状态

3、任务消费者从zookeeper上获取任务

4、任务消费者启动多个工人进程,每个进程又启动多个线程执行任务

5、工人之间通过zeroMQ交互

我们看看如何做一个简单的流计算系统,做法跟上面有些不同:

1、首先不过多依赖zookeerper,任务的分配最好直接给到工人,并能直接监控工人完成状态,这样效率会更高。

2、工人之间直接通讯,不依赖zeroMQ转发。

3、并行管理扁平化,多进程下再分多线程意义不大,增加管理成本,实际上一台机器8个进程,每个进程再开8个线程,总体跟8-10个进程或者线程的效果差不多(数量视机器性能不同)。

4、做成一个流计算系统,而不是平台。

这里我们借助fourinone提供的api和框架去实现,第一次使用可以参考分布式计算上手demo指南,开发包下载地址 http://code.google.com/p/fourinone/

大致思路:用工头去做任务生产和分配,用工人去做任务执行,为了达到流的效果,需要在工人里面调用工头的方式,将多个工人节点串起来。

下面程序演示了连续多个消息先发到一个工人节点A处理,然后再发到两个工人节点B并行处理的流计算过程,并且获取到最后处理结果打印输出(如果不需要获取结果可以直接返回)。

  • StreamCtorA:工头A实现,它获取到线上工人A,然后将消息发给它处理,并轮循等待结果。工头A的main函数模拟了多个消息的连续调用。
  • StreamWorkerA:工人A实现,它接收到工头A的消息进行处理,然后创建一个工头B,通过工头B将结果同时发给两个工人B处理,然后将结果返回工头A。
  • StreamCtorB:工头B实现,它获取到线上两个工人B,调用doTaskBatch等待两个工人处理完成,然后返回结果给工人A。
  • StreamWorkerB:工人B实现,它接收到任务消息后模拟处理后返回结果。

运行步骤(在本地模拟): 

1、启动ParkServerDemo(它的IP端口已经在配置文件指定) 

  1. java -cp fourinone.jar; ParkServerDemo 

2、启动工人A

  1. java  -cp fourinone.jar; StreamWorkerA localhost 2008 

3、启动两个工人B

  1. java  -cp fourinone.jar; StreamWorkerB localhost 2009 
  2. java  -cp fourinone.jar; StreamWorkerB localhost 2010 

4、启动工头A

  1. java  -cp fourinone.jar; StreamCtorA 

多机部署说明:StreamCtorA可以单独部署一台机器,StreamWorkerA和StreamCtorB部署一台机器,两个StreamWorkerB可以部署两台机器。

总结:计算平台和计算系统的区别

如果我们只有几台机器,但是每天有人开发不同的流处理应用要在这几台机器上运行,我们需要一个计算平台来管理好job,让开发者按照规范配置好流程和运行时节点申请,打包成job上传,然后平台根据每个job配置动态分配资源依次执行每个job内容。

如果我们的几台机器只为一个流处理业务服务,比如实时营销,我们需要一个流计算系统,按照业务流程部署好计算节点即可,不需要运行多个job和动态分配资源,按照计算平台的方式做只会增加复杂性,开发者也不清楚每台机器上到底运行了什么逻辑。

如果你想实现一个计算平台,可以参考动态部署和进程管理功能(开发包内有指南)

//完整源码

// ParkServerDemo

  1. import com.fourinone.BeanContext; 
  2. public class ParkServerDemo 
  3.     public static void main(String[] args) 
  4.     { 
  5.         BeanContext.startPark(); 
  6.     } 

//StreamCtorA

  1. import com.fourinone.Contractor; 
  2. import com.fourinone.WareHouse; 
  3. import com.fourinone.WorkerLocal; 
  4. import java.util.ArrayList; 
  5. public class StreamCtorA extends Contractor 
  6.  public WareHouse giveTask(WareHouse inhouse) 
  7.  { 
  8.   WorkerLocal[] wks = getWaitingWorkers("StreamWorkerA"); 
  9.   System.out.println("wks.length:"+wks.length); 
  10.   WareHouse result = wks[0].doTask(inhouse); 
  11.   while(true){ 
  12.    if(result.getStatus()!=WareHouse.NOTREADY) 
  13.    { 
  14.     break; 
  15.    } 
  16.   } 
  17.   return result; 
  18.  } 
  19.  public static void main(String[] args) 
  20.  { 
  21.   StreamCtorA sc = new StreamCtorA(); 
  22.   for(int i=0;i<10;i++){ 
  23.     WareHouse msg = new WareHouse(); 
  24.     msg.put("msg","hello"+i); 
  25.     WareHouse wh = sc.giveTask(msg); 
  26.     System.out.println(wh); 
  27.   } 
  28.   sc.exit(); 
  29.  } 

//StreamWorkerA

  1. import com.fourinone.MigrantWorker; 
  2. import com.fourinone.WareHouse; 
  3. public class StreamWorkerA extends MigrantWorker 
  4.  public WareHouse doTask(WareHouse inhouse) 
  5.  { 
  6.   System.out.println(inhouse); 

  //do something

  1. StreamCtorB sc = new StreamCtorB(); 
  2. WareHouse msg = new WareHouse(); 
  3. msg.put("msg",inhouse.getString("msg")+",from StreamWorkerA"); 
  4. WareHouse wh = sc.giveTask(msg); 
  5. sc.exit(); 
  6. return wh; 
  7.  } 
  8. public static void main(String[] args) 
  9.  { 
  10. StreamWorkerA wd = new StreamWorkerA(); 
  11. wd.waitWorking(args[0],Integer.parseInt(args[1]),"StreamWorkerA"); 
  12.  } 

//StreamCtorB 

  1. import com.fourinone.Contractor; 
  2. import com.fourinone.WareHouse; 
  3. import com.fourinone.WorkerLocal; 
  4. import java.util.ArrayList; 
  5. public class StreamCtorB extends Contractor 
  6.  public WareHouse giveTask(WareHouse inhouse) 
  7.  { 
  8.   WorkerLocal[] wks = getWaitingWorkers("StreamWorkerB"); 
  9.   System.out.println("wks.length:"+wks.length); 
  10.   WareHouse[] hmarr = doTaskBatch(wks, inhouse); 
  11.   WareHouse result = new WareHouse(); 
  12.   result.put("B1",hmarr[0]); 
  13.   result.put("B2",hmarr[1]); 
  14.   return result; 
  15.  } 

//StreamWorkerB 

  1. view sourceprint? 
  2. import com.fourinone.MigrantWorker; 
  3. import com.fourinone.WareHouse; 
  4. public class StreamWorkerB extends MigrantWorker 
  5.  public WareHouse doTask(WareHouse inhouse) 
  6.  { 
  7.   System.out.println(inhouse); 

  //do something

  1. inhouse.put("msg",inhouse.getString("msg")+",from StreamWorkerB"); 
  2. return inhouse; 
  3.  } 
  4.  public static void main(String[] args) 
  5.  { 
  6.   StreamWorkerB wd = new StreamWorkerB(); 
  7.   wd.waitWorking(args[0],Integer.parseInt(args[1]),"StreamWorkerB"); 
  8.  } 

 

责任编辑:黄丹 来源: oschina.net
相关推荐

2020-09-16 11:20:03

流计算基准测试

2018-09-18 09:38:11

RPC远程调用网络通信

2020-11-11 09:49:12

计算架构

2020-09-02 07:22:17

JavaScript插件框架

2023-09-08 08:22:30

2023-09-08 08:10:48

2024-08-27 12:49:20

2024-11-20 13:18:21

2024-04-24 10:38:22

2022-07-18 08:02:16

秒杀系统后端

2024-06-21 08:15:25

2019-08-01 08:36:51

缓存系统并发

2024-06-17 11:59:39

2020-03-26 09:36:06

AB Test平台的流量

2015-07-28 14:35:40

2016-09-30 10:13:07

分布式爬虫系统

2019-07-31 07:36:12

架构运维技术

2022-09-13 08:01:58

短链服务哈希算法字符串

2024-02-28 08:04:15

2013-07-01 11:01:22

API设计API
点赞
收藏

51CTO技术栈公众号