mq如何保證高可用,解決重復消費、數據丟失問題和順序性問題

一、如何保證消息隊列的高可用

1. RabbitMQ的高可用性

rabbitmq有三種模式:單機模式,普通集群模式,鏡像集群模式

  • 普通集群模式:多臺機器部署,每個機器放一個rabbitmq實例,但是創建的queue只會放在一個rabbitmq實例上,每個實例同步queue的元數據。如果消費時連的是其他實例,那個實例會從queue所在實例拉取數據。這就會導致拉取數據的開銷,如果那個放queue的實例宕機了,那么其他實例就無法從那個實例拉取,即便開啟了消息持久化,讓rabbitmq落地存儲消息的話,消息不一定會丟,但得等這個實例恢復了,然后才可以繼續從這個queue拉取數據,這就沒什么高可用可言,主要是提供吞吐量,讓集群中多個節點來服務某個queue的讀寫操作。
  • 鏡像集群模式:queue的元數據和消息都會存放在多個實例,每次寫消息就自動同步到多個queue實例里。這樣任何一個機器宕機,其他機器都可以頂上,但是性能開銷太大,消息同步導致網絡帶寬壓力和消耗很重,另外,沒有擴展性可言,如果queue負載很重,加機器,新增的機器也包含了這個queue的所有數據,并沒有辦法線性擴展你的queue。此時,需要開啟鏡像集群模式,在rabbit管理控制臺新增一個策略,將數據同步到指定數量的節點,然后你再次創建queue的時候,應用這個策略,就會自動將數據同步到其他的節點上去了
2. kafka的高可用性

kafka架構:多個broker組成,每個broker是一個節點;創建一個topic,這個topic可以劃分為多個partition,每個partition可以存在于不同的broker上,每個partition就放一部分數據。

它是一個分布式消息隊列,就是說一個topic的數據,是分散放在多個機器上的,每個機器就放一部分數據。


kafka 0.8以前,是沒有HA機制的,就是任何一個broker宕機了,那個broker上的partition就廢了,沒法寫也沒法讀,沒有什么高可用性可言。


kafka 0.8以后,提供了HA機制,就是replica副本機制。每個partition的數據都會同步到吉他機器上,形成自己的多個replica副本。然后所有replica會選舉一個leader出來,那么生產和消費都跟這個leader打交道,然后其他replica就是follower。寫的時候,leader會負責把數據同步到所有follower上去,讀的時候就直接讀leader上數據即可。kafka會均勻的將一個partition的所有replica分布在不同的機器上,從而提高容錯性。

如果某個broker宕機了也沒事,它上面的partition在其他機器上都有副本的,如果這上面有某個partition的leader,那么此時會重新選舉一個新的leader出來,大家繼續讀寫那個新的leader即可。這就有所謂的高可用性了。


寫數據的時候,生產者就寫leader,然后leader將數據落地寫本地磁盤,接著其他follower自己主動從leader來pull數據。一旦所有follower同步好數據了,就會發送ack給leader,leader收到所有follower的ack之后,就會返回寫成功的消息給生產者。

消費的時候,只會從leader去讀,但是只有當消息已經被所有follower都同步成功返回ack的時候,這個消息才會被消費者讀到。

二、如何保證消息不被重復消費

kafka重復消費的情況:
kafka有個offset的概念,就是每個消息寫進去,都有一個offset,代表他的序號,然后consumer消費了數據之后,每隔一段時間,會把自己消費過的消息的offset提交一下,下次重啟時,從上次消費到的offset來繼續消費。但是offset沒來得及提交就重啟,這部分會再次消費一次。


怎么保證消息隊列消費的冪等性:

  • 比如數據寫庫,可以先根據主鍵查一下,如果這數據都有了,就update
  • 比如寫redis,那沒問題,因為每次都是set,天然冪等性
  • 如果不是上面兩個場景,那做的稍微復雜一點,需要讓生產者發送每條數據的時候,里面加一個全局唯一的id,類似訂單id之類的東西,然后消費到了后,先根據這個id去比如redis里查一下,之前消費過嗎?如果沒有消費過,就處理,然后這個id寫redis。如果消費過了,那就別處理了,保證別重復處理相同的消息即可。
  • 還有比如基于數據庫的唯一鍵來保證重復數據不會重復插入多條,重復數據拿到了以后我們插入的時候,因為有唯一鍵約束了,所以重復數據只會插入報錯,不會導致數據庫中出現臟數據

三、如何保證消息的可靠性傳輸(如何處理消息丟失的問題)

丟數據,mq一般分為兩種,要么是mq自己弄丟了,要么是我們消費的時候弄丟了

1. rabbitmq
  • 生產者弄丟了數據:


    生產者將數據發送到rabbitmq的時候,因為網絡或者其他問題,半路給搞丟了。


    此時可以選擇用rabbitmq提供的事務功能,就是生產者發送數據之前開啟rabbitmq事務(channel.txSelect),然后發送消息,如果消息沒有成功被rabbitmq接收到,那么生產者會收到異常報錯,此時就可以回滾事務(channel.txRollback),然后重試發送消息;如果收到了消息,那么可以提交事務(channel.txCommit)。但是rabbitmq事務機會降低吞吐量,因為太耗性能。


    所以一般是開啟confirm模式,在生產者那里設置開啟confirm模式后,每次寫消息都會分配一個唯一的id,然后如果寫入了rabbitmq中,rabbitmq會回傳一個ack消息,告訴你說這個消息ok了。如果rabbitmq沒能處理這個消息,會回調你一個nack接口,告訴你這個消息接收失敗,你可以重試。而且你可以結合這個機制自己在內存里維護每個消息id的狀態,如果超過一定時間還沒接收到這個消息的回調,那么你可以重發


    事務機制和cnofirm機制最大的不同在于,事務機制是同步的,你提交一個事務之后會阻塞在那兒,但是confirm機制是異步的,你發送個消息之后就可以發送下一個消息,然后那個消息rabbitmq接收了之后會異步回調你一個接口通知你這個消息接收到了。

  • rabbitmq丟失數據:

    開啟rabbitmq的持久化。設置持久化有兩個步驟,第一個是創建queue的時候將其設置為持久化的,這樣就可以保證rabbitmq持久化queue的元數據,但是不會持久化queue里的數據;第二個是發送消息的時候將消息的deliveryMode設置為2,就是將消息設置為持久化的,此時rabbitmq就會將消息持久化到磁盤上去。必須要同時設置這兩個持久化才行,rabbitmq哪怕是掛了,再次重啟,也會從磁盤上重啟恢復queue,恢復這個queue里的數據。

    而且持久化可以跟生產者那邊的confirm機制配合起來,只有消息被持久化到磁盤之后,才會通知生產者ack了,所以哪怕是在持久化到磁盤之前,rabbitmq掛了,數據丟了,生產者收不到ack,你也是可以自己重發的。

  • 消費端弄丟了數據


    消費的時候,剛消費到,還沒處理,結果進程掛了,比如重啟,此時rabbitmq認為消費過了,這數據就丟了。


    用rabbitmq提供的ack機制,簡單來說,就是關閉rabbitmq自動ack,可以通過一個api來調用,然后每次代碼里確保處理完的時候,再程序里ack一把。這樣的話,如果還沒處理完,就沒有ack,那rabbitmq就認為你還沒處理完,這個時候rabbitmq會把這個消費分配給別的consumer去處理,消息是不會丟的。
2. kafka
  • 消費端弄丟了數據


    唯一可能就是消費到了這個消息,然后消費者那邊自動提交了offset,讓kafka以為你已經消費好了這個消息,其實你剛準備處理這個消息,你還沒處理,你自己就掛了,此時這條消息就丟了。


    只要關閉自動提交offset,在處理完之后自己手動提交offset,就可以保證數據不會丟。但是此時確實還是會重復消費,比如剛處理完,還沒提交offset,結果自己掛了,此時肯定會重復消費一次,自己保證冪等性就好了。

  • kafka弄丟了數據


    kafka某個broker宕機,然后重新選舉partiton的leader時。大家想想,要是此時其他的follower剛好還有些數據沒有同步,結果此時leader掛了,然后選舉某個follower成leader之后,中間這部分數據就丟失了。


    所以此時一般是要求起碼設置如下4個參數:

    (1)給這個topic設置replication.factor參數:這個值必須大于1,要求每個partition必須有至少2個副本

    (2)在kafka服務端設置min.insync.replicas參數:這個值必須大于1,這個是要求一個leader至少感知到有至少一個follower還跟自己保持聯系,沒掉隊,這樣才能確保leader掛了還有一個follower

    (3)在producer端設置acks=all:這個是要求每條數據,必須是寫入所有replica之后,才能認為是寫成功了

    (4)在producer端設置retries=MAX(很大很大很大的一個值,無限次重試的意思):這個是要求一旦寫入失敗,就無限重試,卡在這里了

  • 生產者會不會弄丟數據


    如果按照上述的思路設置了ack=all,一定不會丟,要求是,你的leader接收到消息,所有的follower都同步到了消息之后,才認為本次寫成功了。如果沒滿足這個條件,生產者會自動不斷的重試,重試無限次。

三、如何保證消息的順序性

1. rabbitmq

拆分多個queue,每個queue一個consumer,就是多一些queue而已,確實是麻煩點;或者就一個queue但是對應一個consumer,然后這個consumer內部用內存隊列做排隊,然后分發給底層不同的worker來處理

2. kafka

寫入一個partition中的數據一定是有序的,生產者在寫的時候 ,可以指定一個key,比如指定訂單id作為key,這個訂單相關數據一定會被分發到一個partition中去。消費者從partition中取出數據的時候也一定是有序的,把每個數據放入對應的一個內存隊列,一個partition中有幾條相關數據就用幾個內存隊列,消費者開啟多個線程,每個線程處理一個內存隊列。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容