一日一技:隱患——redis-py的blpop可能因爲網絡波動致使收不到信息

一日一技:隱患——redis-py的blpop可能因爲網絡波動致使收不到信息

一日一技:隱患——redis-py的blpop可能因爲網絡波動致使收不到信息

攝影:產品經理
廚師: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詢問緣由,他給個人回覆以下圖所示。隊列

一日一技:隱患——redis-py的blpop可能因爲網絡波動致使收不到信息

意思是說,在使用 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就會馬上把數據彈出來。

經過添加超時時間,解決了數據實時性和網絡鏈接丟失的問題。

相關文章
相關標籤/搜索