【杂谈】合理使用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 参数、选择合适的发送方式以及精确控制消费者的偏移量,能够显著降低消息丢失的概率,提高系统的稳定性和消息传递的可靠性。这些优化措施对于构建高可用和高性能的分布式系统至关重要。

posted @ 2024-12-24 15:24  猫毛·波拿巴  阅读(195)  评论(0)    收藏  举报