前面对kafka的学习中已经了解到KafkaProducer通过设定参数retries
,如果发送消息到broker时抛出异常,且是允许重试的异常,那么就会最大重试retries参数指定的次数。
本片文章主要分析几个问题:
- 哪些异常可以重试
- 如何实现重试
接下来通过分析一一解开这些问题的答案。
1.哪些异常可以重试
org.apache.kafka.clients.producer.internals.Sender类中有如下方法:
private boolean canRetry(ProducerBatch batch, ProduceResponse.PartitionResponse response) {
return batch.attempts() < this.retries &&
((response.error.exception() instanceof RetriableException) ||
(transactionManager != null && transactionManager.canRetry(response, batch)));
}
通过方法名可知,其作用是判断是否能重试,由方法体内的实现可知,允许重试需要满足两个条件:
1. 重试次数少于参数retries
指定的值;
2. 异常是RetriableException类型或者TransactionManager允许重试;
transactionManager.canRetry()后面会分析;先看看哪些异常是RetriableException类型异常。
- RetriableException类型异常
kafka对RetriableException异常注释是:短暂性的通过重试可以成功的异常;通过RetriableException类关系图可知,可重试异常有图中RetriableException的子类那些异常(可以通过异常是否继承自RetriableException判断是否可重试异常):
- TransactionManager允许重试
如果异常不属于RetriableException类型,但是只要满足(transactionManager != null && transactionManager.canRetry(response, batch))
就允许重试,所以,首先需要满足transactionManager不为null。transactionManager是在KafkaProducer中构造Sender传入的。构造TransactionManager的核心源码如下:
private static TransactionManager configureTransactionState(ProducerConfig config, LogContext logContext, Logger log) {
TransactionManager transactionManager = null;
boolean userConfiguredIdempotence = false;
// 用户设置的Properties参数中是否有'enable.idempotence',如果有的话, 就用用户配置的
if (config.originals().containsKey(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG)) {
userConfiguredIdempotence = true;
}
// 用户设置的Properties参数中是否有'transactional.id',如果有的话, 就用用户配置的
boolean userConfiguredTransactions = false;
if (config.originals().containsKey(ProducerConfig.TRANSACTIONAL_ID_CONFIG)) {
userConfiguredTransactions = true;
}
// 得到参数'enable.idempotence'的值
boolean idempotenceEnabled = config.getBoolean(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG);
// 如果用户显示配置enable.idempote