訊息佇列(Message Queue)基本概念

ZYZ_DIDO發表於2016-02-17

背景

  之前做日誌收集模組時,用到flume。另外也有的方案,整合kafaka來提升系統可擴充套件性,其中涉及到訊息佇列當時自己並不清楚為什麼要使用訊息佇列。而在我自己提出的原始日誌採集方案中不適用訊息佇列時,有幾個基本問題:1. 日誌檔案上傳過程,有個基本的生產者-消費者問題;2. 另外系統崩潰時,資料丟失的處理問題。

  今天,幾位同事再次談到訊息佇列這麼個東西,很NB的樣子,我也想弄清楚,OK,搞起。

  訊息佇列(Message Queue,簡稱MQ),從字面意思上看,本質是個佇列,FIFO先入先出,只不過佇列中存放的內容是message而已。其主要用途:不同程式Process/執行緒Thread之間通訊。為什麼會產生訊息佇列?這個問題問的好,我大概查了一下,沒有查到最初產生訊息佇列的背景,但我猜測可能幾個原因:

  • 不同程式(process)之間傳遞訊息時,兩個程式之間耦合程度過高,改動一個程式,引發必須修改另一個程式,為了隔離這兩個程式,在兩程式間抽離出一層(一個模組),所有兩程式之間傳遞的訊息,都必須通過訊息佇列來傳遞,單獨修改某一個程式,不會影響另一個;
  • 不同程式(process)之間傳遞訊息時,為了實現標準化,將訊息的格式規範化了,並且,某一個程式接受的訊息太多,一下子無法處理完,並且也有先後順序,必須對收到的訊息進行排隊,因此誕生了事實上的訊息佇列

  不管到底是什麼原因催生了訊息佇列,總之,上面兩個猜測是其實際應用的典型場景。

  切合前一部分猜測的訊息佇列產生背景,其主要解決兩個問題:

  • 系統解耦:專案開始時,無法確定最終需求,不同程式間,新增一層,實現解耦,方便今後的擴充套件。
  • 訊息快取:系統中,不同程式處理訊息速度不同,MQ,可以實現不同Process之間的緩衝,即,寫入MQ的速度可以儘可能地快,而處理訊息的速度可以適當調整(或快、或慢)。

  下面針對系統解耦訊息快取兩點,來分析實際應用訊息佇列過程中,可能遇到的問題。虛擬場景:Process_A通過訊息佇列MQ_1向Process_B傳遞訊息,幾個問題:

  • 針對MQ_1中一條訊息message_1,如何確保Process_B從MQ_1中只取一次message_1,不會重複多次取出message_1?
  • 如果MQ_1中message_1已經被Process_B取出,正在處理的關鍵時刻,Process_B崩潰了,哭啊,我的問題是,如果重啟Process_B,是否會丟失message_1?

  不要著急,閱讀了下面的簡要介紹後,水到渠成,上面幾個問題就可以解決了。 訊息佇列有如下幾個好處,這大都是由其系統解耦訊息快取兩點擴充套件而來的:

  • 提升系統可靠性:
    • 冗餘:Process_B崩潰之後,資料並不會丟失,因為MQ多采用put-get-delete模式,即,僅當確認message被完成處理之後,才從MQ中移除message
    • 可恢復:MQ實現解耦,部分程式崩潰,不會拖累整個系統癱瘓,例,Process_B崩潰之後,Process_A仍可向MQ中新增message,並等待Process_B恢復;
    • 可伸縮:有較強的峰值處理能力,通常應用會有突發的訪問流量上升情況,使用足夠的硬體資源時刻待命,空閒時刻較長,資源浪費,而訊息佇列卻能夠平滑峰值流量,緩解系統元件的峰值壓力;
  • 提升系統可擴充套件性:
    • 調整模組:由於實現解耦,可以很容易調整,訊息入隊速率、訊息處理速率、增加新的Process;
  • 其他:
    • 單次送達:保證MQ中一個message被處理一次,並且只被處理一次。本質:get獲取一個message後,這一message即被預定,同一程式不會再次獲取這一message;當且僅當程式處理完這一message後,MQ中會delete這個message。否則,過一段時間後,這一message自動解除被預訂狀態,程式能夠重新預定這個message;
    • 排序保證:即,滿足佇列的FIFO,先入先出策略;
    • 非同步通訊:很多場景下,不會立即處理訊息,這是,可以在MQ中儲存message,並在某一時刻再進行處理;
    • 資料流的階段效能定位:獲取使用者某一操作的各個階段(通過message來標識),捕獲不同階段的耗時,可用於定位系統瓶頸。

相關文章