基于Redis延迟队列的实现代码

使用场景

工作中大家往往会遇到类似的场景:

1.对于红包场景,账户 a 对账户 b 发出红包通常在 1 天后会自动归还到原账户。

2.对于实时支付场景,如果账户 a 对商户 s 付款 100 元,5秒后没有收到支付方回调将自动取消订单。

解决方案分析

方案一:

采用通过定时任务采用数据库/非关系型数据库轮询方案。

优点:

1. 实现简单,对于项目前期这样是最容易的解决方案。

缺点:

1. db 有效使用率低,需要将一部分的数据库的qps分配给 job 的无效轮询。

2. 服务资源浪费,因为轮询需要对所有的数据做一次 scan 扫描 job 服务的资源开销很大。

方案二:

采用延迟队列:

优点:

1. 服务的资源使用率较高,能够精确的实现超时任务的执行。

2. 减少 db 的查询次数,能够降低数据库的压力

缺点:

1. 对于延迟队列来说本身设计比较复杂,目前没有通用的比较好过的方案。

基于 redis 的延迟队列实现

基于以上的分析,我决定通过 redis 来实现分布式队列。

设计思路:

1. 第一步将需要发放的消息发送到延迟队列中。

2. 延迟队列将数据存入 redis 的 zset 有序集合中score 为当前时间戳,member 存入需要发送的数据。

3. 添加一个 schedule 来进行对 redis 有序队列的轮询。

4. 如果到达达到消息的执行时间,那么就进行业务的执行。

5. 如果没有达到消息的执行是将,那么消息等待下轮执行。

实现步骤:

由于本处篇幅有限,所以只列举部分代码,完整的代码可以在本文最后访问 github 获取。由于本人阅历/水平有限,如有建议/或更正欢迎留言或提问。先在此谢谢大家驻足阅读 。

需要注意的问题:

单个 redis 命令的执行是原子性的,但 redis 没有在事务上增加任何维持原子性的机制,所以 redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

我们可以通过 redis 的 eval 命令来执行 lua 脚本来保证原子性实现redis的事务。

实现步骤如下:

1. 延迟队列接口

2. 延迟队列消息

3. 延迟队列实现

4. 定时任务

github 地址

参考地址

1.

到此这篇关于基于redis延迟队列的实现代码的文章就介绍到这了,更多相关redis 延迟队列内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐