转载自:https://blog.youkuaiyun.com/lulongzhou_llz/article/details/46399457
Bolt 接口
Storm中定义的Bolt接口主要有IBolt 、IRichBolt 、IBasicBolt和IBatchBolt,
IBolt
IBolt定义了Bolt的功能集合。
Bolt是Storm中的基础运行单位,当其启动并有消息输人时,将调用execute方法来进行处理。与ISpout类似, IBolt对象在提交时也会被序列化为字节数组,具体的执行节点通过反序列化的方法得到该对象,并调用prepare回调方法。用户应将复杂对象的初始化放在prepare回调方法中实现,以保证每个具体对象都可以正确初始化。
对象被销毁时,将调用cleanup回调方法,但是Storm并不保证该方法一定被执行。
通常,在execute方法的实现中会对输人消息进行处理,这有可能产生新消息需要发送到下游节点,最后还要对输入的消息进行ack操作。如果消息处理失败,则需对输入的消息进行fail操作 这是保证Ack消息系统可以正常工作的基础。
IRichBolt
IRichBolt需要同时实现IComponent以及IBolt接口。在实际使用中,IRichBolt是实现Topology组件的主要接口。
IBasicBolt
IBasicBolt接口的定义与IBolt基本一致,具体的实现要求也与IBolt相同,它与IBolt的区别在于以下两点:
- 它的输出收集器使用的是
BasicOutputCollector,并且该参数被放在了execute方法中而不是prepare中。- 它实现了
IComponent接口,这表明它可以用来定义Topology组件。
IBasicBolt的主要作用是为用户提供一种更简单的Bolt编写方式。基于IBasicBolt编写的好处是Storm框架本身帮你处理了所发出消息的ack、fail和anchor操作,这是由执行器BasicBoltExecutor实现的。
IBatchBolt
区别于IBasicBolt接口,IBatchBolt主要用于Storm中的批处理。 目前,Storm主要用该接口来实现可靠的消息传输,在这种情况下,批处理会比单一消息处理更为高效。Storm的事务Topology以及Trident主要是基于IBatchBolt的。相比前面的IBolt、IBasicBolt和IRichBolt, IBatchBolt中多了一个finishBatch方法, 它在一个批处理结束时被调用。此外, IBatchBolt还去除了cleanup方法。
Bolt生命周期
Bolt是这样一种组件,它把元组作为输入,然后产生新的元组作为输出。实现一个bolt时,通常需要实现IRichBolt接口。Bolts对象由客户端机器创建,序列化为拓扑,并提交给集群中的主机。然后集群启动工人进程反序列化bolt,调用prepare,最后开始处理元组。
要创建一个bolt对象,它通过构造器参数初始化成员属性,bolt被提交到集群时,这些属性值会随着一起序列化。
拓扑是一个树型结构,消息(元组)穿过其中一条或多条分支。树上的每个节点都会调用ack(tuple)或fail(tuple),Storm因此知道一条消息是否失败了,并通知那个/那些制造了这些消息的spout(s)。既然一个Storm拓扑运行在高度并行化的环境里,跟踪始发spout实例的最好方法就是在消息元组内包含一个始发spout引用。这一技巧称做锚定(Anchoring)。
class SplitSentence implenents IRichBolt {
private OutputCollector collector;
public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
}
public void execute(Tuple tuple) {
String sentence = tuple.getString(0);
for(String word : sentence.split(" ")) {
collector.emit(tuple, new Values(word));
}
collector.ack(tuple);
}
public void cleanup(){}
public void declareOutputFields(OutputFieldsDeclarer declarer){
declar.declare(new Fields("word"));
}
}
锚定发生在调用collector.emit()时。正如前面提到的,Storm可以沿着元组追踪到始发spout。collector.ack(tuple)和collector.fail(tuple)会告知spout每条消息都发生了什么。当树上的每条消息都已被处理了,Storm就认为来自spout的元组被全面的处理了。如果一个元组没有在设置的超时时间内完成对消息树的处理,就认为这个元组处理失败。默认超时时间为30秒。可以通过修改Config.TOPOLOGY_MESSAGE_TIMEOUT修改拓扑的超时时间。
spout需要考虑消息的失败情况,并相应的重试或丢弃消息。处理的每条消息要么是确认的(collector.ack())要么是失败的(collector.fail())。Storm使用内存跟踪每个元组,所以如果不调用这两个方法,该任务最终将耗尽内存。
多锚定
为了用bolt连接或聚合数据流,需要借助内存缓冲元组。为了在这一场景下确保消息完成,需要把流锚定到多个元组上。可以向emit方法传入一个元组列表来达成目的。
...
List anchors = new ArrayList();
anchors.add(tuple1);
anchors.add(tuple2);
collector.emit(anchors, values);
...
通过这种方式,bolt在任意时刻调用ack或fail方法,都会通知消息树,而且由于流锚定了多个元组,所有相关的spout都会收到通知。
使用IBasicBolt自动确认
在许多情况下都需要消息确认。简单起见,Storm提供了另一个用来实现bolt的接口IBasicBolt。对于该接口的实现类的对象,会在执行execute方法之后自动调用ack方法。
class SplitSentence extends BaseBasicBolt {
public void execute(Tuple tuple, BasicOutputCollector collector) {
String sentence = tuple.getString(0);
for(String word : sentence.split(" ")) {
collector.emit(new Values(word));
}
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
}
分发消息的BasicOutputCollector自动锚定到作为参数传入的元组。
本文介绍了Apache Storm中Bolt接口的不同类型及其功能,包括IBolt、IRichBolt、IBasicBolt和IBatchBolt等。文章还详细解释了Bolt组件的工作原理和生命周期,以及如何使用Bolt进行消息处理。
2952

被折叠的 条评论
为什么被折叠?



