使用场景
工作中大家往往会遇到类似的场景:
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!