Kafka延时队列方案探讨

[原创]个人理解,请批判接受,有误请指正。转载请注明出处: https://heyfl.gitee.io/design/Kafka-Delay-Queue.html

s

目前在用方案:直接重新丢回队列后面

延迟队列-原方案

实现逻辑

引入延迟消息消费服务,消费延迟消息
每条消息消费时,Sleep3秒(很长),再处理;
处理时判断是否到点,没到点的数据丢回kafka

优点

不引入新依赖(不依赖DB,不依赖其他第三方)

缺点

1. 处理效率慢,并发低
2. 延时时间不精准,颗粒度非常大
3. 浪费Kafka空间,同一数据在Kafka多次存储(其实Kafka底层是一种文件/文档存储,消息的消费只读不删)   

优化方案1: 延迟消息存DB,通过Redis的zset结构支持

延迟队列-DB+Redis方案
### 实现逻辑 #### 1. 发送延时消息: > 延时消息发送到延时队列TopicA ### 2. 消费延时消息: > 延时程序(消费者)消费延迟队列的消息,把延时消息存入DB,再把[发送时间]+[延时消息在DB记录ID]作为zset设到Redis ### 3. 监控&&发送[到时的消息]: > 1. 通过监控程序,监控Redis 发现[到时的任务],发送到真正的消费队列 进行真正的业务处理 > 2. 标识消息为已处理 或 删除(数据量大选立即删除,否则还是选择存几天,方便异常补数据)

缺点

  1. 强依赖Redis,数据存在: Redis出现异常会或会出现1s的数据丢失,补偿方案实现麻烦、效果不好(1.人工发现,人工通过日志/DB补偿 2.程序定时比对补偿)
  2. 会出现数据倾斜: 单个队列数据量大时,Redis会出现数据倾斜,导致Redis单点数据量大,更容易出现热点数据&单点容量不足的问题 (这一点可以通过key,优化解决,就是每次存的时候麻烦点)

优化方案2: 分级队列+sleep方案 [分级延迟后面(5分钟 10分钟 30分钟…)]

分级队列方案-sleep方案

实现逻辑

1. 根据需求,丢到对应的延迟主题中,如5分钟延迟主题
2. 五分钟主题按顺序消费前面的一条or多条数据时,判断该消息是否到达延迟时间,没到时间就sleep对应的时间;
到时间就消费掉&&发到业务主题中
(PS.得带上当前延迟主题分级DelayLevel,延迟次数tryCount,以方便业务主题消费失败时根据需求进行增量延迟操作)
3. 业务主题消费者消费时,根据[重试次数tryCount]&[延迟主题分级DelayLevel]以及消费情况
决定正常消费掉消息 还是 丢到之前或别的分级延迟主题中;

缺点

1. Sleep太久,kafka会认为该消费者不可用,然后把消息给到别的消费者。。。

优化方案3: 分级队列方案+原生wait方案

延迟队列-分级队列方案-原生wait方案

缺点

1. 文档难找。。。没找到wait接口怎么用。。。只找到特性
作者

神奇宝贝大师

发布于

2019-12-31

更新于

2021-10-31

许可协议

评论