storm-executor-spout(1)

2121SC@SDUSC

storm-executor-spout(1)

在设计拓扑结构时,很重要事情就是消息的可靠性。当有无法处理的消息时,需要决定该怎么办,以及作为一个整体的拓扑结构该做些什么,高可靠性的拓扑必须管理丢失的消息,必然消耗更多资源;可靠性较低的拓扑可能会丢失一些消息,占用的资源也相应更少。
要在spout中管理可靠性,可以在分发时包含一个元组的消息ID(collector.emit(new Values(…),tupleId))。
在一个元组被正确的处理时调用ack方法,而在失败时调用fail方法。
当一个元组被所有的靶bolt和锚bolt处理过,即可判定元组处理成功

发生下列情况之一时为元组处理失败:

1、提供数据的spout调用collector.fail(tuple)
2、处理时间超过配置的超时时间
需求如下:
如果事务失败了,重新发送消息
如果失败了太多次,终结拓扑运行
创建一个spout和一个bolt,spout随机发送100个事务ID,有80%的元组不会被bolt收到。实现spout时利用Map分发事务消息元组,这样就比较容易实现重发消息。

public void nextTuple() {
if(!toSend.isEmpty()){
    for(Map.Entry<Integer, String> transactionEntry : toSend.entrySet()){
        Integer transactionId = transactionEntry.getKey();
        String transactionMessage = transactionEntry.getValue();
        collector.emit(new Values(transactionMessage),transactionId);
    }
    toSend.clear();
}
}

如果有未发送的消息,得到每条事务消息和它的关联ID,把它们作为一个元组发送出去,最后清空消息队列。调用map的clear是安全的,因为nextTuple失败时,只有ack方法会修改map,而它们都运行在一个线程内。

维护两个map用来跟踪待发送的事务消息和每个事务的失败次数。ack方法只是简单的把事务从每个列表中删除。

 public void ack(Object msgId) {
messages.remove(msgId);
failCounterMessages.remove(msgId);
}

fail方法决定应该重新发送一条消息,还是已经失败太多次而放弃它。

注:如果使用全部数据流组,而拓扑里的所有bolt都失败了,spout的fail方法才会被调用。

public void fail(Object msgId) {
Integer transactionId = (Integer) msgId;
//检查事务失败次数
Integer failures = transactionFailureCount.get(transactionId) + 1;

if(failes >= MAX_FAILS){
    //失败数太高了,终止拓扑
    throw new RuntimeException("错误, transaction id 【"+

     transactionId+"】 已失败太多次了 【"+failures+"】");
}

//失败次数没有达到最大数,保存这个数字并重发此消息
transactionFailureCount.put(transactionId, failures);
toSend.put(transactionId, messages.get(transactionId));
LOG.info("重发消息【"+msgId+"】");
}

首先,检查事务失败次数。如果一个事务失败次数太多,通过抛出RuntimeException终止发送此条消息的工人。否则,保存失败次数,并把消息放入待发送队列(toSend),它就会再次调用nextTuple时得以重新发送。

注:Storm节点不维护状态,因此如果你在内存保存信息,而节点又不幸挂了,就会丢失所有缓存的消息。
Storm是一个快速失败的系统。拓扑会在抛出异常时挂掉,然后再由Storm重启,恢复到抛出异常前的状态。

获取数据

一、直接连接

在一个直接连接的架构中,spout直接与一个消息分发器连接在这里插入图片描述

这个架构很容易实现,尤其是在消息分发器是已知设备或已知设备组时。已知设备满足:拓扑从启动时就已知道该设备,并贯穿拓扑的整个生命周期保持不变。未知设备就是在拓扑运行期添加进来的。已知设备组就是从拓扑启动时组内所有设备都是已知的。

spout从配置对象得到连接参数(track,user,password),并连接到API(在这个例子中使用Apache的DefaultHttpClient)。它一次读一行数据,并把数据从JSON转化成Java对象,然后发布它。

public void nextTuple() {
//创建http客户端
client = new DefaultHttpClient();
client.setCredentialsProvider(credentialProvider);
HttpGet get = new HttpGet(STREAMING_API_URL+track);
HttpResponse response;
try {
    //执行http访问
    response = client.execute(get);
    StatusLine status = response.getStatusLine();
    if(status.getStatusCode() == 200){
        InputStream inputStream = response.getEntity().getContent();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String in;
        //逐行读取数据
        while((in = reader.readLine())!=null){
            try{
                //转化并发布消息
                Object json = jsonParser.parse(in);
                collector.emit(new Values(track,json));
            }catch (ParseException e) {
                LOG.error("Error parsing message from twitter",e);
            }
        }
    }
} catch (IOException e) {
    LOG.error("Error in communication with twitter api ["+get.getURI().toString()+"], 
       sleeping 10s");
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e1) {}
}

}
注:如果锁定nextTuple方法,永远也不会执行ack和fail方法。

知识点参考:https://ifeve.com/getting-started-with-storm-4/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值