getting start with storm 翻译 第五章

转载请注明出处:http://blog.youkuaiyun.com/lonelytrooper/article/details/9970241

第五章 Bolts

正如你看到的,bolts是一个storm集群中的关键组件。在本章中,你将看到一个bolt的生命周期,bolt的设计策略,以及怎样实现它们的一些示例。

Bolt生命周期

Bolt是一种将元组作为输入并且制造元组作为输出的组件。当你实现一个bolt的时候,你通常实现IRichBolt接口。Bolts在客户端机器被创建,序列化至topology中,并提交至集群中的master机器。集群运行workers来反序列bolt,调用它上的prepare方法,然后开始处理元组。

要自定义bolt,你需要在它的构造方法中设置参数并且将它们保存为实例变量,这样它们可以在bolt被提交至集群时序列化。

Bolt结构

Bolts包含如下方法:

declareOutputFields(OutputFieldsDeclarerdeclarer)

定义该bolt的输出模式。

prepare(java.util.Map stormConf,TopologyContext context, OutputCollector col

lector)

在bolt开始处理元组前被调用。

execute(Tuple input)

处理一个单独的输入元组。

cleanup()

当bolt将要关闭时被调用。

来看一个将句子分隔成单词的bolt示例:

class SplitSentenceimplementsIRichBolt{

private OutputCollector collector;

public voidprepare(Map conf,TopologyContext context,OutputCollectorcollector) {

this.collector=collector;

}

public voidexecute(Tuple tuple) {

String sentence =tuple.getString(0);

for(Stringword:sentence.split("")) {

collector.emit(newValues(word));

}

}

public voidcleanup(){

}

public voiddeclareOutputFields(OutputFieldsDeclarerdeclarer) {

declarer.declare(newFields("word"));

}

}

正如你看到的,该bolt是非常直观的。值得一提的是这个例子中没有消息担保。这意味着如果该bolt由于某种原因丢弃了一条信息---因为该消息失败了或者以编程的方式故意丢弃了---产生该消息的spout是永远不会被提醒的,并且其间的任何的bolts和spouts也不会。

在许多场景下,你是希望在整个topology中消息是被确保处理的。

可靠Bolts versus不可靠Bolts

如前述,storm确保由spout发送的每条消息都会被所有bolts完全处理。这是一种设计考虑,意味着你需要决定是否你的bolts是确保消息被处理的。

Topology是一颗消息(元组)经过一条或多条分支形成的的结点树。每个结点将ack(元组)或fail(元组),这样storm知道一个消息是什么时候失败的并且通知产生该消息的spout或spouts。因为storm topology运行在一个高度并行的环境,因此记录原始的spout实例的最好方式是在消息元组中包含一个原始spout的引用。这个技术叫做锚定。修改你刚刚看到的SplitSentence bolt,这样它可以确保消息处理。

class SplitSentenceimplementsIRichBolt{

private OutputCollector collector;

public voidprepare(Map conf,TopologyContext context,OutputCollectorcollector) {

this.collector=collector;

}

public voidexecute(Tuple tuple) {

String sentence =tuple.getString(0);

for(Stringword:sentence.split("")) {

collector.emit(tuple,newValues(word));

}

collector.ack(tuple);

}

public voidcleanup(){

}

public voiddeclareOutputFields(OutputFieldsDeclarerdeclarer) {

declarer.declare(newFields("word"));

}

}

锚定发生的具体行是在collector.emit() 语句。就像前边提到的,传递元组使得storm可以记录原始spout的踪迹。collector.ack(tuple) 和collector.fail(tuple)告诉spout每条消息发生了什么。当树中每条消息都被处理后,storm认为由spout发出的元组被完全处理了。当它的消息树没有在配置的超时时间内被全部处理时,一个元组的处理被认为是失败的。缺省时间为30秒。

你可以通过修改topology的Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS配置来修改超时。

 

当然,spout需要考虑消息失败并且重试或者相应的丢弃消息的场景。

每个你处理的元组都必须被应答或者宣告失败。Storm使用内存来保存每个元组的踪迹,所以如果你没有确认/宣告失败每个元组,该任务会逐渐的耗尽内存。

多流

Bolt可以使用emit(streamId, tuple)发射元组到多条流,每条流由字符串streamId来识别。然后,在TopologyBuilder中,你可以决定订阅哪条流。

多锚定

使用bolt来连接或者聚合流时,你需要在内存中缓存元组。为了这种情形下的消息担保,你不得不锚定流到不止一个元组。这通过调用包含元组列表的emit方法实现。

...

List<Tuple>anchors=newArrayList<Tuple>();

anchors.add(tuple1);

anchors.add(tuple2);

_collector.emit(anchors,values);

...

那样,任何时候一个bolt被确认或者失败,它会通知树,并且由于流被锚定给不止一个元组,被包含的所有spouts都会被通知。

通过IBasicBolt来自动Ack

正如你可能注意到的,在许多用例中,你需要消息担保。为简化它,storm为bolt提供了另一个叫做IBasicBolt的接口,它封装了一种在execute方法之后调用ack方法的模式。BaseBasicBolt,一个该接口的实现,被用来做自动确认。

class SplitSentenceextendsBaseBasicBolt{

public voidexecute(Tuple tuple,BasicOutputCollector collector) {

String sentence =tuple.getString(0);

for(Stringword:sentence.split("")) {

collector.emit(newValues(word));

}

}

public voiddeclareOutputFields(OutputFieldsDeclarerdeclarer) {

declarer.declare(newFields("word"));

}

}

被发射到BasicOutputCollector的元组被自动锚定到输入元组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值