首先找到第一个切入口,redis的列表类型有两个命令LPUSH和RPOP,LPUSH命令可以让元素从左侧进入队列,RPOP命令可以让元素从右侧弹出。这样两个命令配合使用就形成了左边进,右边出的形式,间接实现了队列的功能。生产者通过LPUSH命令添加任务到某个键中,消费者通过RPOP命令不断从该键中取出任务。

这时候问题来了,消费者怎么知道啥时有任务?消费者只能不断循环的读取键对应的队列,如果有任务就消费,没任务就等待一段时间然后再尝试获取任务消费,如此循环。但是如果其实长时间都没有任务进队列,这样的循环就是无用的,浪费资源。

能不能没有任务就阻塞,有任务才执行,BRPOP命令可以做到,当任务队列中没有新任务产生时,BRPOP命令会一直阻塞,不会执行。所以把RPOP命令改成BRPOP命令就可以避免做无谓的循环,同时一旦队列中有任务生成,消费者会像收到了通知一样,此时就可以开始取出任务了。

BRPOP的基本语法

BLPOP LIST1 LIST2 .. LISTN TIMEOUT 

第一个是键名,第二个是超时时间,单位是秒,如果列表为空或者超过了超时时间还没获取到新元素,就返回一个nil,否则返回一个含有两个元素的列表,第一个元素是被弹出元素所属的key,第二个元素是被弹出元素的值。

超时时间为"0",表示不限制等待的时间。

使用LPUSH和BRPOP实现消息队列的操作示例

先开启两个redis-cli实例,端口都为6380,一个作为消费者,一个作为生产者,如下:

yii redis 队列 redis实现队列_yii redis 队列

接下来消费者端输入brpop命令,等待新任务的生成,可以发现没有任何结果返回,是阻塞状态,如下:

yii redis 队列 redis实现队列_任务队列_02

然后生产者端输入lpush命令,生产一个任务插入队列中,如下:

yii redis 队列 redis实现队列_任务队列_03


会发现本来阻塞的消费端不再阻塞了,返回了被插入队列的新任务的键名和元素值。

yii redis 队列 redis实现队列_阻塞状态_04

这样就简单的了解到Redis是如何实现任务队列功能的。