歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)
週一至週五早8點半!精品技術文章準時送上!
目錄
(1)前請提示
(2)unack訊息的積壓問題
(3)如何解決unack訊息的積壓問題
(4)高併發場景下的記憶體溢位問題
(5)低吞吐量問題
(6)合理設定prefetch count
(7)階段性總結
1、前情提示
上一篇文章:網際網路面試必殺:如何保證訊息中介軟體全鏈路資料100%不丟失(2),我們分析了ack機制的底層實現原理(delivery tag機制),還有消除處理失敗時的nack機制如何觸發訊息重發。
通過這個,已經讓大家進一步對消費端保證資料不丟失的方案的理解更進一層了。
這篇文章,我們將會對ack底層的delivery tag機制進行更加深入的分析,讓大家理解的更加透徹一些。
面試時,如果被問到訊息中介軟體資料不丟失問題的時候,可以更深入到底層,給面試官進行分析。
2、unack訊息的積壓問題
首先,我們要給大家介紹一下RabbitMQ的prefetch count這個概念。
大家看過上篇文章之後應該都知道了,對每個channel(其實對應了一個消費者服務例項,你大體可以這麼來認為),RabbitMQ投遞訊息的時候,都是會帶上本次訊息投遞的一個delivery tag的,唯一標識一次訊息投遞。
然後,我們進行ack時,也會帶上這個delivery tag,基於同一個channel進行ack,ack訊息裡會帶上delivery tag讓RabbitMQ知道是對哪一次訊息投遞進行了ack,此時就可以對那條訊息進行刪除了。
大家先來看一張圖,幫助大家回憶一下這個delivery tag的概念。
所以大家可以考慮一下,對於每個channel而言(你就認為是針對每個消費者服務例項吧,比如一個倉儲服務例項),其實都有一些處於unack狀態的訊息。
比如RabbitMQ正在投遞一條訊息到channel,此時訊息肯定是unack狀態吧?
然後倉儲服務接收到一條訊息以後,要處理這條訊息需要耗費時間,此時訊息肯定是unack狀態吧?
同時,即使你執行了ack之後,你要知道這個ack他預設是非同步執行的,尤其如果你開啟了批量ack的話,更是有一個延遲時間才會ack的,此時訊息也是unack吧?
那麼大家考慮一下,RabbitMQ他能夠無限制的不停給你的消費者服務例項推送訊息嗎?
明顯是不能的,如果RabbitMQ給你的消費者服務例項推送的訊息過多過快,比如都有幾千條訊息積壓在某個消費者服務例項的記憶體中。
那麼此時這幾千條訊息都是unack的狀態,一直積壓著,是不是有可能會導致消費者服務例項的記憶體溢位?記憶體消耗過大?甚至記憶體洩露之類的問題產生?
所以說,RabbitMQ是必須要考慮一下消費者服務的處理能力的。
大家看看下面的圖,感受一下如果消費者服務例項的記憶體中積壓訊息過多,都是unack的狀態,此時會怎麼樣。
3、如何解決unack訊息的積壓問題
正是因為這個原因,RabbitMQ基於一個prefetch count來控制這個unack message的數量。
你可以通過 “channel.basicQos(10)” 這個方法來設定當前channel的prefetch count。
舉個例子,比如你要是設定為10的話,那麼意味著當前這個channel裡,unack message的數量不能超過10個,以此來避免消費者服務例項積壓unack message過多。
這樣的話,就意味著RabbitMQ正在投遞到channel過程中的unack message,以及消費者服務在處理中的unack message,以及非同步ack之後還沒完成ack的unack message,所有這些message加起來,一個channel也不能超過10個。
如果你要簡單粗淺的理解的話,也大致可以理解為這個prefetch count就代表了一個消費者服務同時最多可以獲取多少個message來處理。所以這裡也點出了prefetch這個單詞的意思。
prefetch就是預抓取的意思,就意味著你的消費者服務例項預抓取多少條message過來處理,但是最多隻能同時處理這麼多訊息。
如果一個channel裡的unack message超過了prefetch count指定的數量,此時RabbitMQ就會停止給這個channel投遞訊息了,必須要等待已經投遞過去的訊息被ack了,此時才能繼續投遞下一個訊息。
老規矩,給大家上一張圖,我們一起來看看這個東西是啥意思。
4、高併發場景下的記憶體溢位問題
好!現在大家對ack機制底層的另外一個核心機制:prefetch機制也有了一個深刻的理解了。
此時,我們們就應該來考慮一個問題了。就是如何來設定這個prefetch count呢?這個東西設定的過大或者過小有什麼影響呢?
其實大家理解了上面的圖就很好理解這個問題了。
假如說我們把prefetch count設定的很大,比如說3000,5000,甚至100000,就這樣特別大的值,那麼此時會如何呢?
這個時候,在高併發大流量的場景下,可能就會導致消費者服務的記憶體被快速的消耗掉。
因為假如說現在MQ接收到的流量特別的大,每秒都上千條訊息,而且此時你的消費者服務的prefetch count還設定的特別大,就會導致可能一瞬間你的消費者服務接收到了達到prefetch count指定數量的訊息。
打個比方,比如一下子你的消費者服務記憶體裡積壓了10萬條訊息,都是unack的狀態,反正你的prefetch count設定的是10萬。
那麼對一個channel,RabbitMQ就會最多容忍10萬個unack狀態的訊息,在高併發下也就最多可能積壓10萬條訊息在消費者服務的記憶體裡。
那麼此時導致的結果,就是消費者服務直接被擊垮了,記憶體溢位,OOM,服務當機,然後大量unack的訊息會被重新投遞給其他的消費者服務,此時其他消費者服務一樣的情況,直接當機,最後造成雪崩效應。
所有的消費者服務因為扛不住這麼大的資料量,全部當機。
大家來看看下面的圖,自己感受一下現場的氛圍。
5、低吞吐量問題
那麼如果反過來呢,我們要是把prefetch count設定的很小會如何呢?
比如說我們把prefetch count設定為1?此時就必然會導致消費者服務的吞吐量極低。因為你即使處理完一條訊息,執行ack了也是非同步的。
給你舉個例子,假如說你的prefetch count = 1,RabbitMQ最多投遞給你1條訊息處於unack狀態。
此時比如你剛處理完這條訊息,然後執行了ack的那行程式碼,結果不幸的是,ack需要非同步執行,也就是需要100ms之後才會讓RabbitMQ感知到。
那麼100ms之後RabbitMQ感知到訊息被ack了,此時才會投遞給你下一條訊息!
這就尷尬了,在這100ms期間,你的消費者服務是不是啥都沒幹啊?
這不就直接導致了你的消費者服務處理訊息的吞吐量可能下降10倍,甚至百倍,千倍,都有這種可能!
大家看看下面的圖,感受一下低吞吐量的現場。
6、合理的設定prefetch count
所以鑑於上面兩種極端情況,RabbitMQ官方給出的建議是prefetch count一般設定在100~300之間。
也就是一個消費者服務最多接收到100~300個message來處理,允許處於unack狀態。
這個狀態下可以兼顧吞吐量也很高,同時也不容易造成記憶體溢位的問題。
但是其實在我們的實踐中,這個prefetch count大家完全是可以自己去壓測一下的。
比如說慢慢調節這個值,不斷加大,觀察高併發大流量之下,吞吐量是否越來越大,而且觀察消費者服務的記憶體消耗,會不會OOM、頻繁FullGC等問題。
7、階段性總結
其實通過最近幾篇文章,基本上已經把訊息中介軟體的消費端如何保證資料不丟失這個問題剖析的較為深入和透徹了。
如果你是基於RabbitMQ來做訊息中介軟體的話,消費端的程式碼裡,必須考慮三個問題:手動ack、處理失敗的nack、prefetch count的合理設定
這三個問題背後涉及到了各種機制:
自動ack機制
delivery tag機制
ack批量與非同步提交機制
訊息重發機制
手動nack觸發訊息重發機制
prefetch count過大導致記憶體溢位問題
prefetch count過小導致吞吐量過低
這些底層機制和問題,我們們都一步步分析清楚了。
所以到現在,單論消費端這塊的資料不丟失技術方案,相信大家在面試的時候就可以有一整套自己的理解和方案可以闡述了。
接下來下篇文章開始,我們就來具體聊一聊:訊息中介軟體的生產端如何保證資料不丟失。
end
如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!
一大波微服務、分散式、高併發、高可用的原創系列文章正在路上
歡迎掃描下方二維碼,持續關注:
石杉的架構筆記(id:shishan100)
十餘年BAT架構經驗傾囊相授
推薦閱讀:
2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?
3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰
6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問
7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍
9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?
11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?
16、億級流量系統架構之如何設計全鏈路99.99%高可用架構
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進階面試系列之三】哥們,訊息中介軟體在你們專案裡是如何落地的?
29、【Java進階面試系列之四】扎心!線上服務當機時,如何保證資料100%不丟失?
30、一次JVM FullGC的背後,竟隱藏著驚心動魄的線上生產事故!
31、【高併發優化實踐】10倍請求壓力來襲,你的系統會被擊垮嗎?
32、【Java進階面試系列之五】訊息中介軟體叢集崩潰,如何保證百萬生產資料不丟失?
33、億級流量系統架構之如何在上萬併發場景下設計可擴充套件架構(上)?
34、億級流量系統架構之如何在上萬併發場景下設計可擴充套件架構(中)?
35、億級流量系統架構之如何在上萬併發場景下設計可擴充套件架構(下)?
37、億級流量系統架構之如何保證百億流量下的資料一致性(上)
38、億級流量系統架構之如何保證百億流量下的資料一致性(中)?
39、億級流量系統架構之如何保證百億流量下的資料一致性(下)?
40、網際網路面試必殺:如何保證訊息中介軟體全鏈路資料100%不丟失(1)
41、網際網路面試必殺:如何保證訊息中介軟體全鏈路資料100%不丟失(2)
作者:石杉的架構筆記 連結:juejin.im/post/5c263a… 來源:掘金 著作權歸作者所有,轉載請聯絡作者獲得授權!