基本概念
- Nodes:服务器,配置了storm集群,有安装nimbus的node,以及安装supervisor的node
- Workers(JVM虚拟机):一个服务器上相互独立运行的JVM进程,一个服务器node可以配置一个或者多个worker,一个topology会分配到一个或者多个worker运行,如下图:
注意:worker只存在于supervisor服务器 - Task:任务,就是spout或bolt的实例,他们的nextTuple方法会被executor线程调用执行
- Executor:一个worker(jvm进程)中的java线程,可以同时执行多个task,默认情况下,并行度设置几,即有几个task,会默认给每个task分配一个executor线程去执行它
单词计数流程如下:
默认配置
默认情况下,storm的并发度为1,以下是单词计数案例的topology执行过程
可以看到在一台服务器上有一个worker(JVM进程),里面跑了4个java线程,每个线程执行一个task实例,一共4个task实例,包括3个bolt和一个spout,即每个任务在这个jvm不同线程中执行,并发为线程级
配置executor和task
增加一个spout以后,图例如下,将会造成2倍的数据流入,产出
设置为1个服务器2个worker(JVM进程)
单词分割bolt配置如下(设置单词分割bolt有两个executor线程来执行4个单词分割实例)
builder.setBolt(SPLIT_BOLT_ID,splitBolt,2).setNumTasks(4).shufferGrouping(SENTENCE_SPOUT_ID);
单词计数bolt配置如下(设置单词计数bolt有4个executor线程来执行4个单词分割实例,分组方式为按字段分组,相同单词进入同一个bolt实例)
builder.setBolt(COUNT_BOLT_ID,countBolt,4).fieldGrouping(SPLIT_BOLT_ID,new Fields("word"));
综合上述图例如下:
数据流分组方式
并发版本单词计数拓扑中,单词分割bolt指定了4个task,数据流分组将决定每个tuple分发到哪个task
storm定义了七种内置数据流分组方式
-
Shuffle grouping(随机分组):这种方式随机分发tuple到不同bolt实例,每个bolt实例收到相同数量tuple,类似于kafka不同分区消息均衡算法
-
Fields grouping(按字段分组):根据指定字段的值进行分组,比如单词切割以后发到计数bolt,not如果分发到计数bolt1,则下一个not肯定会分发到计数bolt1而不会到计数bolt2,即not单词只可能存在于bolt1
注意:如果是fieldgrouping一共有3种句子,大批量发送,然后有3个bolt实例分割,不一定绝对是每个bolt实例每一种句子,还是可能出现一个休息的bolt,另外两个里面一个有2种句子,一个一种
-
Fields grouping(按字段分组):根据指定字段的值进行分组,比如单词切割以后发到计数bolt,not如果分发到计数bolt1,则下一个not肯定会分发到计数bolt1而不会到计数bolt2,即not单词只可能存在于bolt1
-
Globle grouping(全局分组):这种分组方式会将所有的tuple都流入到同一个bolt实例,至于这个bolt实例到底选取哪个,storm将根据最小的task ID来选取接收数据的task(bolt示例)
注意:由上面的理论可以知道,当使用全局分组的时候,设置bolt实例的并发度是没有意义的,因为所有的tuple都会流入同一个bolt实例,当然这也将导致问题:所有的tuple流入一个JVM实例,导致storm集群中某个jvm或者服务器出现性能瓶颈、故障、甚至挂掉
-
Local or shuffle grouping(本地或随机分组):类似于随机分组。如果当前worker(JVM进程)中有下一个流入的bolt,则当前bolt会将tuple分发给同一个服务器上的同一个worker(JVM进程)中的下一个bolt实例,如果没有,则和随机分组结果相同。这种分组方式key减少网络传输,进而提高拓扑性能
-
All grouping(全复制分组)
-
None grouping(不分组)
-
Direct grouping(指向型分组)
分组实践
实践:查看如果采用随机分组会对单词计数结果造成差错(对比随机分组和按字段分组),仍然针对单词计数案例:spout和其他bolt全部都并行度1,wordcountbolt单词计数bolt并行度3,因为只有并行度>1,分组实践才有意义
测试句子:
private String[] sentences={
"my dog has fleas",
"i like cold beverages",
"do not always play games",
"i do not like fleas",
"do you know his name"
};
计数bolt代码:
/**
* tuple:word,count
*/
@Slf4j
public class WordCountBolt extends BaseRichBolt {
private OutputCollector collector;
private HashMap<String,Long