RabbitMq之消息確認

  最近閱讀了rabbitmq的官方文檔,然後結合之前面試時被問到關於消息隊列的問題來探索一下關於消息隊列的消息確認機制。

  其實消息確認就是消費者確認消息被消費了, 生產者確認消息已經發送到了消息隊列中了。

  我們知道rabbitmq有四種消息機制,下圖是爲了我們對消息確認的理解從官網盜了一張工作隊列的圖如下:

 

一、 關於消費者確認方面問題

  在我們的mq推送了消息給消費者後,我們怎麼知道消息被消費者消費了呢?萬一消費者沒有消費該消息,或者消費者掛了,這消息是不是就永久丟失了,所以根據此有下列幾個關於消費者確認的相關問題。同時在這我們也糾正一個常見的誤區,mq是推消息到消費者處的而不是消費者去mq中取消息的,然後在mq中消息充足的情況下,mq推消息給消費者不是等消費者消費完一個再推一個,而是根據 prefetch_count參數來決定可以推多個消息到消費者的緩存裏面。

 

問題1: 如果其中一個消費者開始一項漫長的任務,而僅部分完成而死掉,會發生什麼情況。使用我們當前的代碼,RabbitMQ一旦將消息傳遞給消費者,便立即將其標記爲刪除。在這種情況下,如果您殺死一個work,我們將丟失正在處理的消息。我們還將丟失所有發送給該特定工作人員但尚未處理的消息。

答:爲了確保消息永不丟失,RabbitMQ支持 消息確認。消費者發送回一個確認(acknowledgement)以告知RabbitMQ已經接收,處理了特定的消息,然後RabbitMQ會去刪除這條消息,如果消費者在不發送確認的情況下死亡(其通道已關閉,連接已關閉或TCP連接丟失),RabbitMQ將瞭解消息未得到充分處理,並將重新排隊。如果同時有其他消費者在線,它將很快將其重新分發給另一個消費者。這樣,您可以確保即使工人偶爾死亡也不會丟失任何消息

 

問題2:開啓了消息持久化,消息就一定不會丟失嗎?

答: 將消息標記爲持久性並不能完全保證不會丟失消息。儘管它告訴RabbitMQ將消息保存到磁盤,但是仍有很短的時間RabbitMQ接受了消息但尚未將其保存。另外,RabbitMQ不會對每條消息都執行fsync(2)-它可能只是保存到緩存中,而沒有真正寫入磁盤。持久性保證並不強,但是對於我們的簡單任務隊列而言,這已經綽綽有餘了。如果您需要更強有力的保證,則可以使用 發佈者確認

  在這裏補充一個知識:如果mq開啓了持久化以後, 生產者把消息推給消息隊列, 消息隊列會複製一份消息到持久化隊列,然後有新線程從持久化隊列中把消息持久化到磁盤中。

 

問題3: 兩個消費者同時消費一個隊列,是隊列分發消息還是消費者去取消息?

答:您可能已經注意到,調度仍然無法完全按照我們的要求進行。例如,在有兩名工人的情況下,當有的消息都很重,有的消息消息很輕時,一位工人將一直忙碌而另一位工人將幾乎不做任何工作。好吧,RabbitMQ對此一無所知,並且仍將平均分配消息。

發生這種情況是因爲RabbitMQ在消息進入隊列時才調度消息。它不會查看使用者的未確認消息數。它只是盲目地將每第n條消息發送給第n個使用者。
爲了解決這個問題,我們可以將Channel#basic_qos通道方法與 prefetch_count = 1設置一起使用。這使用basic.qos協議方法來告訴RabbitMQ一次不向工作人員發送多條消息。換句話說,在處理並確認上一條消息之前,不要將新消息發送給工作人員。而是將其分派給不忙的下一個工作程序。
 
  這裏補充一個知識:當兩個消費者同時訂閱了同一個隊列時,隊列會把消息循環平均分配給兩個消費者。

 

問題4: 關於隊列大小的注意事項,如果隊列滿了怎麼處理?

答:如果隊列滿了以後,我們一方面可以增加消費者的數量,很淺顯消費者越多消費消息就越快,還有一個是設置消息的過期時間來控制。

  這裏補充個知識: 當消息過期或者被消費者拒絕並且設置不返回隊列中,這消息將加入死信隊列。

 

二、關於生產者確認方面問題

  同樣的,我們的生產者給mq push消息的時候,我們怎麼知道這消息放進了mq裏面了呢?所以這引發了mq確認消息的相關問題。

問題1: 發佈者確認消息機制是怎樣的?

答:首先消息的傳遞機制是這樣,發佈者將消息發送到消息隊列的exchange中,然後根據exchange的分發規則,分發到制定具體隊列,如果開啓了持久化,消息會複製一份持久化隊列中, 持久化隊列在收到消息後會給隊列返回ack確認信息, 然後隊列給exchange返回確認信息, exchange根據回調函數給發佈者返回確認信息,這樣發佈者確認就算完成了。

  當時你知道發佈者的確認規則,你是不是立馬想到確認要經過這麼多箇中間人,省略中間的環節行不行勒,哈哈答案是可以的,不過得自己去改造啦,這是性能優化的一項。

 

問題2:發佈者確認的方式有哪幾種?

答:有三種確認方式

1)同步確認,消息發出後一直處於阻塞狀態等待確認消息,可以設置超時時間,如果超過超時時間則認爲消息丟失, 如果超時或者消息確認失敗則會拋出異常,我們捕獲異常然後選擇是重發還是等其他處理方式。

2)批量確認,一次性發出一批消息然後阻塞等待,形式和同步確認相似,有點則是一批確認所以性能上會有很大的提升,缺點是我們不能確認具體發生了什麼錯誤,並且我們得在內存中存儲這批消息以確認發送成功的消息和重發失敗的消息。

3)異步確認,發送消息後註冊一個回調函數,不阻塞線程,在消息確認後會調用回調函數

 

  如果想更詳細地瞭解其機制可以閱讀其官方文檔,文檔中有關於消息確認的具體代碼展示,可以更方便地理解其機制。

 

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