kafka如何保证消费不丢失

消息可靠性维度

消息的可靠性性一般需要从三个维度进行考量。分别是生产端、服务端、消费端。

  • 发送端可靠性:生产者需要确保消费发送到了服务端机器上。
  • 服务端存储可靠性:服务端需要保证消息的持久化不丢失。
  • 消费可靠性:消费端需要确认每条消息都被成功进行消费。

producer可靠性

对于kafka生产端来说,发送消息主要有两类API可以调用,分别是producer.send(msg)和producer.send(msg,callback)。

  • producer.send(msg):俗称“发后即忘”,不管消息有没有成功写入到broker端,生产者都不会收到任何通知,那么到消息因为某些原因(如:网络异常,消息体过大等)并未被broker接受时,就产生了消息丢失。
 // sendAPI
 KafkaProducer producer = new KafkaProducer<String, String>(props);
 String message = "test message";
 producer.send(new ProducerRecord<String, String>("test-topic", message));
  • producer.send(msg,callback):带有回调函数,通过callback的回调来处理broker端的响应结果,如果未成功发送,那么就可以做响应的处理工作,如进行重试,记录日志等。
	// send带回调API
    KafkaProducer producer = new KafkaProducer<String, String>(props);
    String message = "test message";
    producer.send(new ProducerRecord<String, String>("test-topic", message), new Callback() {
         @Override
         public void onCompletion(RecordMetadata recordMetadata, Exception e) {
             // 具体的逻辑判断
             if (Objects.nonNull(e)) {
                 System.out.println("发送异常");
             }
         }
     });

在kafka中,对于某些异常,生产者捕获到异常会,会进行异常重试,重试的次数是由retries参数来控制的,因此为了保证消费的可靠性,还需要将这个参数的值设置为大于0的值,一般可设置为3~5。

同时对于生产者而言,还有一个重要的参数需要设置,就是acks的值,acks可以设置为 1,0,-1三个值,每个值的含义如下

  • 0:生产者发送消息后,不需要等待任何服务端的响应。
  • 1:其默认值为此值,表示生产者将消息成功写入到leader副本中,服务端就会返回成功响应。
  • -1 或 all:生产者发送消息后,消息需要写入ISR集合中全部副本,才算提交成功。
    因此为了保证消息的可靠性,需要将acks参数设置为-1,这样可以避免leader结点宕机后,follower结点没有及时同步到消息,而产生的数据丢失。

broker端可靠性

在kafka中,每条消费都会被存储到磁盘上进行持久化存储,即使broker因为异常进行重启,也不会消息丢失,并且在生产环境,kafka都是以集群的方式进行部署,同时因为kafka的分区和副本的特性,一般可以保证broker端的消息不丢失的情况,但是也有一些特殊情况下存在消息丢失的可能。

broker端的参数设置不合理:对于每个消费分区而言,副本数replication.factor >= 3,消息进行多余的冗余备份,可以防止因为broker端异常,导致的消息丢失。

当所有follower副本的消息同步无法同步leader副本时,就会自动退送ISR集合,这个时候ISR集合只有1条记录,当出现这种情况时,生产端acks设置为-1就退化了1,此时leader分区出现异常时,就会出现消息丢失的情况,所以需要设置min.insync.replicas > 1,这个参数用来控制消息需要最小写入的副本数。

当leader副本出现异常后,kafka回进行重选举,从follower副本中,选出新的leader节点,如果选出的新leader副本的消息落后于此前的leader副本,也会存在消息丢失的情况,所以需要将参数unclean.leader.election.enable = false,表示不允许,非ISR集合中的分区,进行leader选举。

consumer可靠性

在kafka中,每一条消息就是自己offset偏移量,消费者每次消费完消息后,都会提交自己消费的位移,如下图所示,消费A消费到offset = 9的数据,消费者B消费到offset = 11的数据。consumer会提交自己的消费位移,用来知道自己消费的位置,如果消费位移提交不当,也会产生消息没有消费的情况。
在这里插入图片描述
对于consumer端来说,有两种提交消费位移的方式,分别是自动提交和手动提交。

  • 自动提交:设置为enable.auto.commit为true,表示开启自动提交,自动提交会在每次调用poll时,提交上次poll时的消费位移,每次poll时,都是提交上次的offset的位移,如果是在单线程的情况,不会出现消费丢失的情况,但是对应多线程的应用来说,就有可能出现消费丢失的情况,例如我们每次poll到的数据都先放在一个队列中,用一个专门的线程来处理队列中的数据,但是我们poll的时候,上次提交的位移还没有完成消费,消费端出现了宕机,这个时候消费端重启后,就会出现消息丢失的情况。
 Properties props = new Properties();
        // 开启自动提交
        props.put("enable.auto.commit", "true");
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
        consumer.subscribe(Arrays.asList("test-topic"));
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            for (ConsumerRecord<String, String> record : records)
                System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
        }
  • 手动提交,使用commitSync() 和 commitASync()API来进行手动提交,手动提交,可以让我们根据自己的实际消费情况来设置什么时间点进行提交位移,将位移提交交给用户自己,合理设置位移提交点可以保证消费的消费不丢失。
 while (true) {
            ConsumerRecords<String, String> records =
                    consumer.poll(Duration.ofSeconds(1));
            process(records); // 处理消息
            try {
                // 提交消费位移
                consumer.commitSync();
            } catch (CommitFailedException e) {
                System.out.println("处理提交失败异常"); // 处理提交失败异常
            }
        }

消费不丢失参数配置

  1. 在producer端使用,不要使用producer.send(msg)的API,要使用producer.seng(msg,callback)带有回调方法的API,来进行消息发送会掉确认。
  2. producer端设置acks=all,表示消息全部提交到ISR集合中的全部分区,才算消息提交成功。
  3. producer端设置retries > 0,此参数,表示当生产者发送出现异常(如:broker出现网络抖动,导致超时)producer端进行重试的次数。
  4. broker端,unclean.leader.election.enable = false,表示不允许,非ISR集合中的分区,进行leader选举,因为如果一个follower分区,消息落后于leader分区太远,当这个follower成为leader分区后,就会存在消息丢失。
  5. broker端,replication.factor >= 3,表示副本的数量,消息进行多余的冗余备份,可以防止因为broker端异常,导致的消息丢失。
  6. broker端,min.insync.replicas > 1,这个参数用来控制消息需要最小写入的副本数。
  7. consumer端,将自动提交改为手动提交,确认消息消费完成后,在进行提交。
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值