简体   繁体   English

在Apache Storm上为螺栓添加重试机制

[英]Add retry mechanism for bolt on Apache Storm

I have a bolt (dispatcher) in my storm topology which open http request connection. 我的风暴拓扑中有一个螺栓(调度程序),可以打开http请求连接。

I want to add retry mechanism in-case of failure (connection time out, fail status, etc..). 如果发生故障(连接超时,故障状态等),我想添加重试机制。 The retry should occur only in the dispatcher-bolt and not to start over the whole topology. 重试应该仅在调度程序螺栓中进行,而不能从整个拓扑开始。

usually what I would do is to add a queue which would be responsible for the retry and exception handling (for example after 3 time automatically dispatch the message to an error queue..) 通常我要做的是添加一个队列,该队列负责重试和异常处理(例如3次后自动将消息分发到错误队列。)

Is it OK to do such thing inside a bolt? 在螺栓内做这样的事情可以吗? anyone has any experience with that and could suggest which library I could use? 任何人都有任何经验,可以建议我可以使用哪个库?

Sure! 当然! That seems like a reasonable way to handle errors. 这似乎是处理错误的合理方法。 I'm not sure what library you would need to use except for the one which provides the API for connecting to the queuing system of your choice. 除了提供用于连接到您选择的排队系统的API的库之外,我不确定您需要使用哪种库。

Inside your bolt, you might have code which looks like this: 在您的螺栓内,您可能具有如下代码:

@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
   try {
      // do something which might fail here...
   } catch (Exception e) {
      // do you want to log the error?
      LOG.error("Bolt error {}", e);
      // do you want the error to show up in storm UI?
      collector.reportError(e);
      // or just put information on the queue for processing later
   }
}

As long as you are catching the exception inside your bolt, your topology will not restart. 只要您在螺栓内部捕获到异常,拓扑就不会重新启动。

Another option is to leverage Storm's built-in ability for guaranteed message processing to fail tuples and retry them that way. 另一个选择是利用Storm的内置功能来确保消息处理以使元组失败并以这种方式重试。

package banktransactions;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.apache.log4j.Logger;

import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichSpout;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Values;

public class TransactionsSpouts extends BaseRichSpout{

private static final Integer MAX_FAILS = 2;
Map<Integer,String> messages;
Map<Integer,Integer> transactionFailureCount;
Map<Integer,String> toSend;
private SpoutOutputCollector collector;  

static Logger LOG = Logger.getLogger(TransactionsSpouts.class);


public void ack(Object msgId) {
    messages.remove(msgId);
    LOG.info("Message fully processed ["+msgId+"]");
}

public void close() {

}

public void fail(Object msgId) {
    if(!transactionFailureCount.containsKey(msgId))
        throw new RuntimeException("Error, transaction id not found ["+msgId+"]");
    Integer transactionId = (Integer) msgId;

    //Get the transactions fail
    Integer failures = transactionFailureCount.get(transactionId) + 1;
    if(failures >= MAX_FAILS){
        //If exceeds the max fails will go down the topology
        throw new RuntimeException("Error, transaction id ["+transactionId+"] has had many errors ["+failures+"]");
    }
    //If not exceeds the max fails we save the new fails quantity and re-send the message 
    transactionFailureCount.put(transactionId, failures);
    toSend.put(transactionId,messages.get(transactionId));
    LOG.info("Re-sending message ["+msgId+"]");
}

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);
        }
        /*
         * The nextTuple, ack and fail methods run in the same loop, so
         * we can considerate the clear method atomic
         */
        toSend.clear();
    }
    try {
        Thread.sleep(1);
    } catch (InterruptedException e) {}
}

public void open(Map conf, TopologyContext context,
        SpoutOutputCollector collector) {
    Random random = new Random();
    messages = new HashMap<Integer, String>();
    toSend = new HashMap<Integer, String>();
    transactionFailureCount = new HashMap<Integer, Integer>();
    for(int i = 0; i< 100; i++){
        messages.put(i, "transaction_"+random.nextInt());
        transactionFailureCount.put(i, 0);
    }
    toSend.putAll(messages);
    this.collector = collector;
}

public void declareOutputFields(OutputFieldsDeclarer declarer) {
    declarer.declare(new Fields("transactionMessage"));
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM