關於非同步消息,大家都知道,如下: 這些用起來都是比較複雜的,RabbitMQ先要創建Exchange,在創建Queue,還要將Queue和Exchange通過某種規則綁定起來。發消息之前要指定routing-Key,還要控制頭部信息。 即使你只需要一組消息者。那麼你就要經歷上面繁瑣的過程。 但是Re ...
關於非同步消息,大家都知道,如下:
這些用起來都是比較複雜的,RabbitMQ先要創建Exchange,在創建Queue,還要將Queue和Exchange通過某種規則綁定起來。發消息之前要指定routing-Key,還要控制頭部信息。
即使你只需要一組消息者。那麼你就要經歷上面繁瑣的過程。
但是Redis對於那些輕量級和只有一組消息者的消息隊列;
Redis的list數據結構常用來作為非同步消息隊列來使用。使用rpush/lpush操作入隊列,用lpop/rpop來出隊列。我們都知道list是一個鏈表,所以操作方式如下
當然我們會遇到一些問題,比如隊列空了會怎麼樣?客戶端是通過隊列的 pop 操作來獲取消息,然後進行處理。處理完了再接著獲取消息,再進行處理。如此迴圈往複,這便是作為隊列消費者的客戶端的生命周期。 可是如果隊列空了,客戶端就會陷入 pop 的死迴圈,不停地 pop,沒有數據,接著再 pop,又沒有數據。這就是浪費生命的空輪詢。空輪詢不但拉高了客戶端的 CPU,redis 的 QPS 也會被拉高,如果這樣空輪詢的客戶端有幾十來個,Redis 的慢查詢可能會顯著增多。 通常我們使用 sleep 來解決這個問題,讓線程睡一會,睡個 1s 鐘就可以了。不但客戶端的 CPU 能降下來,Redis 的 QPS 也降下來了。(摘自Redis深度歷險)
睡眠會導致消息的延遲增大·,多個消費者情況下,延遲會有所下降,因為每個消費者都是的睡眠時間是岔開來的。通過阻塞讀:blocking,也就是這兩個命令:blpop,brpop。
當然還有會空閑連接自動斷開,顧名思義,一直阻塞,Redis客戶端就成了閑置的,時間長了,伺服器會斷開連接,減少閑置資源,這時候就會拋出異常,所以編寫消費者的時候,註意捕獲異常,重試。
延時隊列:
這種方式比較適合非同步消息處理,將當前衝突的請求扔到另一個隊列延後處理以避開衝突
我們將消息序列化成一個字元串作為 zset 的 value,這個消息的到期處理時間作為 score,然後用多個線程輪詢 zset 獲取到期的任務進行處理,多個線程是為了保障可用性,萬一掛了一個線程還有其它線程可以繼續處理。因為有多個線程,所以需要考慮併發爭搶任務,確保任務不能被多次執行。