面試中消息隊列的問題

消息隊列的匹配規則

1.消息隊列模式
消息隊列模式:發送者,接受者

2.主題消息模式
主題消息:發佈者,訂閱者

3.Rabbitmq消息確認機制
通過持久化數據的方式,生產者將消息發送出去之後,消息到底有沒有達到rabbitmq服務器默認是不知道的。

消息隊列如何確保其消息的順序性

通常來說有以下的思路

  • 單線程消費來確保消息的順序性
  • 對消息進行編號,消費者處理時根據編號判斷順序。

rabbitmq:(隊列消息的思路)
拆分多個queue,每個queue一個consumer。或者就一個queue但是對應一個consumer,然後這個consumer內部用內存隊列做排隊,然後分發給底部不同worker處理

  • 防止使用同一個隊列,導致數據123進入不同的消費者,從而使得數據123沒有按指定的順序被執行

  • 通過拆分queue來保證每一個消費者都能獲得完整的數據123,然後消費者內部進行排隊,從而保證消息的有序性。

  • 這裏同時也要設計,保證消息的冪等性。
    在這裏插入圖片描述
    kafka
    一個topic,一個partition(分割),一個consumer,內部單線程消費,寫N個內存queue,然後N個線程分別消費一個內存queue。

  • 通過指定key的方式,來確保相關的數據123會分發到同一個partition

  • partition會內部對其進行排序,保證其有序性。
    在這裏插入圖片描述

消息隊列如何保證其不會重複消費

簡單來說,如何實現消息的冪等性,即消息執行一次和執行多次的結果是一樣的。
保證數據不會重複消費,要結合業務來實現

  1. 比如你拿個數據要寫庫,你先根據主鍵查一下,如果這數據都有了,你就別插入了,update 一下好吧。
  2. 比如你是寫 Redis,那沒問題了,反正每次都是 set,天然冪等性。
  3. 比如你不是上面兩個場景,那做的稍微複雜一點,你需要讓生產者發送每條數據的時候,裏面加一個全局唯一的 id,類似訂單 id
    之類的東西,然後你這裏消費到了之後,先根據這個 id 去比如 Redis 裏查一下,之前消費過嗎?如果沒有消費過,你就處理,然後這個
    id 寫 Redis。如果消費過了,那你就別處理了,保證別重複處理相同的消息即可。
  4. 比如基於數據庫的唯一鍵來保證重複數據不會重複插入多條。因爲有唯一鍵約束了,重複數據插入只會報錯,不會導致數據庫中出現髒數據。

消息隊列如何保證消息不會丟失

消息從生產到消費可以經歷三個階段:生產階段、存儲階段和消費階段。
生產階段:在這個階段,從消息在生產者創建出來,經過網絡傳輸到消息隊列服務器中。
存儲階段:消息在消息隊列服務器中存儲,如果是集羣,消息會在這個階段被複制到其他的副本上。
消費階段:消費者從消息隊列服務器中拉取消息,通過網絡傳輸發送到消費者。
而解決消息隊列在整個過程中不會消息丟失的方式,就是藉助消息隊列的應答模式來實現。

應答模式
消費者完成消費處理後,會發送一個消費應答,告訴消息隊列服務器這個消息已經處理完成可以刪除這個消息了,如果一個消費者由於宕機
沒有發送消息應答,那麼消息隊列服務器會認爲消息發送失敗,自動進行補償行爲,即將這個消息重新加入隊列,重新投遞。
應答模式又分爲自動應答和手動應答,區別在於告訴消息隊列服務刪除消息的時間點是否要手動刪除。
應答模式犧牲了消息隊列的性能,從而提高了消息的可靠性。

消息隊列如何解決消息堆積問題

消息隊列除了有異步解耦的功能,還有擋住前端數據洪峯的功能。

  1. 修復現有consumer的問題,並將其停掉。
  2. 重新創建一個容量更大的topic,比如patition是原來的10倍。
  3. 編寫一個臨時consumer程序,消費原來積壓的隊列。該consumer不做任何耗時的操作,將消息均勻寫入新創建的隊列裏。
  4. 將修復好的consumer部署到原來10倍的機器上消費新隊列。
  5. 消息積壓解決後,恢復原有架構

核心思路,提高消費者的消費能力。

在RabbitMQ提供了一個消息回推機制可以解決消息堆積的問題
在RabbitMQ2.0之前
如果發佈者應用程序因爲發佈消息太快而開始對RabbitMQ造成壓力,那麼RabbitMQ將發送Channel.FlowRPC方法來讓你的發佈者阻塞,即發佈者不能發送任何消息直到收到另一條Channel.Flow命令爲止。
但是,存在發佈者沒有監聽Channel.Flow方法的極端情況。

在RabbitMQ3.2之後
採用TCP背壓的機制來解決這種極端情況,採用一個連接信用閾值的機制,RabbitMQ將根據RPC請求的完成情況給每一個發佈者打分,RabbitMQ只處理有足夠信用的發佈者的消息。
同時藉助Connection.Blocked和Connection.Unblocked這兩個異步方法,來通知客戶端進行阻塞和取消阻塞。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章