redis學(xué)習(xí):延遲隊(duì)列 異步消息隊(duì)列
redis延遲隊(duì)列使用zset有序列表來(lái)實(shí)現(xiàn) 對(duì)于如加鎖失敗的線(xiàn)程 如果一直輪詢(xún)會(huì)消耗資源 但如果使用sleep那么遇到死鎖時(shí)就會(huì)徹底癱瘓 所以會(huì)使用延遲隊(duì)列。
當(dāng)獲取鎖失敗 會(huì)把消息序列序列化為字符串作為zset的value 把時(shí)間戳作為score (如time()+5 )多個(gè)線(xiàn)程對(duì)延遲隊(duì)列進(jìn)行輪詢(xún):lua腳本(網(wǎng)絡(luò)往返從兩次變?yōu)橐淮?并且多線(xiàn)程情況下因?yàn)閘ua原子性不會(huì)出現(xiàn)多個(gè)線(xiàn)程查詢(xún)但只有一個(gè)線(xiàn)程能執(zhí)行的現(xiàn)象) 每次zrangebyscore取出范圍為0到當(dāng)前時(shí)間戳的第一個(gè)value 然后zrem刪除(搶到了) 之后處理業(yè)務(wù)邏輯。
消息隊(duì)列:可以使用redis 的list作為消息隊(duì)列 生產(chǎn)者使用lpush/rpush 消費(fèi)者使用blpop/brpop b是blocking 就是阻塞讀 在消息隊(duì)列為空的時(shí)候 會(huì)進(jìn)入休眠狀態(tài) 當(dāng)有任務(wù)會(huì)立即喚醒
但redis作為消息隊(duì)列有一定的缺點(diǎn)1.redis數(shù)據(jù)在內(nèi)存中 沒(méi)有持久化時(shí)宕機(jī)數(shù)據(jù)即丟失 即使開(kāi)啟aof每秒刷盤(pán) 但還是可能會(huì)丟失一秒的數(shù)據(jù) 如果開(kāi)啟appendfsync always 那么又大大影響性能 無(wú)法支持高并發(fā)任務(wù)。 2.消息確認(rèn)機(jī)制不足 不同于mq的ack/nack的消息確認(rèn)機(jī)制 redis作消息隊(duì)列本身沒(méi)有確認(rèn)機(jī)制 可能會(huì)導(dǎo)致重復(fù)消費(fèi)或者消費(fèi)失敗后任務(wù)丟失 3.主從同步延時(shí) redis主從異步復(fù)制 在故障切換時(shí)可能會(huì)丟失數(shù)據(jù) 如果redis主節(jié)點(diǎn)在寫(xiě)入或修改后 還沒(méi)來(lái)得及同步到從節(jié)點(diǎn)就宕機(jī) 那么切換從節(jié)點(diǎn)后可能會(huì)丟失關(guān)鍵據(jù)
無(wú)法做到高一致性 4. 可能帶來(lái)性能瓶頸 阻塞讀需要?jiǎng)?chuàng)建tcp連接去監(jiān)聽(tīng)隊(duì)列 在高并發(fā)的情況下 大量tcp連接會(huì)占用大量資源 同時(shí)這些連接的建立 斷開(kāi)會(huì)帶來(lái)cpu壓力 如果brpop/blpop還有超時(shí)管理機(jī)制(超時(shí)將阻塞的客戶(hù)端直接移除) 在高并發(fā)場(chǎng)景下會(huì)帶來(lái)大量cpu壓力( redis使用無(wú)序雙向鏈表來(lái)存儲(chǔ)時(shí)間事件 每次事件循環(huán)迭代,遍歷時(shí)間事件鏈表,檢查是否有事件到期 這會(huì)帶來(lái)cpu消耗)