Kafka进阶02

一.  问题场景以及解决的问题

          哪些异常可以重试

          如何实现重试

          场景:发送消息到Broker时抛出异常,并且是允许重试的异常——>就会进行最大重试retries参数 指定的次数

二.  机制解读

1. 允许重试的必要条件

       a)  重试次数少于参数retries指定的值

       b)  异常是RetriableException类型   或者   TranscationManager允许重试

2.  RetriableException—通过重试 使用较短时间可以成功的异常

3.  TransactionManager允许重试——异常不满足类型,但此处允许,也会进行重试

         |——此参数是KafkaProducer中构造Sender传入的

         |——transactionManager.canRetray(response,batch)

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.idempotence为false,并且又配置了transactional.id,就会抛出这个异常
    if (!idempotenceEnabled && userConfiguredIdempotence && userConfiguredTransactions) {
        throw new ConfigException("Cannot set a " + ProducerConfig.TRANSACTIONAL_ID_CONFIG + " without also enabling idempotence.");
    } 
    // 如果用户配置了transactional.id,那么idempotenceEnabled就认为是true(与)
    if (userConfiguredTransactions) {
        idempotenceEnabled = true;
    }

    // 只有用户配置了transactional.id,且enable.idempotence没有设置为false,这里才为true,就会构造一个有效的TransactionManager;从这里可知,如果用户没有配置transactional.id,那么TransactionManager为null
    if (idempotenceEnabled) {
        // 构造TransactionManager的几个重要参数
        String transactionalId = config.getString(ProducerConfig.TRANSACTIONAL_ID_CONFIG);
        int transactionTimeoutMs = config.getInt(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG);
        long retryBackoffMs = config.getLong(ProducerConfig.RETRY_BACKOFF_MS_CONFIG);
        transactionManager = new TransactionManager(logContext, transactionalId, transactionTimeoutMs, retryBackoffMs);
        ... ...
    }
   
    return transactionManager;
}

4.  如何实现重试

4.1  原理图

              1|——创建KafkaProducer对象后,就会创建一个后台线程KafkaThread,它会扫描判断RecordAccumlator中是否有消息

              2|——调用KafkaProducer.send()发送消息,把消息保存到RecordAccumlator中(append)

              3|——后台线程 扫描i到RecordAccumlator中有消息后,将消息发送到Broker               (真正发送)

              4|——如果发送失败,判断是否需要重试。如果允许重试,把消息保存到RecordAccumlator中,等待后台线程再次扫描                                                                         |——发送的代码在Sender.java——|

4.2 RecordAccumlator——保存消息/重发消息的核心

                                     |——核心数据结构是Deque,双端队列

          |——发送消息之前,保存发送的消息

          |——异步线程启动后,从这里取数据发送到Broker

          |——当出错允许重试后,重新保存消息

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值