kafka之消费者线程安全设计
消费者线程安全问题
首先kafka的Java consumer是单线程的设计,但准确来说是双线程,kafka新版本中kafkaConsumer变成了用户主线程和心跳线程的双线程设计。
所谓用户主线程可以理解为启动Consumer应用程序的main方法的那个线程,而心跳线程(Heartbeat Thread)只负责定期发送心跳给对应的Boroker,以标识消费者应用的存活性。
引入心跳线程的目的还有一个:解耦真实的消息处理逻辑与消费者组成员存活性管理。
尽管多了一个心跳线程,但是实际的消息处理还是由主线程完成,所以我们还是可以认为KafkaConsumer是单线程设计的。
采用单线程设计的原因
1、新版本Consumer设计了单线程+轮询的机制,这种设计能够较好的实现非阻塞式的消息获取。
2、单线程的设计能够简化Consumer端的设计,将处理消息的逻辑是否使用多线程的选择,交由你来决定。
3、不论使用那种编程语言,单线程的设计都比较容易实现,并且,单线程设计的Consumer更容易移植到其它语言上。
多线程安全问题
Kafka Consumer不是线程安全的,在使用中必须在业务中确保线程安全。
死信队列&重试队列
重试队列:
与重试队列对应的还有一个“回退队列”的概念,比如消费者在消费时发生了异常,则不会对这一次消费进行确认(Ack),进而发生回滚消息的操作之后消息始终会放在队列的顶部,然后不断被处理和回滚,导致队列陷入死循环。为了解决这个问题,可以为每个队列设置一个回退队列,它和死信队列都是为异常的处理提供的一种机制保障,实际情况下回退队列的角色可以由死信队列和重试队列来扮演。
重试队列其实可以看成是一种回退队列,具体指消费端消费消息失败时,为防止消息无故丢失而重新将消息回滚到Broker中。与回退队列不同的是重试队列一般分成多个重试等级,每个重试等级一般也会设置重新投递延时,重试次数越多投递延时就越大。
死信队列:
当一条消息初次消费失败,消息队列MQ会自动进行消息重试;达到最大重试次数后若依然失败,则表明消费者在正常情况下无法正确地消费该消息,此时消息队列MQ不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中,这种正常情况下无法被消费的消息称为死信消息(Dead-Letter Message),存储死信消息的特殊队列称为死信队列(Dead-Letter Queue)。
注意事项:
Kafka不支持重试机制也就不支持消息重试,也不支持死信队列,因此使用kafka做消息队列时,如果遇到了消息在业务处理时出现异常的场景时,需要额外实现消息重试的功能。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?