storm-组件

Spout

为了管理Spout的可靠性,可以在发射元组的时候,在元组里面包含一个消息ID: collector.emit(new Values(..),tupleId);

当元组处理时会调用ack()方法,当元组失败时调用fail()方法,当元组被所有目标Bolt和锚定Bolt处理时,认为元组处理成功。

当如下情况发生时,元组处理会失败:

collectior.fail(tuple)方法补目标Spout调用 。

处理时间超过配置的超时时间。



Bolt

bolt的主要方法:

declareOutputFileds(OutputFieldsDeclarer declarer) ;

prepare(Map conf,TopologyContext context,OutputCollector collector); 仅在Bolt开始处理Tuple之前调用;

execute(Tuple input);处理一个bolt的输入

clearup();当bole关闭时调用


可靠的与不可靠的Bolt

可靠的Bolt

    @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

    @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<String, Object> 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<String, Object> 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) {  
          
    }  
  
  
} 

综上所述:

要实现可靠的Bolt,可以继承IBasicBolt或者实现IBasicBolt接口。

要实现不可靠Bolt,可以继承BaseRichBolt或者实现IRichBolt接口。

不可靠Bolt可以使用Anchoring机制实现可靠的Bolt


事务拓扑中的Bolt

在事务拓扑中存在3种类型的Bolt:

BasicBolt:BasicBolt不处理Batch,不能处理单个输入元组。

BatchBolt:BatchBolt能够处理元组Batch,Batch中的每个元组都会被调用 execute方法,当Batch处理完成时调用finishBatch方法。

storm会为每个batch创建这个一个BatchBolt对象的新实例。而这些BatchBolt是运行在BatchBoltExecutor里面的。

在事务拓扑中的所有元组必须以TransactionAttempt作为元组的第一个字段。这使storm可以识别元组属于哪个Batch.

标记为Committer的BatchBolt:该Bolt和普通BatchBolt的区别是调用 finishBatch的时机。一个CommitterBolt在提交阶段会调用 finishBatch.

CommitterBolt不会在事务处理阶段调用finishBatch方法

有两种方法可以使BatchBolt成为Committer BatchBolt,实现ICommitter接口或者使用TransactionalTopologyBuilder类的setCommiterBolt方法。


在transaction topology里面发射的所有的tuple都必须以TransactionAttempt作为第一个field,然后storm可以根据这个field来判断哪些tuple属于一个batch。所以你在发射tuple的时候需要满足这个条件。TransactionAttempt包含两个值: 一个transaction id,一个attempt id。transaction id的作用就是我们上面介绍的对于每个batch是唯一的,而且不管这个batch replay多少次都是一样的。 我们可以把attempt id理解成replay-times, storm利用这个id来区别一个batch发射的tuple的不同版本。transaction id对于每个batch加一, 所以第一个batch的transaction id是”1″, 第二个batch是”2″,以此类推。execute方法会为batch里面的每个tuple执行一次。最后, 当这个bolt接收到某个batch的所有的tuple之后, finishBatch方法会被调用。这个例子里面的BatchCount类会在这个时候发射它的局部数量到它的输出流里面去。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值