Kafka 实现延迟队列、死信队列、重试队列
更多内容,访问 IT-BLOG
Kafka中实现延迟队列
在发送延时消息的时候并不是先投递到要发送的真实主题(real_topic)中,而是先投递到一些 Kafka 内部的主题(delay_topic)中,这些内部主题对用户不可见,然后通过一个自定义的服务拉取这些内部主题中的消息,并将满足条件的消息再投递到要发送的真实的主题中,消费者所订阅的还是真实的主题。
如果采用这种方案,那么一般是按照不同的延时等级来划分的,比如设定5s、10s、30s、1min、2min、5min、10min、20min、30min、45min、1hour、2hour这些按延时时间递增的延时等级,延时的消息按照延时时间投递到不同等级的主题中,投递到同一主题中的消息的延时时间会被强转为与此主题延时等级一致的延时时间,这样延时误差控制在两个延时等级的时间差范围之内(比如延时时间为17s的消息投递到30s的延时主题中,之后按照延时时间为30s进行计算,延时误差为13s)。虽然有一定的延时误差,但是误差可控,并且这样只需增加少许的主题就能实现延时队列的功能。
发送到内部主题(delaytopic)中的消息会被一个独立的 DelayService 进程消费,这个 DelayService 进程和 Kafka broker 进程以一对一的配比进行同机部署(参考下图),以保证服务的可用性。
针对不同延时级别的主题,在 DelayService 的内部都会有单独的线程来进行消息的拉取,以及单独的 DelayQueue(这里用的是 JUC 中 DelayQueue)进行消息的暂存。与此同时,在 DelayService 内部还会有专门的消息发送线程来获取 DelayQueue 的消息并转发到真实的主题中。从消费、暂存再到转发,线程之间都是一一对应的关系。如下图所示,DelayService 的设计应当尽量保持简单,避免锁机制产生的隐患。
为了保障内部 DelayQueue 不会因为未处理的消息过多而导致内存的占用过大,DelayService 会对主题中的每个分区进行计数,当达到一定的阈值之后,就会暂停拉取该分区中的消息。
因为一个主题中一般不止一个分区,分区之间的消息并不会按照投递时间进行排序,DelayQueue的作用是将消息按照再次投递时间进行有序排序,这样下游的消息发送线程就能够按照先后顺序获取最先满足投递条件的消息。
Kafka中实现死信队列和重试队列
死信可以看作消费者不能处理收到的消息,也可以看作消费者不想处理收到的消息,还可以看作不符合处理要求的消息。比如消息内包含的消息内容无法被消费者解析,为了确保消息的可靠性而不被随意丢弃,故将其投递到死信队列中,这里的死信就可以看作消费者不能处理的消息。再比如超过既定的重试次数之后将消息投入死信队列,这里就可以将死信看作不符合处理要求的消息。
重试队列其实可以看作一种回退队列,具体指消费端消费消息失败时,为了防止消息无故丢失而重新将消息回滚到 broker 中。与回退队列不同的是,重试队列一般分成多个重试等级,每个重试等级一般也会设置重新投递延时,重试次数越多投递延时就越大。
理解了他们的概念之后我们就可以为每个主题设置重试队列,消息第一次消费失败入重试队列 Q1,Q1 的重新投递延时为5s,5s过后重新投递该消息;如果消息再次消费失败则入重试队列 Q2,Q2 的重新投递延时为10s,10s过后再次投递该消息。
然后再设置一个主题作为死信队列,重试越多次重新投递的时间就越久,并且需要设置一个上限,超过投递次数就进入死信队列。重试队列与延时队列有相同的地方,都需要设置延时级别。
Kafka 实现延迟队列、死信队列、重试队列的更多相关文章
- Kafka 延时队列&重试队列
一.延时队列 1. 简介 TimingWheel是kafka时间轮的实现,内部包含了⼀个TimerTaskList数组,每个数组包含了⼀些链表组成的TimerTaskEntry事件,每个TimerTa ...
- Spring Boot 实现 RabbitMQ 延迟消费和延迟重试队列
本文主要摘录自:详细介绍Spring Boot + RabbitMQ实现延迟队列 并增加了自己的一些理解,记录下来,以便日后查阅. 项目源码: spring-boot-rabbitmq-delay-q ...
- RocketMQ之八:重试队列,死信队列,消息轨迹
问题思考 死信队列的应用场景? 死信队列中的数据是如何产生的? 如何查看死信队列中的数据? 死信队列的读写权限? 死信队列如何消费? 重试队列和死信队列的配置 消息轨迹 1.应用场景 一般应用在当正常 ...
- RabbitMQ 发布订阅-实现延时重试队列(参考)
RabbitMQ消息处理失败,我们会让失败消息进入重试队列等待执行,因为在重试队列距离真正执行还需要定义的时间间隔,因此,我们可以将重试队列设置成延时处理.今天参考网上其他人的实现,简单梳理下消息延时 ...
- RabbitMQ发布订阅实战-实现延时重试队列
RabbitMQ是一款使用Erlang开发的开源消息队列.本文假设读者对RabbitMQ是什么已经有了基本的了解,如果你还不知道它是什么以及可以用来做什么,建议先从官网的 RabbitMQ Tutor ...
- 【java多线程】队列系统之说说队列Queue
转载:http://benjaminwhx.com/2018/05/05/%E8%AF%B4%E8%AF%B4%E9%98%9F%E5%88%97Queue/ 1.简介 Queue(队列):一种特殊的 ...
- java队列Queue及阻塞队列
java队列 接口Queue类在java.util包,定义了以下6个方法 详细查看官方文档https://docs.oracle.com/javase/7/docs/api/java/util/Que ...
- 关于TCP 半连接队列和全连接队列
关于TCP 半连接队列和全连接队列 http://jm.taobao.org/2017/05/25/525-1/ 发表于 2017-05-25 | 作者 蛰剑 | 分类于 网络 ...
- BlockingQueue 阻塞队列(生产/消费者队列)
1:BlockingQueue的继承关系 java.util.concurrent 包里的 BlockingQueue是一个接口, 继承Queue接口,Queue接口继承 Collection Blo ...
- Python_Day_05 计数器(counter),有序字典(OrderDict),默认字典(defaultdict),可命名元祖(namedtuple),双向队列(deque),单项队列(deuqe.Queue)
Counter(计数器) 是一个字典的子类,存储形式同样为字典,其中存储的键为字典的元素,值为元素出现的次数,在使用之前我们需要先导入文件 import collections 初始化一个计数器 im ...
随机推荐
- 射频识别技术(RFID)
概述: 无线射频识别即射频识别技术(Radio Frequency Identification,RFID),是自动识别技术的一种,通过无线射频方式进行非接触双向数据通信,利用无线射频方式对记录媒体( ...
- java中BIO、NIO、AIO区别
ava中的IO主要源自于网络和本地文件 IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启 ...
- Spring入门之IoC 的概念和作用(02)
2.1 程序的耦合和解耦 2.1.1 程序的耦合耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量.耦合的强弱取决于模块间接口的复杂性.调用模块的方式以及通过界面传送数据的多少.模块间的 ...
- once函数
function once(fn){ let down = false; return function(){ if(!down){ down = true; return fn.apply(this ...
- pnn模型 待整理
https://blog.csdn.net/qq_18293213/article/details/90262378?spm=1001.2101.3001.6650.5&utm_medium= ...
- uniapp 模拟器的使用
uniapp 模拟器的使用 下载夜深模拟器 uniapp - 工具-设置 adb路径 模拟器路径 模拟器端口号 :26944
- 【Android HttpClient引入】感慨下自己看的Android教程有点老了
教程看到使用HttpClient,发现没有继承该类. 原因是API23即在Android 6.0(API 23) 后,Google已经移除了Apache HttpClient 相关类,推荐使用Http ...
- 库已安装但找不到ttkbootstrap库
cmd里装,弹提示Requirement already satisfied pip install --target=F:\Python37\lib ttkbootstrap https://blo ...
- layui.dtree的学习,自定义扩展toolbar按钮(toolbarExt)
学习layui.dtree请前往 http://www.wisdomelon.com/DTreeHelper/ 记录一下dtree的自定义扩展toolbar按钮(toolbarExt) html代码: ...
- WCF使用post 提交
[OperationContract] [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFor ...