Storm架构分析

  当一个topology在storm cluster中运行时,它的并发主要跟3个逻辑对象相关:worker,executor 和task

1. Worker 是运行在工作节点上面,被Supervisor守护进程创建的用来干活的JVM进程。每个Worker对应于一个给定topology的全部执行任务的一个子集。反过来说,一个Worker里面不会运行属于不同的topology的执行任务。

2. Executor可以理解成一个Worker进程中的工作线程。一个Executor中只能运行隶属于同一个component(spout/bolt)的task。一个Worker进程中可以有一个或多个Executor线程。在默认情况下,一个Executor运行一个task。

3. Task则是spout和bolt中具体要干的活了。一个Executor可以负责1个或多个task。每个component(spout/bolt)的并发度就是这个component对应的task数量。同时,task也是各个节点之间进行grouping(partition)的单位。


conf.setNumWorkers(workers);  //设置worker数量
uilder.setBolt("2", new WordSpliter(),4)    //设置 Executor并发数量
builder.setBolt("2", new WordSpliter(),4).setNumTasks(1); //设置每个线程处理的Task数量


任务分配时 有两种情况:


 (a)task数目比worker多,例如task是[1 2 3 4],可用的slot只有[host1:port1 host2:port1],那么最终是这样分配
{1: [host1:port1] 2 : [host2:port1]
         3 : [host1:port1] 4 : [host2:port1]}
可以看到任务平均地分配在两个worker上。

(b)如果task数目比worker少,例如task是[1 2],而worker有[host1:port1 host1:port2 host2:port1 host2:port2],那么首先会将woker排序, 将不同host间隔排列 ,保证task不会全部分配到同一个机器上,也就是将worker排列成
[host1:port1 host2:port1 host1:port2 host2:port2]
  然后分配任务为
{1: host1:port1 , 2 : host2:port1}



通过 Config.setNumWorkers(int))来指定一个storm集群中执行topolgy的进程数量, 所有的线程将在这些指定的worker进程中运行. 比如说一个topology中要启动300个线程来运行spout/bolt, 而指定的worker进程数量是60个, 那么storm将会给每个worker分配5个线程来跑spout/bolt, 如果要对一个topology进行调优, 可以调整worker数量和spout/bolt的parallelism数量(调整参数之后要记得重新部署topology. 后续会为该操作提供一个swapping的功能来减小重新部署的时间). 

对于worker和task之间的比例, nathan也给出了参考, 即1个worker包含10~15个左右, 当然这个参考, 实际情况还是要根据配置和测试情况 






 最近研究Storm的Stream Grouping的时候,对Field Grouping和Shuffle Grouping理解不是很透彻。去看WordCountTopology也不怎么理解,后来脑洞一开,加了一行代码再次运行,彻底顿悟。只能说自己对Storm的基本概念还是没吃透啊。(WordCountTopology这个例子请自行参考Storm-Starter)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void execute(Tuple tuple, BasicOutputCollector collector) {  
  2.     String word = tuple.getString(0);  
  3.   
  4.     // 添加这行代码的作用是看看值相等的word是不是同一个实例执行的,实时证明确实如此  
  5.     System.out.println(this + "====" + word);  
  6.       
  7.     Integer count = counts.get(word);  
  8.     if (count == null)  
  9.         count = 0;  
  10.     count++;  
  11.     counts.put(word, count);  
  12.     collector.emit(new Values(word, count));  
  13. }  
经过反复测试,下面是我个人的一些总结,如果有缺少或者错误我会及时改正。

官方文档里有这么一句话:“if the stream is grouped by the “user-id” field, tuples with the same “user-id” will always go to the same task”

一个task就是一个处理逻辑的实例,所以fields能根据tuple stream的id,也就是下面定义的xxx

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void declareOutputFields(OutputFieldsDeclarer declarer) {  
  2.         declarer.declare(new Fields("xxx"));  
  3. }  
xxx所代表的具体内容会由某一个task来处理,并且同一个xxx对应的内容,处理这个内容的task实例是同一个。

比如说:

bolt第一次emit三个流,即xxx有luonq pangyang qinnl三个值,假设分别建立三个task实例来处理:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. luonq -> instance1  
  2. pangyang -> instance2  
  3. qinnl -> instance3  


然后第二次emit四个流,即xxx有luonq qinnanluo py pangyang四个值,假设还是由刚才的三个task实例来处理:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. luonq -> instance1  
  2. qinnanluo -> instance2  
  3. py -> instance3  
  4. pangyang -> instance2  

然后第三次emit两个流,即xxx有py qinnl两个值,假设还是由刚才的三个task实例来处理:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. py -> instance3  
  2. qinnl -> instance3  

最后我们看看三个task实例都处理了哪些值,分别处理了多少次:

instance1: luonq(处理2次)
instance2: pangyang(处理2次) qinnanluo(处理1次)
instance3: qinnl(处理2次) py(处理2次)

结论:
1. emit发出的值第一次由哪个task实例处理是随机的,此后再次出现这个值,就固定由最初处理他的那个task实例再次处理,直到topology结束

2. 一个task实例可以处理多个emit发出的值

3. 和shuffle Grouping的区别就在于,当emit发出同样的值时,处理他的task是随机的


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值