Storm实际使用中可能需要分流与合并,分流分为两种情况,第一种是相同的tuple发往下一级不同的bolt,第二种是分别发送不同的tuple到不同的下级bolt上,下面以WordCount为例:
1.发送相同的tuple
即2个或多个bolt接收同一个spout或bolt的数据,如下图:
(注:实际应用场景不会这么用,因为同一个tuple发送给不同的bolt,会导致同一个单词被count两次,这里仅用作举例)
tuple1会发送给bolt1和bolt2。
TopologyMain.java
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("word-reader", new WordReader());
// 分流
builder.setBolt("word-normalizer1", new WordNormalizer()).shuffleGrouping("word-reader");
builder.setBolt("word-normalizer2", new WordNormalizer()).shuffleGrouping("word-reader");
// 合并
builder.setBolt("word-counter", new WordCounter(), 2).fieldsGrouping("word-normalizer1", new Fields("word"))
.fieldsGrouping("word-normalizer2", new Fields("word"));
2.发送不同的tuple
当发送不同的tuple到不同的下级bolt时,就要引入stream的概念,bolt或spout可以使用emit(streamId, tuple)把元祖分发到多个流,其中streamId是一个用来标识流的字符串,然后在TopologyBuilder决定由哪个流来订阅它,如下图所示:
tuple1和tuple2分别发往bolt1和bolt2。
部分代码:
WordReader.java
// 定义输出流格式
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declareStream("streamid1", new Fields("line1"));
declarer.declareStream("streamid2", new Fields("line2"));
}
public void nextTuple() {
……
int i = 0;
while ((str = reader.readLine()) != null) {
i++;
if (i % 2 == 1) {
// 奇数行发给streamid1
this.collector.emit("streamid1", new Values(str), i + "." + str);
} else {
// 偶数行发给streamid2
this.collector.emit("streamid2", new Values(str), i + "." + str);
}
}
}
TopologyMain.java
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("word-reader", new WordReader());
// 分流
builder.setBolt("word-normalizer1", new WordNormalizer()).shuffleGrouping("word-reader", "streamid1");
builder.setBolt("word-normalizer2", new WordNormalizer()).shuffleGrouping("word-reader", "streamid2");
// 合并
builder.setBolt("word-counter", new WordCounter(), 2).fieldsGrouping("word-normalizer1", new Fields("word"))
.fieldsGrouping("word-normalizer2", new Fields("word"));