在详细讲解Storm不同组件之间的tuples传递之前,我们先看下我们的结构图
从上面的结构图,我们可以看到。一个topology是spouts和bolts组成的图,而Spout与Blot以及Blot与Blot之间的传递是通过Stream Grouping来完成的。
定义一个topology的其中一步是定义每个bolt接收什么样的流作为输入。stream grouping就是用来定义一个stream应该如果分配数据给bolts上面的多个tasks。
当我们要定义Topology的时候,需要设置Stream Grouping来指定处理流程;
...
builder.setBlot("word-normalizer",new WordNormalizer()).
<span style="white-space:pre"> </span>shuffleGrouping("word-reader")
...
1、Shuffle Grouping: 随机分组, 也是我们最常用的分组;随机派发stream里面的tuple,保证每个bolt接收到的tuple数目大致相同。我们图片中使用的就是ShuffleGrouping。配置方法很简单,只需指定你上一级流入组件的名称即可;
2、Fields Grouping:按字段分组, 指定某个字段作为分组条件,那么字段值相同的元组(tuple)会被分到同一个Blots里的task进行处理,反之则分配到不同的Blot的task进行处理
在我之前写的wordcount例子中,当你指定流组字段是word,那么word-normalizer将会发送一个指定的word到相同的word-counter Blot实例;
...
builder.setBlot("word-normalizer",new WordNormalizer(),2).
<span style="white-space:pre"> </span>fieldsGrouping("word-reader",new Fields("word"))
...
注:在Fields Grouping中的所有字段,必须在declareOutputFields方法中存在。否则会报错;
3、All Grouping:顾名思义,就是对于每一个tuple,所有的bolts都会收到。类似于我们的广播;
4、Direct Grouping:直接分组;意思是说,消息生产者直接讲元组指定分配给消息消费者中的某个task进行处理;只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发送,而不是emit。消息处理者可以通过TopologyContext来获取处理它的消息的task的id (OutputCollector.emit方法也会返回task的id);看下下面的例子
public void execute(Tuple input)
...
for(String word:words){
...
collector.emitDirect(getWordCountIndex(word),new Values(word))
}
collector.ack(input);
}
这里使用的是emitDirect方法,而不是emit方法
而且我们在Blot的prepare方法中需直声明指定有哪个组件task来接收;这里指定了word-counter
public void prepare(Map stormConf,TopologyContext context,OutputCollector collector){
this.collector=collector;
this.numCounterTasks=context.getComponentTasks("word-counter");
}
在Topology定义的时候是这样定义的;
builder.setBolt("word-counter",new WordCounter(),2).
directGrouping("word-normalizer");
5、Global Grouping:全局分组;全局分组发送的所有实例的源产生一个单一的目标元组实例(具体的说,是发送到ID最低的task进行处理)。
6、None Grouping:不分组;这种分组方法和第一种shuffle Grouping效果是一样的;换句话说,这种方法不关心如何分组;
7、Custom Grouping:自定义分组
除了以上几种分组方式之外,我们还可以自己自定义分组,自己DIY去控制哪些Blot来接收Tuple;
实现自定义分组需要继承backtype.storm.grouping.CustomStreamGrouping 接口;
public class ModuleGrouping implements CustomStreamGrouping, Serializable{
int numTasks = 0;
@Override
public List<Integer> chooseTasks(List<Object> values) {
List<Integer> boltIds = new ArrayList();
<span style="white-space:pre"> </span>if(values.size()>0){
String str = values.get(0).toString();
if(str.isEmpty())
boltIds.add(0);
}else{
boltIds.add(str.charAt(0) % numTasks);
}
return boltIds;
}
@Override
public void prepare(TopologyContext context, Fields outFields,
List<Integer> targetTasks) {
numTasks = targetTasks.size();
}
}
这里写了一个简单的自定义分组(CustomGrouping),通过对第一个character进行取模来选择由哪个Blot接收数据进行处理;
使用自定义分组的实例如下:
builder.setBolt("word-normalizer", new WordNormalizer())
.customGrouping("word-reader", new ModuleGrouping());
参考文献:https://github.com/nathanmarz/storm/wiki/Tutorial
http://blog.linezing.com/category/storm-quick-start?spm=0.0.0.0.vUIENl
转载请注明来源地址:http://blog.csdn.net/weijonathan/article/details/18408535