Storm可靠的Bolt与不可靠的Bolt

Storm可以保证每个Spout发射的消息会被所有的Bolt完全处理。这是设计时要考虑的因素,这意味着程序员将决定Bolt是否需要保证消息处理。

可靠Bolt的execute()方法如下:

@Override
	public void execute(Tuple input) {
		String sentence = input.getString(0);
		for (String word : sentence.split(" ")){
			collector.emit(input,new Values(word));//发射时带上元组
		}
		//手动调用ack()方法,保证消息处理成功
		collector.ack(input);
	}

不可靠Bolt的execute()方法如下:

@Override
	public void execute(Tuple input) {
		String sentence = input.getString(0);
		for (String word : sentence.split(" ")){
			collector.emit(new Values(word));
		}
	}

使用Anchoring机制实现可靠的Bolt

拓扑是一个消息(Tuple)沿着一个或多个分支的树节点。每个节点将ack(tuple)或者fail(tuple),这样当消息失败时Storm就会知道,通知Spout重发消息。因为一个Storm拓扑运行在一个高度并行的环境中,跟踪原始Spout实例的最好方法是,在消息Tuple中包含一个原始Spout的引用,这种技术称为Anchoring。

下面是可以保证消息处理的SplitSentence类,实现IRichBolt接口:

public class SplitSentenceBolt implements IRichBolt{

	private static final long serialVersionUID = 1L;

	//定义发射器
	private OutputCollector collector = null;
	
	@Override
	public void cleanup() {
		
	}

	@Override
	public void execute(Tuple tuple) {
		String sentence = tuple.getString(0);
		
		for (String word : sentence.split(" ")){
			//发射出去(带上元组以确保消息不丢失)
			collector.emit(tuple, new Values(word));
		}
		//处理完成时调用ack方法
		collector.ack(tuple);
	}

	@Override
	public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
		//初始化
		this.collector = collector;
	}

	@Override
	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		declarer.declare(new Fields("word"));
	}

	@Override
	public Map getComponentConfiguration() {
		return null;
	}

}
Anchoring发生的语句在collector.emit()中。如前所述,传递元组使Storm能够跟踪原始Spout。collector.ack(tuple)和collector.fail(tuple)告诉Spout知道每个消息发生了什么事,当消息树上的每个消息已经被处理,Storm认为来自Spout的元组被完全处理。当消息树在一个可配置的超时内处理失败,一个元组被认为是失败的。超时的默认值是30秒。可以通过改变拓扑的Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS配置项的值来改变这个超时值。当然, Spout需要考虑消息失败后重试或者丢弃消息的情况。处理的每一个元组必须是确认或者失败。Storm使用内存来追踪每个元组,所以如果你不对每个元组进行确认/失败,最终会耗尽内存。


使用IBasicBolt接口实现自动确认

为了简化编码,Storm为Bolt提供了一个IBasicBolt接口,它会在调用execute()方法之后正确调用ack()方法。BaseBasicBolt类是该接口的一个实现,用来实现自动确认。例如,在下面代码中的execute()方法中,元组被发射到BasicOutputCollector后自动锚定到输入元组。

public class SplitSentenceBolt implements IBasicBolt{

	private static final long serialVersionUID = 1L;

	@Override
	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		declarer.declare(new Fields("word"));
	}

	@Override
	public Map getComponentConfiguration() {
		return null;
	}

	@Override
	public void cleanup() {
		
	}

	@Override
	public void execute(Tuple tuple, BasicOutputCollector collector) {
		
		try {
			String sentence = tuple.getString(0);
			for (String word : sentence.split(" ")){
				//发射的时候直接发消息,不需要发送原来的tuple
				collector.emit(new Values(word));
			}
			//不需要手动的去调用ack()方法
		} catch (Exception e) {
			//显示的抛出FailedException异常(Storm发现这个错误之后会自动处理)
			throw new FailedException("消息处理失败");
		}
	}

	@Override
	public void prepare(Map conf, TopologyContext context) {
		
	}


}

注:execute()方法处理输入元组,并发射新的元组。execute()方法自动管理所有的Acking机制。如果希望元组失败,可以显示的抛出一个FiledException。

你可能感兴趣的:(Storm,Storm实战)