Redis 實現安全隊列


原創 2015-12-24 杜亦舒 性能與架構 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])


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM