当前位置:首页 > 问答 > 正文

Redis队列到底是啥类型,简单说说它的那些事儿和用法探讨

Redis队列,说白了,就是利用Redis这个速度快、内存存的数据库,来模拟一个排队办事的机制,你可以把它想象成现实生活中任何需要排队的场景,比如银行取号、奶茶店点单,核心思想就是“先进先出”:先来的任务,就先被处理。

那Redis本身并没有一个直接叫“Queue”的数据类型,我们通常是用它的“List”这个基本类型来模拟实现队列的功能,List就是一个简单的字符串列表,你可以从左边放进去,也可以从右边放进去,同样地,也能从左边或右边取出来。

(参考来源:Redis官方文档对List数据类型的定义)

基于这种灵活的进出方式,就演变成了两种最常用、最经典的队列模式:

第一种是“普通队列”,也叫“生产者-消费者”模式。 这个名字听起来有点唬人,但其实很简单。

  • 生产者:就是那些不断产生任务的角色,你的网站用户点击了“发布文章”按钮,这个“发布文章”的任务就是一个待办事项,生产者会执行 LPUSH 命令,把这个任务描述(比如文章ID)从队列的左边推进去。
  • 消费者:就是后台默默干活的工作进程(worker),它们会不停地执行 RPOP 命令,从队列的右边把任务取出来,然后开始处理,比如生成文章静态页、发送通知等。

这样一来,就形成了一个完美的流水线:左边进,右边出,保证最先加入的任务被最优先处理,这就像奶茶店只有一个点单员,顾客排成一队,先来的先点单。

第二种是“阻塞队列”,这是对普通队列的一个非常实用的升级。 你想啊,如果消费者去队列里取任务时,发现队列是空的,它会怎么办?在普通队列里,它取个空,然后就结束了,接着它可能会隔几秒再来问一次,这叫做“轮询”,很浪费资源。

阻塞队列就聪明多了,消费者使用 BRPOP 命令(B代表Blocking,阻塞),当它去队列取任务时,如果队列是空的,它不会立刻离开,而是“阻塞”在那里,相当于竖起耳朵专心等待,一旦生产者放进来了一个新任务,消费者会立刻被唤醒,拿到这个任务去处理,这样既实时又高效,避免了无用的空转。

(参考来源:Redis官方文档对BRPOP命令的说明)

除了这两种核心模式,围绕Redis队列还有一些非常有意思的“事儿”和用法探讨:

优先级队列怎么搞? Redis的List本身是公平的,严格先进先出,但如果有个VIP客户,他的任务需要插队怎么办?一个常见的讨沦和做法是使用多个队列,你设置一个“普通任务队列”和一个“VIP任务队列”,消费者在取任务的时候,不是只盯着一个队列,而是先用 BRPOP 命令去检查“VIP队列”,如果等了一会儿(比如1秒)没任务,它再去检查“普通队列”,这样就在一定程度上实现了优先级。

任务失败了怎么办?—— “可靠队列”的探讨 这是队列应用中非常关键的问题,想象一下,消费者从队列里取走了一个任务,但还没处理完,自己突然崩溃了,这个任务就永远丢失了,因为已经被移出队列了。 为了解决这个问题,人们想出了“可靠队列”的模式,这通常不单靠List实现,还会用到Redis的“Set”集合,基本思路是:消费者不是用 RPOP,而是用 RPOPLPUSH 命令,这个命令很巧妙,它原子性地把任务从主队列移动到另一个“进行中队列”,等消费者处理完任务后,再从这个“进行中队列”里把任务删除,这样,如果消费者崩溃了,我们就可以定时去扫描“进行中队列”,把那些停留时间过长的任务重新放回主队列,让其他消费者重试。

延迟队列的实现思路 有些任务我们不希望它马上被处理,订单15分钟后未支付则自动关闭”,这种延迟队列Redis没有直接支持,但可以通过 (参考来源:Redis Antirez博客关于延迟队列的设想) 的Sorted Set(有序集合)来实现,把任务作为成员,把希望执行的时间戳作为分数(score)存进去,然后启动一个额外的进程,定期去这个有序集合里扫描分数小于当前时间戳的任务(也就是到点了的任务),把它们捞出来放进普通的List队列里,让消费者去处理。

发布/订阅(Pub/Sub)能当队列用吗? Redis还有一个Pub/Sub功能,它像是广播,一个消息发出去,所有订阅的消费者都能收到,这和我们上面说的队列有本质区别:队列是一个任务只能被一个消费者处理;而Pub/Sub是一条消息被多个消费者同时处理,如果你需要做的是通知、广播场景(比如直播间聊天),Pub/Sub很合适,但如果你是要做任务分发,确保每个任务只被一个worker处理,那一定要用List实现的队列,而不是Pub/Sub。

Redis队列的核心就是用List类型搭建的一个简单而强大的工具,它通过LPUSH/RPOP实现普通队列,通过BRPOP实现高效的阻塞队列,围绕它,我们可以通过组合其他数据结构和命令,探讨和实现优先级、可靠性、延迟等更复杂的业务需求,使其成为后台系统中处理异步任务、削峰填谷的利器。

Redis队列到底是啥类型,简单说说它的那些事儿和用法探讨