摘自《Redis入门指南》,李子骅
1 任务队列
Redis中的列表类型可以实现可以实现队列,列表类型有LPUSH和RPOP命令实现队列的概念。如果想要实现任务队列,只需要让生产者将任务使用LPUSH命令加入到某个键中,另一边让消费者不断地使用RPOP命令从该键中取出任务即可。
# 无限循环读取任务队列中的内容
loop
$task = RPOP queue
if $task
#如果队列中有就执行
execute($task)
else
#如果没有则等待1秒以免过于频繁地请求数据
wait 1 second
但是还有一些美中不足的地方,当任务队列中没有任务时消费者每秒都会调用一次RPOP命令查看是否有新任务。如果可以实现一旦有新任务加入任务队列就通知消费者就好了。使用BRPOP可以实现这样的需求。
BRPOP命令和RPOP命令相似,唯一区别就是当列表中没有元素时BRPOP命令会一直阻塞住连接,直到有新元素加入。
loop
#如果任务队列中没有新任务,BRPOP命令会一直堵塞,不会执行execute()
$task = BRPOP queue, 0
#返回值是一个数字,数组第二个值使我们需要的任务。
execute($task[1])
BRPOP命令接收两个参数,第一个是键名,第二个是超时时间,单位是秒。当超过此时间仍然没有获得新元素的话就会返回nil。超时时间是“0”表示不设置超时时间,即如果没有新元素加入队列就会永远阻塞下去。
例子:
打开两个redis-cli:
实例A输入:
redis>BRPOP queue 0
实例B输入:
redis>LPUSH queue task
可以看到实例A返回:
1) "queue"
2) "task"
同时发现queue中的元素已经被取走:
redis>LLEN queue
(integer) 0
2 优先级队列
如果有两种任务同时存在,一种任务应该优先另一种任务处理,我们要如何使用队列呢?
为了实现这一目标,我们需要使用优先级队列,将不同的任务放在不同的任务队列中。
BRPOP命令可以同时接收多个键,其完整的命令格式为BRPOP key [key ...] timeout,如BRPOP queue:1 queue:2 0.
意义是同事检测多个键,如果所有的键都没有元素则阻塞,如果其中有一个键有元素则会从该键中弹出元素。如果多个键都有元素则按照从左到右的顺序取第一个键中的一个元素。借此特性可以区分优先级队列。
例子:
“发布/订阅”模式包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或若干个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。
发布者发送消息的命令是PUBLISH,用法是PUBLISH channel message,如向channel.1说一声“hi”:
redis>PUBLISH channel.1 hi
(integer) 0
这样消息就发出去了。返回值表示接收到这条消息的订阅者数量。发出去的消息不会被持久化,也就是说当客户端订阅channel.1后只能收到后续发布到该频道的消息,之前发送到就收不到了。
订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是 SUBSCRIBE channel [channel ...]。
redis>SUBSCRIBE channel.1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel.1"
3) (integer) 1
执行SUBSCRIBE命令后进入订阅状态,处于此状态下客户端不能使用除SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE这四个属于“发布/订阅”模式之外的命令,否则会报错。
进入订阅模式后客户端可能收到三种类型的回复。每种类型的回复都包含3个值,第一个值是消息的类型,根据消息类型的不同,第二第三个值的含义也不同。消息类型可能的取值有:
(1)Subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个值是当前客户端订阅的频道数。
(2)message。这个类型的回复表示收到的消息。第二个值表示产生消息的频道名称,第三个值是消息内容。
(3)unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态。
可以使用PSUBSCRIBE命令订阅指定的规则:
reids C>PSUBSCRIBE channel.?*
规则channel.?*可以匹配channel.1和channel.10,但不会匹配channel.。
这时在实例B中发布消息
redis B>PUBLISH channel.1 hi!
(integer) 2
C收到的回复是:
1)“pmessage”
2) "channel.?*"
3) "channel.1"
4) "hi!"
第一个值表示这条消息通过PSUBSCRIBE消息订阅频道而收到的,第二个值表示订阅时使用的通配符,第三个值表示实际收到消息的频道命令,第四个值则是消息内容。