【杂谈】合理使用Kafka,防止消息丢失
前言
并非所有业务场景都要求消息绝对不丢失。对很多应用来说,为了追求更高的吞吐量,少量的消息丢失是可以容忍的。
然而,在一些关键的业务场景中,确保消息不丢失至关重要。本文将重点讨论需要保证消息可靠性的场景,并提供相关的优化建议。
消息丢失的场景
消息丢失的场景可以归纳为三种主要情况:
场景 1:【生产】数据未写入 Kafka
在某些情况下,消息未能成功写入 Kafka,但生产者客户端已将其标记为已处理,从而导致数据丢失。可能的原因包括:
Kafka 客户端
Kafka 生产者客户端通常会将多个消息积压成一个批次进行提交。如果在批次提交期间,生产者客户端崩溃或挂掉,消息就会丢失。
Kafka Broker
- 批次消息已经通过网络传输到 Broker,但 Broker 接收到消息后发生故障(Kafka内存不足,磁盘故障),导致消息未能保存。
- 消息已成功保存到 Broker,但在Flush到磁盘之前挂了
处理方式
- 
生产者客户端:生产者在收到 ACK 确认后再将消息标记为已发送。这样可以确保即使生产者崩溃或重启,未确认的消息也会被重新发送。 
同步发送 vs 异步发送:
- 同步发送:同步发送是指调用 send(record).get()后,代码会阻塞,直到从 Broker 获得响应,才会继续执行(注意:如果acks=0,则不会等待 Broker 的响应)。
- 异步发送:异步发送是指调用 send(record, callback)后,代码会继续执行。当 Broker 返回响应时,会触发回调函数。
如何选择同步发送与异步发送?
- 如果发送的消息之间有顺序依赖关系,建议使用同步发送,确保前一条消息成功保存后,才会提交后一条消息。
- 如果消息之间没有顺序要求,推荐使用异步发送,这样可以提高吞吐量,因为无需等待前一条消息的提交结果。
场景2:【存储】分区首领节点宕机,其他分区副本未同步
Kafka生产者默认acks=1,即Broker将消息写入分区首领节点,就会返回确认。但是如果在数据同步到其他分区副本之前,分区首领就挂了,数据就丢失了。
具体场景:
1.生产者将消息提交到分区首领节点
2.该节点成功将消息写入本地文件
3.返回成功给生产者客户端
4.生产者标记消息为已发送
5.分区首领节点宕机
6.选出新的分区首领节点继续服务(不包含该消息)
处理方式:
调整生产者的acks配置,例如设置acks=2,要求Kafka服务端必须至少将数据写入两个分区副本后才返回成功。
场景 3:【消费】已写入 Kafka,但由于偏移量处理不当导致消息跳过
这种情况发生在消费者客户端成功拉取消息后,但在消息处理前提交了偏移量,导致故障重启后消息被跳过。
具体场景
1.消费者采用自动提交模式
2.消费者拉取一批消息(例如1000~2000)
3.自动提交偏移量2000
4.应用消费到1500的时候挂了
5.应用重启,从2000开始消费。(1500~2000之间的消息就被跳过了)
处理方式
上层应用应在消息被实际处理后再提交偏移量。这可以确保只有在消息被成功处理后,才会提交其偏移量。
如果数据量较大,可以将消息分批处理,并在每个批次处理完成后提交一次偏移量。
注意:
1.上层应用不能只是将消息写入内部处理队列,就视为已处理。
2.偏移量提交间隔不能太长,否则会导致服务重启后重复消费过多的消息。
总结
通过合理配置 Kafka 的 acks 参数、选择合适的发送方式以及精确控制消费者的偏移量,能够显著降低消息丢失的概率,提高系统的稳定性和消息传递的可靠性。这些优化措施对于构建高可用和高性能的分布式系统至关重要。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号