用Redis来搞定那些延迟任务,感觉挺方便的,省事又高效
- 问答
- 2026-01-10 00:00:54
- 5
最近在琢磨怎么处理那些“过一会儿再执行”的任务,比如订单下单后半小时没支付要自动关闭,或者用户注册后三天发个提醒消息,以前老用数据库轮询,隔几分钟就去扫一遍表,看看有没有到点的任务,感觉特别笨重,对数据库压力也大,还不实时,后来听人说用Redis就能很优雅地搞定这事,试了试,感觉确实方便,省事又高效。
这个方法的核心,就是用到了Redis的一个叫有序集合(ZSet)的数据结构,这个有序集合挺有意思,它跟普通的集合一样,里面的成员都是唯一的,但每个成员都会关联一个分数(score),Redis会根据这个分数的大小来给成员排序,分数小的排在前面,分数大的排在后面。
那我们怎么用它来做延迟任务呢?思路特别直接:把任务的执行时间戳当做分数,把任务的内容当做成员,扔到这个有序集合里就行了。 现在时间是下午2点,我有一个任务需要在一小时后,也就是下午3点执行,那我就把这个任务的具体信息(比如订单号123)序列化成一个字符串作为成员,然后把下午3点的时间戳(比如1720000000)作为它的分数,存到有序集合里。

我们需要一个后台的守护进程,或者叫工作线程,这个线程的任务很简单,就是不停地去检查这个有序集合,它怎么检查呢?它利用有序集合排序的特性,每次都只查询分数最小(也就是最早要执行)的那些任务,具体操作是,查询当前时间戳之前(分数小于等于当前时间戳)的所有成员,因为当前时间在不停地流逝,所以之前设定的未来执行时间,总会变成“当前时间”或者“过去时间”。
一旦工作线程通过查询,拿到了这些已经到点(甚至稍微超了一点时间)的任务成员,它就可以把这些任务从有序集合里取出来,然后逐个执行任务对应的业务逻辑,比如关闭订单、发送消息等等,执行完了,就把这个任务成员从有序集合里移除,表示处理完毕,就这样,工作线程不断地、循环地执行这个“检查-取出-执行”的过程。

这种方案好处特别明显。效率非常高,因为Redis本身就是在内存里操作,速度极快,查询有序集合里分数最小的成员是非常高效的操作,不像数据库轮询需要全表扫描,即使任务量很大,对性能的影响也相对较小。它比较实时和精确,工作线程可以设置成很短的时间间隔(比如每秒甚至更短)去检查,任务一旦到点,很快就能被处理,延迟很低。它利用了Redis的持久化机制,就算Redis服务器重启了,只要配置了持久化,这些任务数据也不会丢,重启后可以继续处理。
世上没有完美的方案,这个办法也有需要注意的地方,它依赖于一个独立的工作线程/进程不能挂掉,否则就没人处理任务了,通常我们会用一些成熟的队列框架,它们内部已经帮我们实现了这个模式,并且保证了高可用性,但原理上,就是利用Redis有序集合的这个特性。
对于大多数常见的延迟任务场景,用Redis有序集合来实现,确实是一种思路清晰、实现简单、并且性能出色的选择,说它省事又高效,一点也不为过。
本文由召安青于2026-01-10发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/77733.html
