当前位置:网站首页>延时消息常见实现方案
延时消息常见实现方案
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
边栏推荐
- Detectron2 using custom datasets
- ERP function_ Financial management_ The difference between red and blue words in invoices
- Chrome 94 introduces the controversial idle detection API, which apple and Mozilla oppose
- IIS cannot load * woff,*. woff2,*. Solution of SVG file
- Problem brushing plan -- dynamic programming (IV)
- Rust更适合经验较少的程序员?
- matplotlib. Pyplot partition drawing
- Echerts add pie chart random color
- Presto on spark supports 3.1.3 records
- Question brushing plan - depth first search DFS (I)
猜你喜欢

Cancel the default open project setting of idea

阿里又一个“逆天”容器框架!这本Kubernetes进阶手册简直太全了

C language programming based on loop structure (PTA)

在线Excel转CSV工具

Yolov5 NMS source code understanding

Sqlserver edits data in the query interface (similar to Oracle's edit and ROWID)

Idea import a project

ROS learning notes - tutorial on the use of ROS

Is rust more suitable for less experienced programmers?
![[leetcode refers to offer 47. Maximum value of gift (medium)]](/img/b4/34b3c74516e3b1ba93b7d84916dadc.png)
[leetcode refers to offer 47. Maximum value of gift (medium)]
随机推荐
[leetcode refers to the two numbers of offer 57. And S (simple)]
Opencv application -- jigsaw puzzle
Plato farm is one of the four largest online IEOS in metauniverse, and the transaction on the chain is quite high
Norm normalization in tensorflow and pytorch of records
[leetcode refers to offer 21. Adjust the array order so that odd numbers precede even numbers (simple)]
Thread safe sigleton (singleton mode)
airbase 初步分析
Problem brushing plan -- dynamic programming (IV)
Solve importerror: cannot import name 'imread' from 'SciPy misc‘
Use 3080ti to run tensorflow GPU = 1 X version of the source code
管道和xargs
Centralized record of experimental problems
Oracle ora-01033: Oracle initialization or shutdown in progressprocess solution
2022-04-24日報:在生物科學領域應用深度學習的當前進展和開放挑戰
DeNO 1.13.2 release
C, print the source program of beautiful bell triangle
Thinkphp5 + data large screen display effect
Daily operation and maintenance knowledge -- 1
Xiaomi mobile phone has abandoned the "Mi" brand all over the world and switched to the full name brand of "Xiaomi"
DW basic tutorial (I)