我知道SpoutConfig有retryLimit
来设置重新处理邮件的次数。
关于retryLimit
,这是我在SpoutConfig.class中找到的消息:
指数退避重试设置。这些被使用 ExponentialBackoffMsgRetryManager用于在螺栓后重试消息 调用OutputCollector.fail()。
我想知道在我的代码中任何给定的Bolt中处理元组时是否有任何方法可以知道重试的确切数量。
例如,如果我设置retryLimit=5
并且它第一次被重新处理时失败(调用OutputCollector.fail()
)第二次我想知道这个元组已经失败了一次。< / p>
感谢您对此的帮助。
感谢。
答案 0 :(得分:1)
没有内置支持。 https://github.com/apache/storm/blob/master/external/storm-kafka-client/src/main/java/org/apache/storm/kafka/spout/RecordTranslator.java从Kafka记录中产生的元组仅取决于Kafka记录,而不取决于重放次数。
默认的RecordTranslator将作为元组的一部分发出主题,分区和偏移量,因此您可以使用它们检查您的螺栓之前是否已经看过元组(假设您有某种状态存储区)。为什么螺栓需要知道元组失败了多少次?
编辑:
我认为我们没有添加故障的原因之一是作为发出的元组的一个选项,它是不可靠的。由于元组的故障数仅存在于spout中的内存中,因此可能会出现元组失败,spout崩溃,以及从未看到故障计数大于0的元组的情况。
即使我们在spout中有持久状态存储,仍然会出现失败的元组未被标记的情况,例如如果喷口首先崩溃,之前发出的元组则失败。重新启动的喷口无法识别先前发出的元组,因此不会将其标记为失败。
在我看来,你真正需要跟踪的是喷口是否多次发出一个元组,而不是喷口是否认为它先前已经失效。
您可以使用https://github.com/apache/storm/blob/master/external/storm-kafka-client/src/main/java/org/apache/storm/kafka/spout/KafkaTupleListener.java和onEmit
来跟踪多次发出的偏移量。因为它作为喷口的一部分运行,所以当元组被激活时清理状态应该非常简单。由于在喷口发出元组之后运行onEmit
,因此仍有可能错过失败的元组,因此如果喷口在喷射后立即崩溃,则可能会错过故障。也许考虑一下你是否可以先用某种方式设计这个要求。
答案 1 :(得分:0)
据我所知,Storm对此不提供内置支持。
我尝试了以下提到的实现:
public class AuditMessageWriter extends BaseBolt {
private static final long serialVersionUID = 1L;
Map<Object, Integer> failedTuple = new HashMap<>();
public AuditMessageWriter() {
}
/**
* {@inheritDoc}
*/
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
//any initialization if u want
}
/**
* {@inheritDoc}
*/
@Override
public void execute(Tuple input) {
try {
//Write your processing logic
collector.ack(input);
} catch (Exception e2) {
//In case of any exception save the tuple in failedTuple map with a count 1
//Before adding the tuple in failedTuple map check the count and increase it and fail the tuple
//if failure count reaches the limit (message reprocess limit) log that and remove from map and acknowledge the tuple
log(input);
ExceptionHandler.LogError(e2, "Message IO Exception");
}
}
void log(Tuple input) {
try {
//Here u can pass result to dead queue or log that
//And ack the tuple
} catch (Exception e) {
ExceptionHandler.LogError(e, "Exception while logging");
}
}
@Override
public void cleanup() {
// To declare output fields.Not required in this alert.
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// To declare output fields.Not required in this alert.
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}