当前位置:网站首页>延时消息常见实现方案
延时消息常见实现方案
2022-04-23 21:57:00 【InfoQ】
前言
实现方案
1. 基于外部存储实现的方案

基于 数据库(如MySQL)
CREATE TABLE `delay_msg` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`delivery_time` DATETIME NOT NULL COMMENT '投递时间',
`payloads` blob COMMENT '消息内容',
PRIMARY KEY (`id`),
KEY `time_index` (`delivery_time`)
)
- 实现简单;
- B+Tree索引不适合消息场景的大量写入;
基于 RocksDB

- RocksDB LSM 树很适合消息场景的大量写入;
- 实现方案较重,如果你采用这个方案,需要自己实现 RocksDB 的数据容灾逻辑;
基于 Redis

- Messages Pool 所有的延时消息存放,结构为KV结构,key为消息ID,value为一个具体的message(这里选择Redis Hash结构主要是因为hash结构能存储较大的数据量,数据较多时候会进行渐进式rehash扩容,并且对于HSET和HGET命令来说时间复杂度都是O(1))
- Delayed Queue是16个有序队列(队列支持水平扩展),结构为ZSET,value 为 messages pool中消息ID,score为过期时间**(分为多个队列是为了提高扫描的速度)**
- Worker 代表处理线程,通过定时任务扫描 Delayed Queue 中到期的消息
- Redis ZSET 很适合实现延时队列
- 性能问题,虽然 ZSET 插入是一个 O(logn) 的操作,但是Redis 基于内存操作,并且内部做了很多性能方面的优化。
定时线程检查的缺陷与改进
2. 开源 MQ 中的实现方案
RocketMQ

- Level 数固定,每个 Level 有自己的定时器,开销不大
- 将 Level 相同的消息放入到同一个 Queue 中,保证了同一 Level 消息的顺序性;不同 Level 放到不同的 Queue 中,保证了投递的时间准确性;
- 通过只支持固定的Level,将不同延时消息的排序变成了固定Level Topic 的追加写操作
- Level 配置的修改代价太大,固定 Level 不灵活
- CommitLog 会因为延时消息的存在变得很大
Pulsar

- **内存开销:**维护延时消息索引的队列是放在堆外内存中的,并且这个队列是以订阅组(Kafka中的消费组)为维度的,比如你这个 Topic 有 N 个订阅组,那么如果你这个 Topic 使用了延时消息,就会创建 N 个 队列;并且随着延时消息的增多,时间跨度的增加,每个队列的内存占用也会上升。(是的,在这个方案下,支持任意的延时消息反而有可能让这个缺陷更严重)
- **故障转移之后延时消息索引队列的重建时间开销:**对于跨度时间长的大规模延时消息,重建时间可能会到小时级别。(摘自 Pulsar 官方公众号文章)
- 存储开销 :延时消息的时间跨度会影响到 Pulsar 中已经消费的消息数据的空间回收。打个比方,你的 Topic 如果业务上要求支持一个月跨度的延时消息,然后你发了一个延时一个月的消息,那么你这个 Topic 中底层的存储就会保留整整一个月的消息数据,即使这一个月中99%的正常消息都已经消费了。

QMQ

- 时间轮算法适合延时/定时消息的场景,省去延时消息的排序,插入删除操作都是 O(1) 的时间复杂度;
- 通过多级时间轮设计,支持了超大时间跨度的延时消息;
- 通过延时加载,内存中只会有最近要消费的消息,更久的延时消息会被存储在磁盘中,对内存友好;
- 延时消息单独存储(schedule log),不会影响到正常消息的空间回收;
总结
版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢
https://xie.infoq.cn/article/add4395e1eaf60c3dec4e5f2e
边栏推荐
- Xiaomi mobile phone has abandoned the "Mi" brand all over the world and switched to the full name brand of "Xiaomi"
- What if Jenkins forgot his password
- 阿里云回应用户注册信息泄露事件
- Realrange, reduce, repeat and einops in einops package layers. Rearrange and reduce in torch. Processing methods of high-dimensional data
- Google tries to use rust in Chrome
- Arm architecture assembly instructions, registers and some problems
- 阿里又一个“逆天”容器框架!这本Kubernetes进阶手册简直太全了
- [※ leetcode refers to offer 32 - II. Print binary tree II from top to bottom (simple)]
- ROS学习笔记-----ROS的使用教程
- 使用mbean 自动执行heap dump
猜你喜欢
Question brushing plan - depth first search (II)
[※ leetcode refers to offer 48. The longest substring without repeated characters (medium)]
IIS cannot load * woff,*. woff2,*. Solution of SVG file
2. Finishing huazi Mianjing -- 2
Problem brushing plan -- dynamic programming (IV)
Question brushing plan - depth first search DFS (I)
Ali has another "against the sky" container framework! This kubernetes advanced manual is too complete
Amazon and epic will be settled, and the Microsoft application mall will be opened to third parties
CVPR2022 | 基于知识蒸馏的高效预训练
[leetcode refers to offer 52. The first common node of two linked lists (simple)]
随机推荐
What if Jenkins forgot his password
Sqlserver edits data in the query interface (similar to Oracle's edit and ROWID)
Tensorflow1. X and 2 How does x read those parameters saved in CKPT
Pyuninstaller package exe cannot find the source code when running, function error oserror: could not get source code
C, print the source program of beautiful bell triangle
Database Experiment 8 trigger experiment
Ensuring the quality of living materials and food safety in Shanghai
[leetcode refers to offer 22. The penultimate node in the linked list (simple)]
Opencv application -- jigsaw puzzle
Automatic heap dump using MBean
管道和xargs
[leetcode sword finger offer 28. Symmetric binary tree (simple)]
Use 3080ti to run tensorflow GPU = 1 X version of the source code
flomo软件推荐
JS to get the browser and screen height
Is rust more suitable for less experienced programmers?
Centos7 builds MySQL master-slave replication from scratch (avoid stepping on the pit)
使用mbean 自动执行heap dump
Deep understanding of modern mobile GPU (continuously updating)
2022-04-24日報:在生物科學領域應用深度學習的當前進展和開放挑戰