面試連環炮
- 你用過消息隊列麼?
- 說說你們項目裏是怎麼用消息隊列的?
- 我們有一個訂單系統,訂單系統會每次下一個新訂單的時候,就會發送一條消息到ActiveMQ裏面去,後臺有一個庫存系統,負責獲取消息,然後更新庫存。
- 爲什麼使用消息隊列?
- 你的訂單系統不發送消息到MQ,而是直接調用庫存系統的一個接口,然後直接調用成功了,庫存也更新了,那就不需要使用消息隊列了呀
- 使用消息隊列的主要作用是:異步、解耦、削峯
- 消息隊列都有什麼優缺點?
- Kafka、activeMQ、RibbitMQ、RocketMQ都有什麼優缺點?
- 如何保證消息隊列的高可用?
- 如何保證消息不被重複消費?如何保證消息消費時的冪等性?
- 如何保證消息的可靠性傳輸,要是消息丟失了怎麼辦?
- 如何保證消息的順序性?
- 如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以後該怎麼處理?有幾百萬消息持續積壓幾小時,說說怎麼解決?
- 如果讓你寫一個消息隊列,該如何進行架構設計,說一下你的思路?
面試題
如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以後該怎麼處理?有百萬消息積壓接小時,說說解決思路?
剖析
MQ大幅度積壓這件事挺常見的,一般不出,出了的話就是大型生產事故,例如:消費端每次消費之後要寫MySQL,結果MySQL掛了,消費端就不動了,或者一直出錯,導致消息消費速度極其慢。
場景1:積壓大量消息
幾千萬的消息積壓在MQ中七八個小時,這也是一個真實遇到過的一個場景,確實是線上故障了,這個時候要不然就是修復consumer,讓他恢復消費速度,然後傻傻的等待幾個小時消費完畢,但是很顯然這是一種比較不機智的做法。
假設1個消費者1秒消費1000條,1秒3個消費者能消費3000條,一分鐘就是18萬條,1000萬條也需要花費1小時才能夠把消息處理掉,這個時候在設備允許的情況下,如何才能夠快速處理積壓的消息呢?
一般這個時候,只能夠做緊急的擴容操作了,具體操作步驟和思路如下所示:
- 先修復consumer的問題,確保其恢復消費速度,然後將現有consumer都停止
- 臨時建立好原先10倍或者20倍的queue數量
- 然後寫一個臨時的分發數據的consumer程序,這個程序部署上去消費積壓的數據,消費之後不做耗時的處理,直接均勻輪詢寫入臨時建立好的10倍數量的queue
- 接着臨時徵用10倍機器來部署consumer,每一批consumer消費一個臨時queue的數據
- 這種做法相當於臨時將queue資源和consumer資源擴大了10倍,以正常的10倍速度
也就是讓消費者把消息,重新寫入MQ中,然後在用 10倍的消費者來進行消費。
場景2:大量消息積壓,並且設置了過期時間
假設你用的是RabbitMQ,RabbitMQ是可以設置過期時間的,就是TTL,如果消息在queue中積壓超過一定的時間,就會被RabbitMQ給清理掉,這個數據就沒了。這個時候就不是數據被大量積壓的問題,而是大量的數據被直接搞丟了。
這種情況下,就不是說要增加consumer消費積壓的消息,因爲實際上沒有啥積壓的,而是丟了大量的消息,我們可以採取的一個方案就是,批量重導,這個之前線上也有遇到類似的場景,就是大量的消息積壓的時候,然後就直接丟棄了數據,然後等高峯期過了之後,例如在晚上12點以後,就開始寫程序,將丟失的那批數據,寫個臨時程序,一點點查詢出來,然後重新 添加MQ裏面,把白天丟的數據,全部補回來。
假設1萬個訂單積壓在MQ裏面,沒有處理,其中1000個訂單都丟了,你只能手動寫程序把那1000個訂單查詢出來,然後手動發到MQ裏面去再補一次。
場景3:大量消息積壓,導致MQ磁盤滿了
如果走的方式是消息積壓在MQ裏,那麼如果你很長時間都沒有處理掉,此時導致MQ都快寫滿了,咋辦?
這個時候,也是因爲方案一執行的太慢了,只能寫一個臨時程序,接入數據來消費,然後消費一個丟棄一個,都不要了,快速消費掉所有的消息。然後走第二個方案,到凌晨的時候,在把消息填入MQ中進行消費。