天天看點

消息隊列推拉push/pull模式優缺點及使用改進的長輪詢模式的意義

Push方式:

優點:有消息就推給消費者。延遲小,幾乎可以做到實時。等等。。。。

缺點:Server端接收到消息後,主動把消息推送給Client端,實時性高。對于一個提供隊列服務的Server來說,用Push方式主動推送有很多弊端;首先是加大Server端的工作量,進而影響Server的性能,其次Client的處理能力各不相同,Client的狀态不受Server控制,如果Client不能及時處理Server推送過來的消息,會造成各種潛在問題。

鳳梨科技注:意思是1 加大server(broker)工作量,影響性能。2 有的消費者機器配置好處理能力強,有的配置低處理能力低,但是server推相同數量級消息給消費者,就會導緻消費者強的等待,弱的處理效率跟不上,進而導緻崩潰。3server資源相比消費者的資源肯定是更寶貴  4總結下就是用戶端慢消費(設計到io等耗時操作)時會放大缺點。

Pull方式:

優點:對比push優點就是消費者可以根據自己能力拉取消息處理。。。

缺點:Client端循環地從Server端拉取消息,主動權在Client手裡,自己拉取到一定量消息後,處理妥當了再接着取。Pull方式的問題是循環拉取消息的間隔不好設定,間隔太短就處在一個“忙等”的狀态,浪費資源;每個Pull的時間間隔太長,Server端有消息到來有可能沒有被及時處理。

鳳梨科技注:假如處理完消息後,現在空閑,設定多久去server再拉消息?主要問題就是消息處理延遲忙等。server沒消息時,但是消費者因為是定時去pull,導緻空pull。

長輪詢:

CMQ (騰訊)提供了長輪詢的優化方法,用以平衡 Pull/Push 模型各自的缺點。

消費者如果嘗試拉取失敗,不是直接 return,而是把連接配接挂在那裡 wait,服務端如果有新的消息到來,把連接配接拉起,傳回最新消息。原文連結:https://blog.csdn.net/wabiaozia/article/details/102057941

場景:

場景1:Producer 速率大于 Consumer 速率

當 Producer 速率大于 Consumer 速率時,有兩種可能性:一種是 Producer 本身的效率就要比 Consumer 高(例如,Consumer 端處理消息的業務邏輯可能很複雜,或者涉及到磁盤、網絡等 I/O 操作);另一種是 Consumer 出現故障,導緻短時間内無法消費或消費不暢。

Push 方式由于無法得知目前 Consumer 的狀态,是以隻要有資料産生,便會不斷地進行推送,在以上兩種情況下時,可能會導緻 Consumer 的負載進一步加重,甚至是崩潰(例如生産者是 flume 瘋狂抓日志,消費者是 HDFS+hadoop,處理效率跟不上)。除非Consumer 有合适的回報機制能夠讓服務端知道自己的狀況。

而采取 Pull 的方式問題就簡單了許多,由于 Consumer 是主動到服務端拉取資料,此時隻需要降低自己通路頻率即可。舉例:如前端是 flume 等日志收集業務,不斷向 CMQ 生産消息,CMQ 向後端投遞,後端業務如資料分析等業務,效率可能低于生産者。原文

場景2:強調消息的實時性

采用 Push 的方式時,一旦消息到達,服務端即可馬上将其推送給消費端,這種方式的實時性顯然是非常好的;而采用 Pull 方式時,為了不給服務端造成壓力(尤其是當資料量不足時,不停的輪詢顯得毫無意義),需要控制好自己輪詢的間隔時間,但這必然會給實時性帶來一定的影響。

場景3:Pull 的長輪詢

Pull 模式存在的問題:由于主動權在消費方,消費方無法準确地決定何時去拉取最新的消息。如果一次 Pull 取到消息了還可以繼續去 Pull,如果沒有 Pull 取到消息則需要等待一段時間再重新 Pull。

由于等待時間很難判定。您可能有 xx 動态拉取時間調整算法,但問題的本質在于,是否有消息到來不是由消費方決定。也許1分鐘内連續到來1000條消息,接下來的半個小時卻沒有新消息産生,可能您的算法算出下次最有可能到來的時間點是31分鐘之後,或者60分鐘之後,結果下條消息10分鐘後到達。

當然,延遲也有對應的解決方案,業界較成熟的做法是從短時間開始(不會對 CMQ broker 有太大負擔),然後指數級增長等待。例如開始等5ms,然後10ms,然後20ms,然後40ms,以此類推,直到有消息到來,然後再回到5ms。即使這樣,依然存在延遲問題:假設40ms到80ms之間的50ms消息到來,消息就延遲了30ms,對于半個小時來一次的消息,這些開銷就是白白浪費的。

CMQ 提供了長輪詢的優化方法,用以平衡 Pull/Push 模型各自的缺點。基本方式是:消費者如果嘗試拉取失敗,不是直接 return,而是把連接配接挂在那裡 wait,服務端如果有新的消息到來,把連接配接拉起,傳回最新消息。

場景4:部分或全部 Consumer 不線上

在消息系統中,Producer 和 Consumer 是完全解耦的,Producer 發送消息時,并不要求Consumer 一定要線上,對于 Consumer 也是同樣的道理,這也是消息通信差別于 RPC 通信的主要特點;但是對于 Consumer 不線上的情況,卻有很多值得讨論的場景。

首先,在 Consumer 偶然當機或下線時,Producer 的生産是可以不受影響的,Consumer 上線後,可以繼續之前的消費,此時消息資料不會丢失;但是如果 Consumer 長期當機或是由于機器故障無法再次啟動,就會出現問題,即服務端是否需要為 Consumer 保留資料,以及保留多久的資料等等。

采用 Push 方式時,因為無法預知 Consumer 的當機或下線是短暫的還是持久的,如果一直為該 Consumer 保留自當機開始的所有曆史消息,那麼即便其他所有的 Consumer 都已經消費完成,資料也無法清理掉,随着時間的積累,隊列的長度會越來越大,此時無論消息是暫存于記憶體還是持久化到磁盤上(采用 Push 模型的系統,一般都是将消息隊列維護于記憶體中,以保證推送的性能和實時性,這一點會在後邊詳細讨論),都将對 CMQ 服務端造成巨大壓力,甚至可能影響到其他 Consumer 的正常消費,尤其當消息的生産速率非常快時更是如此;但是如果不保留資料,那麼等該 Consumer 再次起來時,則要面對丢失資料的問題。

折中的方案是:CMQ 給資料設定一個逾時時間,當 Consumer 當機時間超過這個門檻值時,則清理資料;但這個時間門檻值也并太容易确定。

在采用 Pull 模型時,情況會有所改善;服務端不再關心 Consumer 的狀态,而是采取“你來了我才服務”的方式,Consumer 是否能夠及時消費資料,服務端不會做任何保證(也有逾時清理時間)。

參考文檔:

1 騰訊消息隊列CMQ: https://cloud.tencent.com/document/product/406/4791

2 RocketMQ原理與實戰解析-阿裡巴巴資料專家楊開元

3 消息隊列設計精要:https://tech.meituan.com/2016/07/01/mq-design.html  美團