攝影:產品經理
廚師:kingname
咱們在使用Redis作消息隊列的時候,經常使用列表這個數據結構,並寫出以下的代碼:redis
import redis import time client = redis.Redis() while True: data = client.lpop('key') if not data: time.sleep(5 * 60) continue parse(data)
這個意思是說,若是Redis的名爲 key的列表裏面有數據,那麼就不停取出來,並把取出的數據傳入 parse函數進行處理。若是列表裏面沒有數據,那麼就等待5分鐘再次檢查。markdown
這種方式,若是列表始終爲空,那麼將會每5分鐘檢查一次。網絡
但使用這種方式有一個問題,例如剛剛檢查完列表發現是空的,程序開始等待5分鐘。可是檢查完成的1秒之後,新信息抵達列表。此時信息沒法被馬上消費,必須要等滿5分鐘才行。數據結構
爲了解決實時性的問題,使用了列表的阻塞式彈出命令 blpop,因而代碼變爲:ide
import redis client = redis.Redis() while True: data = client.blpop('key')
parse(data[1])
若是列表裏面沒有數據,程序就會卡在 data=client.blpop('key')這一行,直到列表裏面有了新的數據,再馬上彈出送進後面的邏輯。函數
這種方法在測試的時候完美運行,因而就放到了生成環境使用。測試
一個週末過去了,週一上班時,同事反饋寫到Redis裏面的信息不能被正常消費了。code
可是我發現程序正常運行,並無出現任何異常。blog
因而我找 redis-py的做者 AndyMcCurdy詢問緣由,他給個人回覆以下圖所示。隊列
意思是說,在使用 blpop的時候,若是中途由於網絡波動或者某些其餘緣由致使鏈接池失效,那麼就永遠接收不到信息了,雖然 redis-py有鏈接狀態檢查的功能,可是因爲程序是阻塞的, redis-py的鏈接狀態檢查功能不能正常使用。
爲了解決這個問題,就須要 blpop的超時功能。讓 blpop每幾分鐘就斷開,檢查一下網絡,再從新連上。
因而代碼變爲:
import redis client = redis.Redis() while True: data = client.blpop('key', timeout=5 * 60) if not data: continue parse(data[1])
設置超時時間爲5分鐘,若是5分鐘內列表沒有收到信息(不管是真的列表一直沒有數據,仍是鏈接池斷開了),都會返回 None,此時只須要從新執行 blpop,在執行的瞬間會檢查鏈接的狀態,若是鏈接池有問題,那麼它會從新鏈接。
若是5分鐘內有數據,那麼 blpop就會馬上把數據彈出來。
經過添加超時時間,解決了數據實時性和網絡鏈接丟失的問題。