架構(gòu)設(shè)計消息篇之消息丟失

前言

這篇文章我們討論一下消息中間件如何保證消息不丟失敢会,其實這是分布式系統(tǒng)面臨的一個基本問題曾沈。
分布式系統(tǒng)必然涉及網(wǎng)絡(luò)數(shù)據(jù)傳輸和數(shù)據(jù)存儲,在傳輸方面數(shù)據(jù)會面臨網(wǎng)絡(luò)異常鸥昏,
在存儲方面數(shù)據(jù)會面臨單點故障塞俱、磁盤損壞以及服務(wù)重啟等故障,從而導(dǎo)致數(shù)據(jù)丟失吏垮。
所以障涯,如何確保數(shù)據(jù)不丟失便成了所有分布式系統(tǒng)面臨的一個基本問題罐旗。
接下來,我們以消息中間件為例唯蝶,首先討論一下消息丟失的原因尤莺,然后討論它的解決方案,最后我們在簡單了解一下Kafka具體是如何解決消息丟失的問題生棍。

問題

avatar

上圖是最簡單的消息生產(chǎn)與消費模型圖,圖中生產(chǎn)者表示消息的發(fā)送方媳谁,消費者表示消息的接受方涂滴,箭頭表示的是網(wǎng)絡(luò)連接,中間的消息中間件用于傳輸和存儲消息晴音。
我們知道柔纵,當(dāng)消息從生產(chǎn)者發(fā)送到消息中間件的過程中,可能會因網(wǎng)絡(luò)問題導(dǎo)致消息發(fā)送失敗锤躁,如果沒有其它措施搁料,那么消息就會丟失。
即使消息成功到達消息中間件系羞,也會因為存儲方面的問題郭计,導(dǎo)致消息丟失,比如:不對消息持久化處理而是只存在內(nèi)存中椒振,那么服務(wù)重啟便會導(dǎo)致消息丟失昭伸,即使做持久化處理存儲在磁盤,也有可能因磁盤故障導(dǎo)致消息丟失澎迎。
退一步說庐杨,如果傳輸和存儲都正常,那么也會因為消費機制的問題夹供,導(dǎo)致消息丟失灵份,比如:消息中間件向消費者投遞消息但消費者還未確認消息時就將數(shù)據(jù)刪除或更新消息的消費偏移量。

所以哮洽,任意一款消息中間件無論是Kafka填渠、Rabbitmq還是RocketMQ,為了保證消息不丟失袁铐,都必須處理這三方面的問題:網(wǎng)絡(luò)揭蜒、存儲、消費機制剔桨。

方案

針對以上三個方面的問題屉更,各消息中間件解決問題的邏輯都是一樣的,都是采用確認機制解決網(wǎng)絡(luò)傳輸?shù)膯栴}洒缀,采用持久化和副本解決存儲的問題瑰谜,采用提交機制解決消費機制方面的問題欺冀。
下面,我們分別來看一下對應(yīng)問題的解決方案萨脑。

確認機制
avatar

從上面的問題分析中隐轩,我們已經(jīng)知道:生產(chǎn)者將消息發(fā)往消息中間件的過程中,可能會因網(wǎng)絡(luò)問題導(dǎo)致消息丟失渤早;
之所以說可能丟失职车,是因為一次完整的消息發(fā)送過程包含發(fā)送和響應(yīng)二個階段,如果消息在發(fā)送階段發(fā)生網(wǎng)絡(luò)異常鹊杖,那么消息會丟失悴灵,但如果消息在響應(yīng)階段出現(xiàn)網(wǎng)絡(luò)異常,那么消息未必丟失骂蓖。
因此积瞒,為了保證消息不丟失,可能的解決方式有兩種:第一登下、出現(xiàn)異常時重新發(fā)送消息不管消息之前是否發(fā)送成功茫孔,第二、出現(xiàn)異常時先查詢消息狀態(tài)然后再根據(jù)情況選擇是否重試被芳。
因為缰贝,消息的數(shù)據(jù)量不是很大,所以一般情況下消息中間件會選擇第一種方式:當(dāng)生產(chǎn)者沒有收到消息中間件(接收者)的確認回復(fù)(ACK)時筐钟,生產(chǎn)者就不斷地進行重試揩瞪,直到收到ACK或者重試超過一定的閥值為止。
ACK是一種消息發(fā)送確認機制——發(fā)送者和接收者約定篓冲,在消息發(fā)送過程中李破,如果接收者收到了某條信息,那么就向發(fā)送者回復(fù)一個ack字段壹将,用該字段用來標(biāo)示消息是否成功被接收者處理或存儲嗤攻。

持久化

通過確認機制我們可以確保消息可以成功到達消息中間件,但如果消息中間件存儲消息的方式是采用內(nèi)存诽俯,或者是異步定時持久化到磁盤妇菱,那么消息也是有可能丟失的。
因為暴区,當(dāng)服務(wù)器重啟時闯团,內(nèi)存中的數(shù)據(jù)便會丟失,即使是異步刷盤也會造成部分數(shù)據(jù)來不及持久化而丟失仙粱,之所以將消息存在內(nèi)存中是為了提高消息發(fā)送和消費的處理效率房交。
因此,為了保證數(shù)據(jù)(消息)不在消息中間件中丟失同時又能保證消息的發(fā)送和消費效率伐割,大多數(shù)消息中間件以及數(shù)據(jù)庫都會采用追加日志的方式順序地將變化的數(shù)據(jù)先寫入到日志文件中候味。
這樣刃唤,通過順序地將數(shù)據(jù)寫入日志文件中,既保證了數(shù)據(jù)持久化也保證了數(shù)據(jù)處理的效率白群。

副本

雖然持久化可以保證發(fā)送成功的消息不丟失尚胞,但是如果出現(xiàn)磁盤損壞或者單點故障的情況,那么相當(dāng)于消息丟失了帜慢。
因此笼裳,在其它服務(wù)器上冗余相應(yīng)的數(shù)據(jù),便成了分布式數(shù)據(jù)庫軟件粱玲,解決單點故障的唯一方案侍咱。
實現(xiàn)方式有兩種一種是客戶端往不同的數(shù)據(jù)服務(wù)器發(fā)送同一份數(shù)據(jù),直到這些服務(wù)器都收到為止密幔;另一個方式是將數(shù)據(jù)發(fā)往集群中的Leader節(jié)點,然后由Leader同步到Follower中撩轰,然后再響應(yīng)客戶端的請求胯甩。
其中第二種方式是主流的數(shù)據(jù)副本的處理方式,其實現(xiàn)原理也很簡單堪嫂,如下圖所示:

avatar

當(dāng)消息中間件中的Leader節(jié)點收到Producer發(fā)過來的消息后偎箫,它會將該消息同步給它的Follower節(jié)點,當(dāng)所有的Follower節(jié)點都收到了同步的數(shù)據(jù)后皆串,Leader便響應(yīng)Producer的請求淹办。
當(dāng)然,同步的Follower數(shù)量以及是同步進行還是異步恶复,這些要根據(jù)實際情況來決定怜森。

提交機制

當(dāng)保證了消息在生產(chǎn)者和消息中間件中不會丟失后,最后我們還需要保證在消費者消費消息的時候消息也"不丟失"谤牡。
這里的不丟失副硅,其實是每一條消息都要能被消費者消費不能出現(xiàn)遺漏,這就和具體中間件的消費機制有關(guān)翅萤。
最常見的一種消息消費機制恐疲,是通過Offset來維護消費者消費消息的進度。
比如說套么,消息中間件中有一個消息隊列A培己,里面有從0到100編好序號的100條消息,有一個消費者B胚泌,它要從隊列中獲取消息省咨;
假設(shè),在沒有Offset的情況诸迟,消費者B從0開始每次拉取一條處理一條茸炒,當(dāng)它拉去到50時愕乎,此時消費者B掛了,重啟之后從什么地方開始壁公?
也許你會說記錄一下消息的消費進度感论?對,這個消費進度就是Offset紊册,但它不能由消費者進行維護而是由消息中間件進行維護比肄。
那么接著的問題便是,消息中間件在什么時候跟新Offset呢囊陡?如果在消息中間件將消息投遞給消費者后芳绩,但消費者還未處理之前,消息中間件就跟新offset撞反,
那么在消費者掛了重啟后妥色,就會出現(xiàn)某些消息沒有消費到的情況。顯然遏片,只能將Offset的更新即提交Offset的權(quán)限交給消費者嘹害,這樣消費者消費完數(shù)據(jù)后主動請求更新Offset便不會導(dǎo)致消息消費不到的情況出現(xiàn)。

Kafka

Kafka的配置中有一配置項spring.kafka.producer.acks吮便,它有三個可選值如下所示:
ack=0:相當(dāng)于不需要消息確認笔呀,發(fā)出去之后就不管Broker是否收到,哪怕網(wǎng)絡(luò)異常丟失也不管髓需。
ack=1(默認):只要Leader節(jié)點收到了消息许师,就返回ACK,不管Follower有沒有收到僚匆。
ack=-1(ALL):要求Leader和所有正常的Follower都收到微渠,才放回ACK。

Kafka的Offset提交機制有兩種方式咧擂,一種是自動提交敛助,一種是手動提交。
自動提交是在一定時間間隔后屋确,Kafka客戶端將當(dāng)前消費者的Offset進度纳击,在后端自動提交給Broker,這不僅會存在消息丟失的可能攻臀,而且還有可能導(dǎo)致消息被重復(fù)消費焕数。
因此,對消息丟失敏感的應(yīng)用都會選擇手動提交刨啸,雖然也有可能導(dǎo)致消息重復(fù)消費堡赔,但最少可以保證消息沒有丟失的可能。

Kafka在持久化和副本方面的處理方式设联,大致的邏輯上面已經(jīng)提到過了善已,具體實現(xiàn)細節(jié)比較復(fù)雜灼捂,由于篇幅有限就不詳細細說了。

總結(jié)

為了保證消息不丟失换团,那么生產(chǎn)者在消息發(fā)送的時候需要有確認機制悉稠,消費者在消費消息的時候需要有提交機制,以及消息中間件需要對消息做持久化處理以及采用多副本策略存儲消息艘包,這樣就可以保證絕大多數(shù)的消息是不會丟失的的猛。
之所以說絕大多少,是因為消息在生產(chǎn)者這邊如果采用的是異步的方式而且沒有做持久化存儲想虎,那么消息也是有丟失的可能的卦尊。

擴展閱讀

架構(gòu)設(shè)計思維篇之結(jié)構(gòu)

架構(gòu)設(shè)計思維篇之概念

架構(gòu)設(shè)計容錯篇之重試

架構(gòu)設(shè)計容錯篇之熔斷

架構(gòu)設(shè)計容錯篇之限流

架構(gòu)設(shè)計事務(wù)篇之Mysql事務(wù)原理

架構(gòu)設(shè)計事務(wù)篇之CAP定理

架構(gòu)設(shè)計事務(wù)篇之分布式事務(wù)

架構(gòu)設(shè)計消息篇之消息丟失

架構(gòu)設(shè)計消息篇之保證消息順序性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市舌厨,隨后出現(xiàn)的幾起案子岂却,更是在濱河造成了極大的恐慌,老刑警劉巖裙椭,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淌友,死亡現(xiàn)場離奇詭異葵腹,居然都是意外死亡,警方通過查閱死者的電腦和手機砂蔽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門纷纫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人止吐,你說我怎么就攤上這事。” “怎么了婿崭?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肴颊。 經(jīng)常有香客問我氓栈,道長,這世上最難降的妖魔是什么婿着? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任授瘦,我火速辦了婚禮,結(jié)果婚禮上竟宋,老公的妹妹穿的比我還像新娘提完。我一直安慰自己,他們只是感情好丘侠,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布徒欣。 她就那樣靜靜地躺著,像睡著了一般蜗字。 火紅的嫁衣襯著肌膚如雪打肝。 梳的紋絲不亂的頭發(fā)上脂新,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天,我揣著相機與錄音粗梭,去河邊找鬼争便。 笑死,一個胖子當(dāng)著我的面吹牛楼吃,可吹牛的內(nèi)容都是我干的始花。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼孩锡,長吁一口氣:“原來是場噩夢啊……” “哼酷宵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起躬窜,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤浇垦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荣挨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體男韧,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年默垄,在試婚紗的時候發(fā)現(xiàn)自己被綠了此虑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡口锭,死狀恐怖朦前,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鹃操,我是刑警寧澤韭寸,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站荆隘,受9級特大地震影響恩伺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜椰拒,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一晶渠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧燃观,春花似錦乱陡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春爽彤,著一層夾襖步出監(jiān)牢的瞬間养盗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工适篙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留往核,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓嚷节,卻偏偏與公主長得像聂儒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子硫痰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容