【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

石杉的架構筆記發表於2018-12-19

歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)

週一至週五早8點半!精品技術文章準時送上!


一、寫在前面

上篇文章「Java進階面試系列之三」訊息中介軟體在你們專案裡是如何落地的?,我們用一個簡單易懂的電商場景給大家引入說明了一個訊息中介軟體的使用場景。

同時,我們還基於RabbitMQ的HelloWorld級別的程式碼,給出了訂單服務和倉儲服務如何基於MQ中介軟體收發訊息的示例。


二、業務場景回顧

這篇文章,我們來稍微深入探討一些MQ中介軟體使用中的基礎技術問題。

首先回顧一下上篇文章做出來的一個架構圖,看看訂單服務和訊息服務是如何基於MQ來收發訊息的。

我們稍微把這個圖細化一點,簡單來說就是多個訂單服務例項給queue推送訊息,多個倉儲服務每個消費一部分訊息。如下圖所示:

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

三、意外當機,問題凸現

假如你線上對MQ技術的使用就到此為止了,那麼基本可以跟offer說拜拜了。。。

因為如果是我的話,作為一個面試官就沒法繼續往下問了。你這個MQ的使用以及理解的深度僅此而已的話,那基本就是剛剛對MQ技術入門的程度。

如果面試官要繼續問,完全可以問下面的問題:

  • 那你說說如果倉儲服務作為消費者服務,剛收到了一個訂單訊息,但是在完成訊息的處理之前,也就是還沒對訂單完成倉儲排程發貨,結果這個倉儲服務突然就當機了,這個時候會發生什麼事情?


所以說,大家還是要對這個技術瞭解的稍微深入一點點,否則隨便被問幾個問題就完蛋了。

大夥兒先來看看下面的圖,感受一下車禍現場。

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

RabbitMQ這個中介軟體預設的一個行為,就是隻要倉儲服務收到一個訂單訊息,RabbitMQ就會立馬把這條訂單訊息給標記為刪除,這個行為叫做自動ack,也就是投遞完成一條訊息就自動確認這個訊息處理完畢了。

但是接著如果此時倉儲服務收到了一個訂單訊息,但是還沒來得及對倉庫系統完成商品的排程發貨,結果直接就當機了。

此時,明顯這個訂單訊息就丟失了啊,因為RabbitMQ那裡已經沒有了。。。

這會導致什麼樣的尷尬體驗呢?就是一個使用者支付了8999元,對一個iphone8下了訂單,結果呢,死等活等了好幾天,就是不見網站上顯示他的iphone8在發貨。

搞了半天,原因就是他的那個iphone8的訂單在倉儲服務那裡,還沒來得及排程發貨直接就當機了,導致這個訂單訊息就一直丟失了,始終沒有給這個使用者通知倉庫系統進行發貨。

這個問題,是不是很尷尬?所以說,技術問題是會嚴重影響企業的核心業務流程的!

各位小夥伴,還記得上一講我們們的倉儲服務消費訊息的程式碼中,有一行關鍵的程式碼:

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

這行程式碼對channel.basicConsume()方法,傳入的第二個引數:true,其實就是一個關鍵的引數。

這個true就代表了一個核心的含義,他的意思是,RabbitMQ只要把一個訊息投遞到倉儲服務手上,立馬就標記這個訊息刪除了。

但是在這個預設的配置之下,要是倉儲服務收到一個訂單訊息,結果還沒來得及完成耗時幾十秒的倉儲排程發貨的業務邏輯,結果突然當機了,那麼這個訂單訊息就永久性丟失了!

找了半天,原來問題的癥結在這裡啊!大家是不是明白了,上一篇文章最後為什麼我會說,這個程式碼目前為止還有很多的問題。

所以這個時候,我們如果希望不要因為倉儲服務的突然當機導致一條訂單訊息丟失,就需要改造一下倉儲服務消費訊息的程式碼了。

首先,我們需要把那個引數從true改為false,如下程式碼所示:

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

只要修改為false之後,RabbitMQ就不會盲目的投遞訊息到倉儲服務,立馬就刪除訊息了,說白了就是關閉autoAck的行為,不要自作主張的認為訊息處理成功了。

接著,我們需要改造一下處理訂單訊息的程式碼,如下程式碼所示。

這段程式碼,說白了,就是在對訂單完成了排程發貨之後,在finally程式碼塊中手動執行了ack操作,說我自己已經完成了耗時幾十秒的業務邏輯的處理,現在可以手動ack通知RabbitMQ,這個訊息處理完畢了。

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

此時整個架構執行流程大致看起來跟下面的圖那樣子。

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

架構流程改成上面那樣後,就意味著只有完成了倉儲排程發貨的程式碼業務邏輯,確保倉庫系統收到通知之後,倉儲服務才會在程式碼中手動傳送ack訊息給RabbitMQ。

此時,RabbitMQ收到了這個ack訊息,才會標記對應的訂單訊息被刪除了。

如果說在倉儲服務收到了訂單訊息,但是還沒來得及完成倉儲排程發貨的業務邏輯,那也就絕對不會執行這條訂單訊息的ack操作,然後RabbitMQ也就不會收到這條訂單訊息的ack通知。

一旦RabbitMQ發現代表消費者的某個倉儲服務例項突然當機了,而這個倉儲服務收到的一些訂單訊息還沒來得及處理,沒給自己傳送那些訊息的ack通知。

此時,RabbitMQ會自動對這條訂單訊息重發推送給其他在執行中的倉儲服務例項,讓其他的倉儲服務例項去處理這條訂單訊息。

這樣的話,就可以保證這條訂單訊息不會因為某個倉儲服務例項的當機而丟失,他會確保必須由某個倉儲服務例項完成這條訂單訊息的排程發貨處理,然後才會刪除那條訂單訊息。


四、總結 tips

最後再來一張圖,大家直觀的感受一下:

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

好了,各位同學,這篇文章是不是相對稍微深入一點點,讓大家瞭解到了一些使用MQ技術時候要考慮的一些問題?

實際上無論是RocketMQ、Kafka還是RabbitMQ,都有類似的autoAck或者是手動ack的機制。

線上生產環境中執行時,你必須要考慮到消費者服務可能當機的問題。

如果消費者服務沒處理完訊息就自己當機了,那麼一定會導致部分訊息的丟失,進而影響核心業務流程的運轉。

因此大家線上上使用MQ時,一定要充分考慮這些潛在問題,同時結合具體的MQ提供的一些API、引數來進行合理設定,確保訊息不要隨意丟失。

END


如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!


一大波微服務、分散式、高併發、高可用的原創系列文章正在路上

歡迎掃描下方二維碼,持續關注:

【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?【石杉的架構筆記】

石杉的架構筆記(id:shishan100)

十餘年BAT架構經驗傾囊相授


推薦閱讀:

1、拜託!面試請不要再問我Spring Cloud底層原理

2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?

3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰

4、微服務架構如何保障雙11狂歡下的99.99%高可用

5、兄弟,用大白話告訴你小白都能聽懂的Hadoop架構原理

6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問

7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍

8、拜託,面試請不要再問我TCC分散式事務的實現原理坑爹呀!

9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?

10、拜託,面試請不要再問我Redis分散式鎖的實現原理!

11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?

12、億級流量系統架構之如何支撐百億級資料的儲存與計算

13、億級流量系統架構之如何設計高容錯分散式計算系統

14、億級流量系統架構之如何設計承載百億流量的高效能架構

15、億級流量系統架構之如何設計每秒十萬查詢的高併發架構

16、億級流量系統架構之如何設計全鏈路99.99%高可用架構

17、七張圖徹底講清楚ZooKeeper分散式鎖的實現原理

18、大白話聊聊Java併發面試問題之volatile到底是什麼?

19、大白話聊聊Java併發面試問題之Java 8如何優化CAS效能?

20、大白話聊聊Java併發面試問題之談談你對AQS的理解?

21、大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?

22、大白話聊聊Java併發面試問題之微服務註冊中心的讀寫鎖優化

23、網際網路公司的面試官是如何360°無死角考察候選人的?(上篇)

24、網際網路公司面試官是如何360°無死角考察候選人的?(下篇)

25、Java進階面試系列之一:哥們,你們的系統架構中為什麼要引入訊息中介軟體?

26、【Java進階面試系列之二】:哥們,那你說說系統架構引入訊息中介軟體有什麼缺點?

27、【行走的Offer收割機】記一位朋友斬獲BAT技術專家Offer的面試經歷

28、【Java進階面試系列之三】哥們,訊息中介軟體在你們專案裡是如何落地的?



相關文章