这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
本文主要阐述一下在开发过程中可能发生的 kafka 消息丢失问题。
消息丢失
首先问自己,可能丢失的阶段有哪些?
- producer 丢失
- consumer 丢失
- kafka server 丢失
清楚了阶段,就来想想,如何解决丢失?
producer
一般来说,producer 发送msg使用 → producer.send(msg) 。这种情况下,开发者发送消息出去,并不知道 msg 是否发送成功:
- 发送是异步的 ⇒ client 端有缓冲区 →
RecordBatch - 实际意义上的不知道是不是发送成功
此处可以使用:producer.send(msg, callback) 。
因为既然异步处理,回调的作用就只是在操作完毕后,做一些确认或者是失败补偿机制啥的。
另外就是:重试机制 ⇒ 可以将 retries 设置为较大的值(一般为3),同时注意重试间隔(退避算法啥的)。因为无效的重试是没有意义的,浪费资源。
consumer
这个阶段的丢失其实是:消费者没有真正消费成功这条 msg。如何评定 consumer 消费成功 msg?
就是向 server 发送 commit offset 的请求,server 认定你已经消费了(不然你提交干嘛,闹着玩呢?),但是 consumer 实际上没有对 msg 做处理或者是消费逻辑失败。
解决方案 :auto.commit = true ⇒ auto.commit = false
但是紧接出现的问题是:重复消费,以至于如何保证消费幂等的问题?
先按下不表,后面来说这个大块的问题
server
本质来说,如果说是 server 端出问题,一般是副本复制机制没有做到位。
你在单节点情况下,出现了什么 server 宕机;或者是多节点下,同步没有到位,都会有可能发生消息丢失的情况。
这种情况,通过调参解决。涉及 4 个参数:
acks = allreplication.factor ≥ 3min.insync.replicas > 1unclean.leader.election.enable = false
对于 1 :看开发情况,是否需要全部副本都接收到 msg
对于2/3:replication.factor = min.insync.replicas + 1 不能说一个副本挂了,导致整个集群无法正常工作,不符合高可用。
对于 4:当 leader 副本发生故障时就不会从 follower 副本中和 leader 同步程度达不到要求的副本中选择出 leader ,这样降低了消息丢失的可能性。