1. 程式人生 > >如何保證訊息的可靠性傳輸?或者說,如何處理訊息丟失的問題?

如何保證訊息的可靠性傳輸?或者說,如何處理訊息丟失的問題?

面試題

如何保證訊息的可靠性傳輸?或者說,如何處理訊息丟失的問題?

面試官心理分析

這個是肯定的,用 MQ 有個基本原則,就是資料不能多一條,也不能少一條,不能多,就是前面說的重複消費和冪等性問題。不能少,就是說這資料別搞丟了。那這個問題你必須得考慮一下。

如果說你這個是用 MQ 來傳遞非常核心的訊息,比如說計費、扣費的一些訊息,那必須確保這個 MQ 傳遞過程中絕對不會把計費訊息給弄丟。

面試題剖析

資料的丟失問題,可能出現在生產者、MQ、消費者中,咱們從 RabbitMQ 和 Kafka 分別來分析一下吧。

RabbitMQ

生產者弄丟了資料

生產者將資料傳送到 RabbitMQ 的時候,可能資料就在半路給搞丟了,因為網路問題啥的,都有可能。

此時可以選擇用 RabbitMQ 提供的事務功能,就是生產者傳送資料之前開啟 RabbitMQ 事務channel.txSelect,然後傳送訊息,如果訊息沒有成功被 RabbitMQ 接收到,那麼生產者會收到異常報錯,此時就可以回滾事務channel.txRollback,然後重試傳送訊息;如果收到了訊息,那麼可以提交事務channel.txCommit

// 開啟事務
channel.txSelect
try {
    // 這裡傳送訊息
} catch (Exception e) {
    channel.txRollback

    // 這裡再次重發這條訊息
}

// 提交事務
channel.txCommit

但是問題是,RabbitMQ 事務機制(同步)一搞,基本上吞吐量會下來,因為太耗效能。

所以一般來說,如果你要確保說寫 RabbitMQ 的訊息別丟,可以開啟 confirm 模式,在生產者那裡設定開啟 confirm 模式之後,你每次寫的訊息都會分配一個唯一的 id,然後如果寫入了 RabbitMQ 中,RabbitMQ 會給你回傳一個 ack 訊息,告訴你說這個訊息 ok 了。如果 RabbitMQ 沒能處理這個訊息,會回撥你的一個 nack 介面,告訴你這個訊息接收失敗,你可以重試。而且你可以結合這個機制自己在記憶體裡維護每個訊息 id 的狀態,如果超過一定時間還沒接收到這個訊息的回撥,那麼你可以重發。

事務機制和 confirm 機制最大的不同在於,事務機制是同步的,你提交一個事務之後會阻塞在那兒,但是 confirm 機制是非同步的,你傳送個訊息之後就可以傳送下一個訊息,然後那個訊息 RabbitMQ 接收了之後會非同步回撥你的一個介面通知你這個訊息接收到了。

所以一般在生產者這塊避免資料丟失,都是用 confirm 機制的。

RabbitMQ 弄丟了資料

就是 RabbitMQ 自己弄丟了資料,這個你必須開啟 RabbitMQ 的持久化,就是訊息寫入之後會持久化到磁碟,哪怕是 RabbitMQ 自己掛了,恢復之後會自動讀取之前儲存的資料,一般資料不會丟。除非極其罕見的是,RabbitMQ 還沒持久化,自己就掛了,可能導致少量資料丟失,但是這個概率較小。

設定持久化有兩個步驟:

  • 建立 queue 的時候將其設定為持久化

    這樣就可以保證 RabbitMQ 持久化 queue 的元資料,但是它是不會持久化 queue 裡的資料的。
  • 第二個是傳送訊息的時候將訊息的 deliveryMode 設定為 2

    就是將訊息設定為持久化的,此時 RabbitMQ 就會將訊息持久化到磁碟上去。

必須要同時設定這兩個持久化才行,RabbitMQ 哪怕是掛了,再次重啟,也會從磁碟上重啟恢復 queue,恢復這個 queue 裡的資料。

注意,哪怕是你給 RabbitMQ 開啟了持久化機制,也有一種可能,就是這個訊息寫到了 RabbitMQ 中,但是還沒來得及持久化到磁碟上,結果不巧,此時 RabbitMQ 掛了,就會導致記憶體裡的一點點資料丟失。

所以,持久化可以跟生產者那邊的 confirm 機制配合起來,只有訊息被持久化到磁碟之後,才會通知生產者 ack 了,所以哪怕是在持久化到磁碟之前,RabbitMQ 掛了,資料丟了,生產者收不到 ack,你也是可以自己重發的。

消費端弄丟了資料

RabbitMQ 如果丟失了資料,主要是因為你消費的時候,剛消費到,還沒處理,結果程序掛了,比如重啟了,那麼就尷尬了,RabbitMQ 認為你都消費了,這資料就丟了。

這個時候得用 RabbitMQ 提供的 ack 機制,簡單來說,就是你必須關閉 RabbitMQ 的自動 ack,可以通過一個 api 來呼叫就行,然後每次你自己程式碼裡確保處理完的時候,再在程式裡 ack 一把。這樣的話,如果你還沒處理完,不就沒有 ack 了?那 RabbitMQ 就認為你還沒處理完,這個時候 RabbitMQ 會把這個消費分配給別的 consumer 去處理,訊息是不會丟的。

Kafka

消費端弄丟了資料

唯一可能導致消費者弄丟資料的情況,就是說,你消費到了這個訊息,然後消費者那邊自動提交了 offset,讓 Kafka 以為你已經消費好了這個訊息,但其實你才剛準備處理這個訊息,你還沒處理,你自己就掛了,此時這條訊息就丟咯。

這不是跟 RabbitMQ 差不多嗎,大家都知道 Kafka 會自動提交 offset,那麼只要關閉自動提交 offset,在處理完之後自己手動提交 offset,就可以保證資料不會丟。但是此時確實還是可能會有重複消費,比如你剛處理完,還沒提交 offset,結果自己掛了,此時肯定會重複消費一次,自己保證冪等性就好了。

生產環境碰到的一個問題,就是說我們的 Kafka 消費者消費到了資料之後是寫到一個記憶體的 queue 裡先緩衝一下,結果有的時候,你剛把訊息寫入記憶體 queue,然後消費者會自動提交 offset。然後此時我們重啟了系統,就會導致記憶體 queue 裡還沒來得及處理的資料就丟失了。

Kafka 弄丟了資料

這塊比較常見的一個場景,就是 Kafka 某個 broker 宕機,然後重新選舉 partition 的 leader。大家想想,要是此時其他的 follower 剛好還有些資料沒有同步,結果此時 leader 掛了,然後選舉某個 follower 成 leader 之後,不就少了一些資料?這就丟了一些資料啊。

生產環境也遇到過,我們也是,之前 Kafka 的 leader 機器宕機了,將 follower 切換為 leader 之後,就會發現說這個資料就丟了。

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

  • 給 topic 設定 replication.factor 引數:這個值必須大於 1,要求每個 partition 必須有至少 2 個副本。
  • 在 Kafka 服務端設定 min.insync.replicas 引數:這個值必須大於 1,這個是要求一個 leader 至少感知到有至少一個 follower 還跟自己保持聯絡,沒掉隊,這樣才能確保 leader 掛了還有一個 follower 吧。
  • 在 producer 端設定 acks=all:這個是要求每條資料,必須是寫入所有 replica 之後,才能認為是寫成功了。
  • 在 producer 端設定 retries=MAX(很大很大很大的一個值,無限次重試的意思):這個是要求一旦寫入失敗,就無限重試,卡在這裡了。

我們生產環境就是按照上述要求配置的,這樣配置之後,至少在 Kafka broker 端就可以保證在 leader 所在 broker 發生故障,進行 leader 切換時,資料不會丟失。

生產者會不會弄丟資料?

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

本文在米兜公眾號連結:
https://mp.weixin.qq.com/s/cEKl-PGj4MypHgDxTgJhRg

歡迎關注米兜Java,一個注在共享、交流的Java學習平臺。

相關推薦

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

RabbitMQ   生產者弄丟了資料     生產者將資料傳送到RabbitMQ的時候,可能資料就在半路給搞丟了,因為網路啥的問題,都有可能。     此時可以選擇用RabbitMQ提供的事務功能,就是生產者傳送資料之前開啟RabbitMQ事務(channel.tx

使用華為推送向伺服器註冊並接收訊息處理訊息點選事件。

華為推送是華為公司推出的,優秀的推送服務,在專案中,我使用了華為的推送服務,記錄下來,供其他同學參考。 1.配置Maven庫 在allprojects->repositories 裡面配置HMSSDK的maven倉。  allprojects {         

RabbitMQ訊息丟失問題和保證訊息可靠性-消費端不丟訊息和HA(二)

繼續上篇文章解決RabbitMQ訊息丟失問題和保證訊息可靠性(一) 未完成部分,我們聊聊MQ Server端的高可用和消費端如何保證訊息不丟的問題? 迴歸上篇的內容,我們知道訊息從生產端到服務端,為了保證訊息不丟,我們必須做哪些事情? 傳送端採用Confirm模式,注意Server端沒成功通

如何保證訊息可靠性傳輸或者如何處理訊息丟失的問題?

面試題 如何保證訊息的可靠性傳輸?或者說,如何處理訊息丟失的問題? 面試官心理分析 這個是肯定的,用 MQ 有個基本原則,就是資料不能多一條,也不能少一條,不能多,就是前面說的重複消費和冪等性問題。不能少,就是說這資料別搞丟了。那這個問題你必須得考慮一下。 如果說你這個是用 MQ 來傳遞非常核心的訊息,比

Combobox控制元件使用MoveWindow()移動位置時OnNcCalcSize訊息處理

說到OnNcCalcSize在程式內部的訊息處理次數。主要說的是Combobox控制元件 1:如果是從工具箱拖出來的控制元件 只會走一次  OnNcCalcSize()  訊息 2:從工具箱中拖出來的控制元件,並且使用了MoveWindow時   &

基於MFC對話方塊的圖示滑鼠形狀鍵盤訊息處理的示例

標頭檔案 // MFC_ShowPointDlg.h : 標頭檔案 // #pragma once // CMFC_ShowPointDlg 對話方塊 class CMFC_ShowPointDlg : public CDialogEx { // 構造 public: CMFC

消費RabbitMQ時的注意事項如何禁止大量的訊息湧到Consumer保證執行緒安全

按照官網提供的訂閱型寫法( Retrieving Messages By Subscription ("push API")) 我發現,RabbitMQ伺服器會在短時間內傳送大量的訊息給Consumer,然後,如果你沒有來得及Ack的話,那麼服務端會積壓大量的UnAcked訊息,而Cons

pomelo通過過濾器增加訊息處理分隔線

pomelo對訊息都有一個過濾機制,我們只需要before或after,列印分隔線。在app.configure,對應的伺服器實始化的時候,增加過濾器。 let xxfilter = requ

Linux定時器處理之實時訊號使用訊息佇列阻塞模型避免超時等待

man msgrcv翻到msgrcv函式英文有段話說明了,意思是這樣,當msgrcv所在的程序捕獲到一個訊號的時候,該函式會呼叫失敗並且把errno設定為EINTR,也就是說這個時候msgrcv就不會繼續阻塞了,會直接返回,如果在這之前啟動了定時器,這個時候就可以進行超時判

spring+activemq配置多個生產者多個消費者併發處理訊息

先貼配置 <?xml version="1.0" encoding="UTF-8"?>    <beans xmlns="http://www.springframework.org/schema/beans"   xmlns:xsi="http://w

RabbitMQ 訊息中介軟體如何保證消費者customer能夠成功處理訊息?

一、確保消費者customer處理訊息成功 預設情況下消費者C1接收到訊息1無論是否正常接受和處理都會立即應答rabbit伺服器,

解決RabbitMQ訊息丟失問題和保證訊息可靠性

工作中經常用到訊息中介軟體來解決系統間的解耦問題或者高併發消峰問題,但是訊息的可靠性如何保證一直是個很大的問題,萬一訊息丟了

使用訊息中介軟體時如何保證訊息僅僅被消費一次?

訊息中介軟體使用廣泛,常用來削峰填谷、系統解耦、非同步處理。非同步處理可能是使用的最多的場景了,比如現在的技術部落格網站,都採用積分制,使用者發表一篇文章後,可以獲取想要的積分,為了提升系統的效能,給使用者加積分的操作可以非同步處理,並不需要放在同步流程中。 我們可以把使用者ID,需要增加的積分封裝成一條訊

RabbitMQ高階之如何保證訊息可靠性

>人生終將是場單人旅途,孤獨之前是迷茫,孤獨過後是成長。 ## 楔子 本篇是訊息佇列`RabbitMQ`的第四彈。 `RabbitMQ`我已經寫了三篇了,基礎的收發訊息和基礎的概念我都已經寫了,學任何東西都是這樣,先基礎的上手能用,然後遇到問題再去解決,無法理解就去深入原始碼,隨著時間的積累對這

僅8小時4訊息! 火箭功勳迴歸 16+28悍將馳08:32

南樂縣 阿里巴巴集團董事局主席馬雲發表致股東的公開信表示:生意難做之時,正是阿里巴巴兌現“讓天下沒有難做的生意”的使命之時。,阿里巴巴(NYSE:BABA)今日釋出了截至2018年9月30日的2019財年第二季度財報(注:阿里巴巴財年與自然年不同步,從每年的4月1日開始,至第二年的3月31日結束)。 財報中

mui訊息框的alertconfirmprompttoast的區別?

<span style="font-family:FangSong_GB2312;font-size:14px;">script type="text/javascript" charset="utf-8">   &nbs

RabbitMQ實戰篇8-在庫存服務中配置RabbitMQ實現訊息接收

上節介紹瞭如何實現訊息的傳送,這節我們接著上節說說如何實現訊息的接收。 新增依賴,進行配置 同樣的,訊息消費者也需要新增RabbitMQ的依賴,配置連線資訊。 因為在上一節已經說過了,這裡過於依賴和連線資訊的配置就不在贅述了。 訂閱訊息 新建一個OrderConsumer,用於訂閱和消費訊

轉載大牛所寫內容MAC 訊息驗證編碼的使用和相關概念非我所寫我只是備忘檢視並加註解一些紅色字型內容

  資訊保安基礎知識 MAC訊息驗證碼及金鑰管理問題   版權宣告:本文為博主原創文章,未經博主允許不得轉載。 原文地址https://blog.csdn.net/a359680405/article/details/41518685   &n

Windows訊息佇列、執行緒訊息佇列視窗訊息的概念與關係

1.視窗 Windows程式是由一系列的視窗構成的,每個視窗都有自己的視窗過程,視窗過程就是一個擁有有固定 Signature 的 C函式,具體格式如下: LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wPa

JAVA接收第三方的訊息的推送物聯網的裝置端的訊息推送

裝置端,進行訊息推送,就是裝置的一些資訊,比如電量的值,和是否推送成功的狀態值 其推送的值的格式是json的格式,推送的標識的cmd,我這裡列子是cmd:"signal_test_status" 接收推送的程式碼是  */ @RestController("DeviceS