Kafka 丢消息情况分析

Kafka 丢消息情况分析

1. 问题排查方向

1.1 生产者

  1. 网络原因:网络抖动导致数据根本就没发送到 Broker 端。
  2. 数据原因:消息体太大超出 Broker 承受范围而导致 Broker 拒收消息。

1.2 kafka

由于 Kafka 中并没有提供「同步刷盘」的方式,所以说从单个 Broker 来看还是很有可能丢失数据的。

kafka 通过「多 Partition (分区)多 Replica(副本)机制 已经可以最大限度的保证数据不丢失,如果数据已经写入 PageCache 中但是还没来得及刷写到磁盘,此时如果所在 Broker 突然宕机挂掉或者停电,极端情况还是会造成数据丢失。

1.3 消费者

可能使用的「自动提交 Offset 方式

拉取消息后「先提交 Offset,后处理消息」,如果此时处理消息的时候异常宕机,由于 Offset 已经提交了, 待 Consumer 重启后,会从之前已提交的 Offset 下一个位置重新开始消费, 之前未处理完成的消息不会被再次处理,对于该 Consumer 来说消息就丢失了。

拉取消息后「先处理消息,在进行提交 Offset」, 如果此时在提交之前发生异常宕机,由于没有提交成功 Offset, 待下次 Consumer 重启后还会从上次的 Offset 重新拉取消息,不会出现消息丢失的情况, 但是会出现重复消费的情况,这里只能业务自己保证幂等性。

2. 解决方案

2.1 生产者

  1. 更换调用方式

使用带回调通知函数的方法进行发送消息,即 Producer.send(msg, callback) 或者使用Springkafka ProducerListener, 这样一旦发现发送失败, 就可以做针对性处理。

(1)网络抖动导致消息丢失,Producer 端可以进行重试。

(2)消息大小不合格,可以进行适当调整,符合 Broker 承受范围再发送。 通过以上方式可以保证最大限度消息可以发送成功。

  1. 修改ACK确认机制

0:不保证消息的到达确认,只管发送,低延迟但是会出现消息的丢失

1:发送消息,并会等待leader 收到确认后,一定的可靠性

-1:发送消息,等待leader收到确认,并进行复制操作后,才返回,最高的可靠性

注意:采用 -1 还需设置以下参数 replication.factor >= 2 min.insync.replicas > 1

  1. 重试次数

将 retries 设置为大于0的数

  1. 重试时间

该参数表示消息发送超时后两次重试之间的间隔时间,避免无效的频繁重试,默认值为100ms, 推荐设置为300ms

2.2 kafka

其是通过「异步批量刷盘」的策略,先将数据存储到 「PageCache」,再进行异步刷盘, 由于没有提供 「同步刷盘」策略, 因此 Kafka 是通过「多分区多副本」的方式来最大限度的保证数据不丢失。

  1. 禁止非 ISR 中的副本选举为 Leader

unclean.leader.election.enable:false

  1. 增加分区副本个数

表示分区副本的个数。建议设置 replication.factor >=3, 这样如果 Leader 副本异常 Crash 掉,Follower 副本会被选举为新的 Leader 副本继续提供服务。

  1. 消息写入 ISR 个数

消息至少要被写入成功到 ISR 多少个副本才算 "已提交", 建议设置min.insync.replicas > 1, 这样才可以提升消息持久性,保证数据不丢失。

另外我们还需要确保一下 replication.factor > min.insync.replicas, 如果相等,只要有一个副本异常 Crash 掉,整个分区就无法正常工作了,因此推荐设置成: replication.factor = min.insync.replicas +1, 最大限度保证系统可用性。

2.3 消费者

  1. 取消自动提交

拉取数据、业务逻辑处理、提交消费 Offset 位移信息

我们还需要设置参数 enable.auto.commit = false, 采用手动提交位移的方式。

另外对于消费消息重复的情况,业务自己保证幂等性, 保证只成功消费一次即可

引用:

unclean.leader.election.enable参数解释:https://blog.csdn.net/u013256816/article/details/80790185

kafka 丢数据分析:https://juejin.cn/post/7053742681117163528

kafka 丢数据分析:https://juejin.cn/post/7035983899788312589

broker配置参数:https://www.cnblogs.com/MyOnlyBook/p/10035670.html

producer的回调实现:https://flytoair.github.io/producer的回调实现.html

重平衡:https://juejin.cn/post/6992195021910835230

重平衡:https://www.cnblogs.com/chanshuyi/p/kafka_rebalance_quick_guide.html

重平衡解决方案:https://help.aliyun.com/document_detail/154454.html

重平衡解决方案:https://blog.csdn.net/lzxlfly/article/details/106246879

阻塞情况分析:https://segmentfault.com/a/1190000024441682

producer参数:https://jiamaoxiang.top/2020/10/24/Kafka-producer的几个重要配置参数/

分区与副本:https://juejin.cn/post/6844903862885679112

3. 现实场景

2022-04-26 12:22:50.120 ERROR 8603 --- [ad | producer-1] c.i.s.z.s.h.KafkaProducerHandle          : ======>>>>>> Failed to send message producerRecord: ProducerRecord(topic=devOps-test-count-client-access, partition=null, headers=RecordHeaders(headers = [], isReadOnly = true), key=null, value={"clientId":"57","clientType":"2","requestTime":"2022-04-26 12:19:35","requestType":"ordinary"}, timestamp=null)
org.apache.kafka.common.errors.TimeoutException: Expiring 1 record(s) for devOps-test-count-client-access-1:194139 ms has passed since batch creation
    
结论:kafka 网络原因导致客户端无法连接超时
    https://blog.51cto.com/u_12564104/2896730
    

    
[Producer clientId=producer-1] Received invalid metadata error in produce request on partition devOps-test-count-client-access-2 due to org.apache.kafka.common.errors.NetworkException: The server disconnected before a response was received.. Going to request metadata update now
    
结论:网络闪断:https://support.huaweicloud.com/dli_faq/dli_03_0121.html    
    
    
    
2022-04-21 09:57:53.079  WARN 8210 --- [ducerThread - 1] c.i.s.z.s.h.KafkaProducerHandle          : ======>>>>>> Failed to send message producerRecord: ProducerRecord(topic=devOps-test-count-client-access1, partition=null, headers=RecordHeaders(headers = [], isReadOnly = false), key=null, value={"clientId":"3","clientType":"5","requestTime":"2022-04-21 09:57:52","requestType":"ordinary"}, timestamp=null)
2022-04-21 09:57:53.080 ERROR 8210 --- [ducerThread - 1] c.i.s.z.c.ThreadPoolConfig               : ==========================Send failed; nested exception is org.apache.kafka.common.errors.TimeoutException: Topic devOps-test-count-client-access1 not present in metadata after 100 ms.=======================
    
    
结论:与 kafka 建立连接时间超过所设置时间,异常抛出。通过加大 max-block-ms 可避免异常抛出
    https://blog.csdn.net/PacosonSWJTU/article/details/121725539
    
    
    
    
2022-04-27 09:36:13.657 ERROR 18165 --- [ducerThread - 1] c.i.s.z.s.h.KafkaProducerHandle          : ======>>>>>> Failed to send message producerRecord: ProducerRecord(topic=devOps-test-count-client-access, partition=null, headers=RecordHeaders(headers = [], isReadOnly = true), key=null, value={"clientId":"40","clientType":"8000","requestTime":"2022-04-27 09:36:13","requestType":"ordinary"}, timestamp=null)

org.apache.kafka.common.errors.TimeoutException: Failed to allocate memory within the configured max blocking time 100 ms.
    

结论:生产者消息生产过快,内存缓存设置过小且等待时长超过设置时间 max-block-ms
    https://blog.csdn.net/maoyuanming0806/article/details/102864547
posted @ 2022-06-22 09:03  生活是很好玩的  阅读(665)  评论(0编辑  收藏  举报