Redis 实现安全队列

Redis的列表数据结构可以让我们方便的实现消息队列

 

例如用 LPUSH(BLPUSH)把消息入队,用 RPOP(BRPOP)获取消息

 

绝大部分的情况下,这些操作都是没问题的,但并不能保证绝对安全

 

当 LPOP 返回一个元素给客户端的时候,会从 list 中把该元素移除,这意味着该元素就只存在于客户端的上下文中,如果客户端在处理这个返回元素的过程崩溃了,那么这个元素就永远丢失了

 

如何解决?

 

redis 有一个 RPOPLPUSH (或者其阻塞版本的 BRPOPLPUSH)命令

 

命令格式

 

RPOPLPUSH source destination 

 

原子性地返回并移除 source 列表的最后一个元素, 并把该元素放入 destination 列表的头部

 

用这个命令可以保证队列的安全问题:

 

使用 RPOPLPUSH 获取消息时,RPOPLPUSH 会把消息返给客户端,同时把该消息放入一个备份消息列表,并且这个过程是原子的,可以保证消息的安全,当客户端成功的处理了消息后,就可以把此消息从备份列表中移除了

 

命令的阻塞与非阻塞区别

 

redis的命令中,很多都提供了阻塞与非阻塞两个方式

 

例如 LPUSH 为非阻塞,BLPUSH 为阻塞方式

 

他们的区别是什么?

 

唯一的区别是当列表中没有元素时,BRPOP命令会一直阻塞住连接,直到有新元素加入,而RPOP会直接返回nil

 

实际应用的区别

 

需要从队列获取任务

 

如果用非阻塞的方式,代码会是这样

 

# 无限循环读取任务队列中的内容 

loop 

$task = RPOR queue 

if $task 

# 如果有任务则执行 

execute($task) 

else 

# 如果没有就等待1秒

wait 1 second 

 

当队列中没有任务时,每秒都会调用一次RPOP命令查看是否有新任务,可能会白白浪费很多系统资源,如果在有新任务加入队列时就通知消费者就好了,这个需求就可以使用阻塞式命令来实现

 

loop 

# 如果队列中没有任务,BRPOP命令会一直阻塞

# 0 表示一直等待,永不过期 

$task = BRPOP queue, 0 

# 有返回值就继续执行 

execute($task[1])

 

 

https://www.cnblogs.com/wangdaijun/p/6497403.html

posted @ 2018-12-05 20:39  牧之丨  阅读(3440)  评论(0编辑  收藏  举报