02.26 高併發場景下,如何保證生產者投遞到消息中間件的消息不丟失?

林文泉


消息中間件消息不丟失主要從以下幾個方面考慮

投遞

生產者向消息中間件投遞消息是push的方式,這種方法會出現以下情況

1、生產者掛掉了

情況是這樣的,你的生產者收到了數據,並存到了數據庫中,同時生產者要降消息push到消息中間件做異步處理。這時候如果生產者掛掉了,就導致消息數據沒有push到消息中間件裡,也就會出現數據不一致的問題。

這時候我們可以在數據庫設置是否投遞成功標誌位,在生產者push之後,再將標誌位設置為已經投遞。另外,客氣啟動一個定時任務,檢測是否有消息沒有投遞,保證消息數據一定會進入中間件。

2、消息重試

生產者沒有掛掉,但是因為網絡等其他問題,導致生產者不知道有沒有投遞成功。這時候生產者可以失敗重試,這保證消息可以再次投遞。但是這有可能會出現重複投遞,導致出現中間件消息數據重複。

存儲

消息中間件是存到磁盤上的,存入磁盤的消息一般是不會丟失的,同時磁盤文件還會做備份。如果一個丟失了,可以通過備份文件恢復。

消費

一般消費者需要在消費者消費成功之後再設置提交消費位點。如果消費失敗,消費者不提交消費位點還是可以消費該數據的。這就引出一個問題就是消息重複消費。這個問題和上邊提到的消息重複投遞相同,都會導致重複消費,這就需要考慮消費的冪等性,可以做消費記錄,防止重複消費。


MiLi視頻


消息傳遞分3步:

1, 生產者 --> MQ

2, MQ 緩存

3, MQ --> 消費者

如何確保消息不丟失?

各家MQ都有複雜的機制,拿RocketMQ舉例,對應上面的3步,簡單來說:

第1步,同步阻塞投遞

如果返回成功,則說明消息一定投遞到了Broker。

如果返回超時,默認重試2次。而超時,到底成功還是失敗,可通過實時API查詢Broker確定,不過一般人不會這麼幹。那應該怎麼辦?

第2步,刷盤持久化,分同步和異步。為了性能,一般選擇異步,但極端情況下Broker掛掉時,異步方式可能丟失消息,這個跟具體集群方式有關。而消息丟了,怎麼發現?

第3步,如果消費者沒有返回成功標識,Broker會默認重試最多16次。那超過16次,怎麼發現?

RocketMQ已經為我們提供了完善的機制,高併發下,如何確保100%消息不丟失並且被正確消費完成,則要回答上面1,2,3提出的問題。

我在實際工作中,使用RocketMQ時,都是額外再開發一個“定時任務”來檢查業務處理結果,不管是1,2,3哪一步出現問題,都可以由這個任務發現。這個補償任務的方式可以用在很多MQ中,有人說任務的性能低、及時性不高,但你要知道消息丟失畢竟是小概率事件,這個任務只是確保萬一。

最後要說的是,為了消息的不丟失,就避免不了消息的重複,所以無論如何,使用者還都要實現“消費的冪等性”。

PS: 沒有經歷過大廠,不知道他們怎麼處理的。有知道的,請指點一下,謝謝。


請先生輸入用戶名


1.先來看下消息的投遞過程,消息發送分為三步,見圖

2.發送方通過這三步便可以保證消息發送到mq的可靠性:

第一步send將消息發送給mq,

第二步mq將消息持久化,mq需要保證高可用, 消息持久化化後不會丟失,一般都會存在多個副本,多個副本之間可以使用raft協議保證數據一致性。

第三步mq應答到send方確認消息已投遞。

但是因為1,2,3步中都可能出現故障,需要重試發送請求。如果是1,2步失敗直接重試就可以了,如果第三步失敗了,就可能一條消息會出現多條,這就需要消費端去保證消費的冪等性。



淺析架構


你這個問題應該是指的是投遞保證一致性,還是投遞成功了,並且收到了ack確認的話然後消息沒有存在在消息隊列中?

第一個的話,一般來說為了保證消息正確投遞,用有acid特性的數據庫,如MySQL,可以保證消息能正確投遞,如rabbitmq有confirm機制,callback機制,還有不被重複投遞。當然這樣做的話併發效果可能不是很強,但是可以保證穩定,這就是業務場景而定了。

第二個的話,基本不用擔心了,很多消息隊列都有持久化功能,在某些災難情況下可以保證不丟失,正常業務情況下,消息會被正確消費。


zhangshen892


1.調整操作系統核心參數,確保每一臺服器在操作系統層能承載高併發

2.消息中間件參數調整,確保中間件本身有足夠緩存

3.提升後端業務處理的性能,減少中間件的堵塞

4.使用http2.0


江南布衣王


第一,可以使用消息投遞後qos機制,進行ack應答,如果投遞後一定時間沒收到消費ack,qos本身會進行重發。

第二,對於發送的消息,可以先持久化,然後定時輪訓發送,對於消費者,可以先將消息報文持久化,然後定時消費,做業務處理。


kid7157887


討論消息丟失的前提是消息已經發送到MQ,如果發送都沒成功,何來丟失的說法?然後發送消息只是一個普通的RPC遠程調用而已,如果失敗,那是消息生產者自己要處理的事情。就像寫入數據到數據庫失敗一樣。所以我覺得樓主提這個問題本身就沒有理解什麼叫做消息丟失。


分享到:


相關文章: