TMQ:定时消息队列原理与实现
TMQ
TMQ: Timing Message Queue,定时消息队列。
概念
什么是定时消息队列?
存储在队列中的消息,可以按投递时间顺序获取。
用(t,m)表示一个消息,其中t是投递时间,m是消息体,则对于先后推送至队列中的消息(t1,m1),(t1,m2),当按投递时间t1获取时,将先后获取到m1、m2。
应用场景
- 新用户注册,第二天上午9点发放优惠券,则可以在新用户注册时推送一条定时消息,消息投递时间为第二天上午9点,消息体可以是用户ID
- 用户下单,半小时后提醒用户付款,消息投递时间为半小时后,消息体为订单ID
- 发起投票,截止前1小时、半小时分别提醒用户投票,则可以推送一批定时消息,每个消息携带不同的投递时间和用户ID
总的应用场景就是需要定时或延时触发的消息。
设计思路
思路1
消息存储于数据表,表中有投递时间字段,并给该字段加索引。
获取消息时按投递时间查询,并按自增ID顺序获取。
需要额外的状态字段标识消息是否已被读取。
存在的问题
- 当一个投递时间有大量消息时,索引是低效的
思路2
在思路1的基础上,采取分表策略,基于投递时间横向拆分。
解决了索引低效的问题,按自增ID顺序获取即可。
存在的问题
- 表数量不可控
- 表数据量分布不均
思路3
采用思路2的分割思想,消息仍存储于数据表中,将相同投递时间的消息ID存储于同一列表中。
获取消息时,首先从列表中取出消息ID,然后从数据表中查出消息数据。
思路3解决了上述问题,满足需求。
技术选型
- 数据库 MySQL
- 列表 Redis LIST
Redis List有原子化的PUSH/POP操作,且性能很高,这确保能够高效获取消息。