因为在具体开发中某些环节考虑使用kafka却担心有消息丢失的风险,本周结合项目对kafka的消息可靠性做了一下调研和总结:
首先明确一下丢消息的定义。kafka集群中的部分或全部broker挂了,导致consumer没有及时收到消息,这不属于丢消息。broker挂了,只要消息全部持久化到了硬盘上,重启broker集群之后,使消费者继续拉取消息,消息就没有丢失,仍然全量消费了。
以我的理解,所谓丢消息,意味着:开发人员未感知到哪些消息没有被消费。
我把消息的丢失归纳了以下几种情况:
1)、 producer把消息发送给broker,因为网络抖动,消息没有到达broker,且开发人员无感知。
解决方案:producer设置acks参数,消息同步到master之后返回ack信号,否则抛异常使应用程序感知到并在业务中进行重试发送。这种方式一定程度保证了消息的可靠性,producer等待broker确认信号的时延也不高。
2)、 producer把消息发送给broker-master,master接收到消息,在未将消息同步给follower之前,挂掉了,且开发人员无感知。
解决方案:producer设置acks参数,消息同步到master且同步到所有follower之后返回ack信号,否则抛异常使应用程序感知到并在业务中进行重试发送。这样设置,在更大程度上保证了消息的可靠性,缺点是producer等待broker确认信号的时延比较高。
3)、 producer把消息发送给broker-master,master接收到消息,master未成功将消息同步给每个follower,有消息丢失风险。
解决方案:同上。
4)、 某个broker消息尚未从内存缓冲区持久化到磁盘,就挂掉了,这种情况无法通过ack机制感知。
解决方案:设置参数,加快消息持久化的频率,能在一定程度上减少这种情况发生的概率。但提高频率自然也会影响性能。
5)、consumer成功拉取到了消息,consumer挂了。
解决方案:设置手动sync,消费成功才提交。
综上所述,集群/项目运转正常的情况下,kafka不会丢消息。一旦集群出现问题,消息的可靠性无法完全保证。要想尽可能保证消息可靠,基本只能在发现消息有可能没有被消费时,重发消息来解决。所以在业务逻辑中,要考虑消息的重复消费问题,对于关键环节,要有幂等机制。
几条建议:
1)、如果一个业务很关键,使用kafka的时候要考虑丢消息的成本和解决方案。
2)、producer端确认消息是否到达集群,若有异常,进行重发。
3)、consumer端保障消费幂等性。
4)、运维保障集群运转正常且高可用,保障网络状况良好。