消息中間件面試題:消息丟失怎么辦感局?

面試題

如何保證消息的可靠性傳輸?或者說暂衡,如何處理消息丟失的問題询微?

消息中間件各種面試題:
消息中間件面試題:消息丟失怎么辦?
消息中間件面試題:消息隊列的優(yōu)缺點狂巢,區(qū)別
消息中間件面試題:消息中間件的高可用
消息中間件面試題:如何保證消息的順序性
消息中間件面試題:如何保證消息不被重復消費
消息中間件面試題:如何解決消息隊列的延時以及過期失效問題撑毛?消息隊列滿了以后該怎么處理?有幾百萬消息持續(xù)積壓幾小時呢唧领?
消息中間件面試題:如果讓你寫一個消息隊列藻雌,該如何進行架構設計雌续?

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

面試題剖析

數(shù)據(jù)的丟失問題歉摧,可能出現(xiàn)在生產者艇肴、MQ、消費者中叁温,咱們從 RabbitMQ 和 Kafka 分別來分析一下吧再悼。

RabbitMQ

rabbitmq-message-lose

生產者弄丟了數(shù)據(jù)

生產者將數(shù)據(jù)發(fā)送到 RabbitMQ 的時候,可能數(shù)據(jù)就在半路給搞丟了膝但,因為網絡問題啥的冲九,都有可能。

此時可以選擇用 RabbitMQ 提供的事務功能跟束,就是生產者發(fā)送數(shù)據(jù)之前開啟 RabbitMQ 事務channel.txSelect莺奸,然后發(fā)送消息,如果消息沒有成功被 RabbitMQ 接收到冀宴,那么生產者會收到異常報錯灭贷,此時就可以回滾事務channel.txRollback,然后重試發(fā)送消息略贮;如果收到了消息甚疟,那么可以提交事務channel.txCommit

// 開啟事務
channel.txSelect
try {
    // 這里發(fā)送消息
} catch (Exception e) {
    channel.txRollback

    // 這里再次重發(fā)這條消息
}

// 提交事務
channel.txCommit

但是問題是逃延,RabbitMQ 事務機制(同步)一搞览妖,基本上吞吐量會下來,因為太耗性能揽祥。

所以一般來說讽膏,如果你要確保說寫 RabbitMQ 的消息別丟,可以開啟 confirm 模式拄丰,在生產者那里設置開啟 confirm 模式之后桅打,你每次寫的消息都會分配一個唯一的 id,然后如果寫入了 RabbitMQ 中愈案,RabbitMQ 會給你回傳一個 ack 消息,告訴你說這個消息 ok 了鹅搪。如果 RabbitMQ 沒能處理這個消息站绪,會回調你的一個 nack 接口,告訴你這個消息接收失敗丽柿,你可以重試恢准。而且你可以結合這個機制自己在內存里維護每個消息 id 的狀態(tài)魂挂,如果超過一定時間還沒接收到這個消息的回調,那么你可以重發(fā)馁筐。

事務機制和 cnofirm 機制最大的不同在于涂召,事務機制是同步的,你提交一個事務之后會阻塞在那兒敏沉,但是 confirm 機制是異步的果正,你發(fā)送個消息之后就可以發(fā)送下一個消息,然后那個消息 RabbitMQ 接收了之后會異步回調你的一個接口通知你這個消息接收到了盟迟。

所以一般在生產者這塊避免數(shù)據(jù)丟失秋泳,都是用 confirm 機制的。

RabbitMQ 弄丟了數(shù)據(jù)

就是 RabbitMQ 自己弄丟了數(shù)據(jù)攒菠,這個你必須開啟 RabbitMQ 的持久化迫皱,就是消息寫入之后會持久化到磁盤,哪怕是 RabbitMQ 自己掛了辖众,恢復之后會自動讀取之前存儲的數(shù)據(jù)卓起,一般數(shù)據(jù)不會丟。除非極其罕見的是凹炸,RabbitMQ 還沒持久化戏阅,自己就掛了,可能導致少量數(shù)據(jù)丟失还惠,但是這個概率較小饲握。

設置持久化有兩個步驟

  • 創(chuàng)建 queue 的時候將其設置為持久化

    這樣就可以保證 RabbitMQ 持久化 queue 的元數(shù)據(jù),但是它是不會持久化 queue 里的數(shù)據(jù)的蚕键。
  • 第二個是發(fā)送消息的時候將消息的 deliveryMode 設置為 2

    就是將消息設置為持久化的救欧,此時 RabbitMQ 就會將消息持久化到磁盤上去。

必須要同時設置這兩個持久化才行锣光,RabbitMQ 哪怕是掛了笆怠,再次重啟,也會從磁盤上重啟恢復 queue誊爹,恢復這個 queue 里的數(shù)據(jù)蹬刷。

注意,哪怕是你給 RabbitMQ 開啟了持久化機制频丘,也有一種可能办成,就是這個消息寫到了 RabbitMQ 中,但是還沒來得及持久化到磁盤上搂漠,結果不巧迂卢,此時 RabbitMQ 掛了,就會導致內存里的一點點數(shù)據(jù)丟失。

所以而克,持久化可以跟生產者那邊的 confirm 機制配合起來靶壮,只有消息被持久化到磁盤之后,才會通知生產者 ack 了员萍,所以哪怕是在持久化到磁盤之前腾降,RabbitMQ 掛了,數(shù)據(jù)丟了碎绎,生產者收不到 ack螃壤,你也是可以自己重發(fā)的。

消費端弄丟了數(shù)據(jù)

RabbitMQ 如果丟失了數(shù)據(jù)混卵,主要是因為你消費的時候映穗,剛消費到,還沒處理幕随,結果進程掛了蚁滋,比如重啟了,那么就尷尬了赘淮,RabbitMQ 認為你都消費了辕录,這數(shù)據(jù)就丟了。

這個時候得用 RabbitMQ 提供的 ack 機制梢卸,簡單來說走诞,就是你必須關閉 RabbitMQ 的自動 ack,可以通過一個 api 來調用就行蛤高,然后每次你自己代碼里確保處理完的時候蚣旱,再在程序里 ack 一把。這樣的話戴陡,如果你還沒處理完塞绿,不就沒有 ack 了?那 RabbitMQ 就認為你還沒處理完恤批,這個時候 RabbitMQ 會把這個消費分配給別的 consumer 去處理异吻,消息是不會丟的。

rabbitmq-message-lose-solution

Kafka

消費端弄丟了數(shù)據(jù)

唯一可能導致消費者弄丟數(shù)據(jù)的情況喜庞,就是說诀浪,你消費到了這個消息,然后消費者那邊自動提交了 offset延都,讓 Kafka 以為你已經消費好了這個消息雷猪,但其實你才剛準備處理這個消息,你還沒處理晰房,你自己就掛了春宣,此時這條消息就丟咯酵颁。

這不是跟 RabbitMQ 差不多嗎,大家都知道 Kafka 會自動提交 offset月帝,那么只要關閉自動提交 offset,在處理完之后自己手動提交 offset幽污,就可以保證數(shù)據(jù)不會丟嚷辅。但是此時確實還是可能會有重復消費,比如你剛處理完距误,還沒提交 offset簸搞,結果自己掛了,此時肯定會重復消費一次准潭,自己保證冪等性就好了趁俊。

生產環(huán)境碰到的一個問題,就是說我們的 Kafka 消費者消費到了數(shù)據(jù)之后是寫到一個內存的 queue 里先緩沖一下刑然,結果有的時候寺擂,你剛把消息寫入內存 queue,然后消費者會自動提交 offset泼掠。然后此時我們重啟了系統(tǒng)怔软,就會導致內存 queue 里還沒來得及處理的數(shù)據(jù)就丟失了。

Kafka 弄丟了數(shù)據(jù)

這塊比較常見的一個場景择镇,就是 Kafka 某個 broker 宕機挡逼,然后重新選舉 partition 的 leader。大家想想腻豌,要是此時其他的 follower 剛好還有些數(shù)據(jù)沒有同步家坎,結果此時 leader 掛了,然后選舉某個 follower 成 leader 之后吝梅,不就少了一些數(shù)據(jù)虱疏?這就丟了一些數(shù)據(jù)啊。

生產環(huán)境也遇到過憔涉,我們也是订框,之前 Kafka 的 leader 機器宕機了,將 follower 切換為 leader 之后兜叨,就會發(fā)現(xiàn)說這個數(shù)據(jù)就丟了穿扳。

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

  • 給 topic 設置 replication.factor 參數(shù):這個值必須大于 1,要求每個 partition 必須有至少 2 個副本国旷。
  • 在 Kafka 服務端設置 min.insync.replicas 參數(shù):這個值必須大于 1矛物,這個是要求一個 leader 至少感知到有至少一個 follower 還跟自己保持聯(lián)系,沒掉隊跪但,這樣才能確保 leader 掛了還有一個 follower 吧履羞。
  • 在 producer 端設置 acks=all:這個是要求每條數(shù)據(jù),必須是寫入所有 replica 之后,才能認為是寫成功了忆首。
  • 在 producer 端設置 retries=MAX(很大很大很大的一個值爱榔,無限次重試的意思):這個是要求一旦寫入失敗,就無限重試糙及,卡在這里了详幽。

我們生產環(huán)境就是按照上述要求配置的,這樣配置之后浸锨,至少在 Kafka broker 端就可以保證在 leader 所在 broker 發(fā)生故障唇聘,進行 leader 切換時,數(shù)據(jù)不會丟失柱搜。

生產者會不會弄丟數(shù)據(jù)迟郎?

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市魔熏,隨后出現(xiàn)的幾起案子衷咽,更是在濱河造成了極大的恐慌,老刑警劉巖蒜绽,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镶骗,死亡現(xiàn)場離奇詭異,居然都是意外死亡躲雅,警方通過查閱死者的電腦和手機鼎姊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來相赁,“玉大人相寇,你說我怎么就攤上這事∨タ疲” “怎么了唤衫?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绵脯。 經常有香客問我佳励,道長休里,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任赃承,我火速辦了婚禮妙黍,結果婚禮上,老公的妹妹穿的比我還像新娘瞧剖。我一直安慰自己废境,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布筒繁。 她就那樣靜靜地躺著,像睡著了一般巴元。 火紅的嫁衣襯著肌膚如雪毡咏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天逮刨,我揣著相機與錄音呕缭,去河邊找鬼。 笑死修己,一個胖子當著我的面吹牛恢总,可吹牛的內容都是我干的。 我是一名探鬼主播睬愤,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼片仿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尤辱?” 一聲冷哼從身側響起砂豌,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎光督,沒想到半個月后阳距,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡结借,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年筐摘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片船老。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡咖熟,死狀恐怖,靈堂內的尸體忽然破棺而出努隙,到底是詐尸還是另有隱情球恤,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布荸镊,位于F島的核電站咽斧,受9級特大地震影響堪置,放射性物質發(fā)生泄漏。R本人自食惡果不足惜张惹,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一舀锨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宛逗,春花似錦坎匿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至屎暇,卻和暖如春承桥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背根悼。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工凶异, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挤巡。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓剩彬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矿卑。 傳聞我的和親對象是個殘疾皇子喉恋,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容