常见模式
这篇文章列出了storm拓扑中各种各样的常见模式。
1. 流连接(
Stream join)
2. 批处理(Batching)
3. BasicBolt
4. In-memory缓存 + 字段分组(Fields grouping)组合
5. 流动的Top N
6. 通过TimeCacheMap高效缓存最近更新的对象
7. 用于分布式RPC的CoordinatedBolt和KeyedFairBolt
流连接
流连接基于一些相同字段,把两个或两个以上数据流连接起来。但是,流连接与常规的数据库表连接(table join)不同,数据库表连接的输入是有限的,语义是清晰的,而流连接的输入是无限的,语义是不清晰的。
根据不同的应用,你所需要的流连接类型也不同。一些应用在一段时间内连接两个流的所有元组,而另一些应用期望每个流连接基于一个不同的连接字段。其它应用的流连接可能完全不同。所有流连接类型中的常见模式是用同样的方式分割各种各样的输入流。在storm中,这是很容易做到的,只需对多个输入流基于相同字段使用字段分组,然后将多个输入流连接到一个bolt。例如:
- builder.setBolt("join", new MyJoiner(), parallelism)
- .fieldsGrouping("1", new Fields("joinfield1", "joinfield2"))
- .fieldsGrouping("2", new Fields("joinfield1", "joinfield2"))
- .fieldsGrouping("3", new Fields("joinfield1", "joinfield2"));
当然,不同的数据流也不必有相同的字段名称。
批处理(Batching)
经常因为效率或其它方面原因,你想用批处理方式处理一组元组,而不是分别地处理它们。例如,你想批量更新数据库数据或对一些排序进行流聚合处理。
如果你想让你的数据处理可靠,正确的方式是当bolt等待批处理时,用实例变量引用这些元组,一旦你完成批处理,你再ack这些元组。
如果bolt发射元组,你想使用 multi-anchoring 来确保可靠。这完全取决于具体的应用。更多详细信息参见
可靠消息处理。
BasicBolt
大多数bolts都
遵从相似的模式:首先,读一个输入元组;然后,在输入元组的基础上再发射0-N个元组;最后,在执行方法的末尾直接ack那个输入元组。遵从这个模式的bolts是类似函数和过滤器的事物。Storm为这种常见模式提供了
IBasicBolt接口。更多信息请参见
可靠消息处理。
In-memory缓存 + 字段分组(Fields grouping)组合
Storm的bolts在内存中缓存对象是常见的。当你把内存缓存和字段分组结合起来使用时,效果更好。例如,假如你有一个bolt,这个bolt是用来把短的URL(如:bit.ly, t.co等)转换成长的URL,你可以通过LRU缓存避免重复运算,大幅提升性能,LRU缓存中存储短URL与长URL之间的映射关系。假如“urls”组件发射短URL,“expand”把短URL扩展成长URL,并缓存它。考虑以下两个代码片段之间的差别:
- builder.setBolt("expand", new ExpandUrl(), parallelism)
- .shuffleGrouping(1);
- builder.setBolt("expand", new ExpandUrl(), parallelism)
- .fieldsGrouping("urls", new Fields("url"));
第二种方式的缓存效果更好,因为同一URL总是流向同一任务。这样可以避免在不同机器的任务中重复缓存相同URL,同时使得短URL在缓存中的命中率更高。
流动Top N
Storm中一个常见的持续计算工作是“streaming top N”。假如你有一个bolt以["value", "count"]的形式发射元组,并且你想有一个bolt基于计算发射top N元组。最简单的方式是用一个bolt对流进行全局分组并在内存中维护top N这个列表。
由于整个流都会发送到一个任务,所以,这个方式对于大数据量显然没有伸缩性。一种更好的方式是并行计算流的各部分top N,然后把那些部分top N合并在一起,得到总的top N,这个模式看上去是这样:
- builder.setBolt("rank", new RankObjects(), parallellism)
- .fieldsGrouping("objects", new Fields("value"));
- builder.setBolt("merge", new MergeObjects())
- .globalGrouping("rank");
这个模式的工作结果之所以是正确的,这是因为第一个bolt的字段分组提供了正确的并行计算语义。
通过TimeCacheMap高效缓存最近更新的对象
有时你想在内存中缓存一些最近活动的对象,并且对象在一段时间内不活动将自动过期。
TimeCacheMap是一个高效的数据结构,并且它提供了钩子,所以你可以插入回调函数执行对象过期的处理逻辑。
用于分布式RPC的CoordinatedBolt和KeyedFairBolt
当在storm之上构建分布式RPC应用时,经常需要这两个常见模式。它们被封装在storm标准库的
CoordinatedBolt和
KeyedFairBolt中。
CoordinatedBolt包装一个包含业务逻辑的bolt,并且确定何时你的bolt已经收到了所有元组。它大量使用direct stream来实现这个功能。
KeyedFairBolt也包装一个包含业务逻辑的bolt,并且确保你的拓扑同时处理多个DRPC调用,代替串行地一次处理一个调用。
更多详情请参见
分布式RPC。
转载于:https://blog.51cto.com/chenlx/739445