背景
隨着隊列技術越來越成熟,很多公司都把MQ放入其技術棧中,線上也基本都運行着該組件。接下來我們一起討論下,當使用MQ后,你該如何分析線上問題?這里給出兩個名詞解釋,“推”:指常用的RPC調用,“拉”:使用隊列進行消息傳遞。
示例架構
如上圖一個普通的服務架構,圖中有多個要素,下面對這幾個要素進行詳細說明。
- 用戶 網站的使用者,他會有奇怪的行為:當遲遲看不到結果頁面時,會反復刷新瀏覽器。
- webserver 與用戶進行交互的服務。它把用戶請求寫入mq,並從redis/DB中讀取結果渲染成頁面返回給用戶。
- 隊列 緩沖用戶請求,方便下游服務橫向擴展。
- consumer 消息的消費者。它會有一些處理邏輯:調用(本例使用的rpc是thrift)下游的服務(worker)完成一些計算型任務,把最終處理結果寫入redis/DB中。 consumer調用下游的服務有超時時間設置,如果下游服務在指定timeout時間內沒有返回結果,consumer會選擇(隨機或者順序)其它服務重試。
- worker 本例是一些計算型服務,會消耗cpu。
這個是典型的線上系統:某些地方使用隊列緩沖請求,但由於歷史問題、技術風險、實現復雜性高等原因又不能使每個服務都用隊列串聯。我們用這個架構進行說明,看看當出現如下問題時,會從監控上看到什么樣的表現?系統又會有哪些違反常理的行為?而我們又該如何分析問題。
用戶請求量過大,worker計算能力跟不上
- 現象1: 通過監控看worker的cpu,使用率接近100%。
- 現象2:查看consumer日志,發現大量的請求超時。
20分鍾內有1K+多超時錯誤,后端服務處於“崩潰臨界點”邊緣。 - 現象3:隊列中tot(ready+unack)數會突增(淺藍色)。
“相對論”與“系統崩潰臨界點”
就如物理學相對論中的“運動的尺子會變短”,我們提出計算機系統中的“相對論”:對於一個系統,當並發請求量變大時,每個請求的處理時間會變長。
我們利用“相對論”就能推導出每個二級系統都有崩潰臨界點:兩個服務A,B都遵循相對論,A調用B有超時重試策略;當A加大調用B的並發量后,B遵循“相對論”會使得每個請求的處理時間都變長。當請求量大到一定值后,B服務的處理時間會超過設定的“超時時間”,此時系統中就只有重試請求,並且每次請求都超時,這個“一定值”就是系統崩潰臨界點。
本例展示的這種情況,總體來說對外造成的影響不嚴重,系統壓力已經達到最大,接近崩潰邊緣但是沒有引發雪崩,因為還沒有造成用戶頻繁刷新行為:橙色那條線(用戶請求速率)比較平穩。這個時候只需要增加worker的機器數即可。
consumer數過少,消費跟不上
這種情況分析起來稍微復雜,監控結果比較詭異。
- MQ監控中橙色那條線(代表用戶請求速率)突增,並且此刻隊列中積壓的消息數也很大(綠色的柱狀圖)。
- 觀察consumer日志,請求超時數很少。
10分鍾內只有6次超時,和請求基數比較可以忽略不計,應該不是后端性能處理跟不上。為了確認,順便看看后端的cpu使用率,如下圖。 - 后端woker的cpu使用率並沒有達到100%。
cpu使用率為75%,離崩潰時100%還相差25%。
雞生蛋還是蛋生雞
這種情況下,通常會有兩個結論:
- 雞生蛋:由於用戶請求突然增加(未知原因),系統處理能力跟不上瞬時增加請求,消息大量積壓在隊列中。
這種結論通常都是第一反應,如果不仔細思考可能就會把這種結論作為最終結論,並且輕輕松松把鍋踢給了用戶群體,何樂而不為? - 蛋生雞:由於系統某些環節達到瓶頸,造成消息處理的速率跟不上用戶的請求速率,消息積壓過多;而消息積壓過多,又導致系統對用戶的響應變慢(主要是對后進入到隊列中的消息的響應),超過了用戶忍受的時間,用戶采取頻繁刷新瀏覽器行為;用戶頻繁刷新又造成隊列中進入的消息速率瞬間提高,而提高的速率又加劇消息的積壓,導致更多用戶采取刷新行為......滾雪球一般。
這是比較冷靜不怕承擔責任的分析,自己挖的坑跪着也要填完。
這兩個結論到底孰對孰錯?顯然,第二種結論是對的。
第一種為啥是錯的咧?
如果是第一種情況,系統某些地方肯定會表現出異常,諸如超時異常、cpu飆高異常,而本例中統統木有。
第二種為啥是對的咧?
- 首先看MQ的積壓消息數(綠色柱狀圖),用戶采取刷新行為前(橙色線突增之前)積壓的消息數是逐漸增加的(前期預兆,系統某個地方有瓶頸),消息積壓過多后導致后進入的請求得到響應的時間變慢(隊列基本上是先進先出策略),這部分用戶不能忍受長時間等待便采取刷新行為(橙色線突增),與我們的理論分析一致。
- 其次觀看下游服務的cpu,使用率沒有因為用戶頻繁刷新而瞬間飆高(如果系統沒有瓶頸,突增的的流量會使cpu瞬間飆高到100%)。
- 綜上所述,可以推測系統瓶頸在MQ之后,在后端服務之前,這中間的服務只有consumer,最后的結論是consumer數太少。
如何設置服務參數?
- consumer數:壓力測試時,能夠把后端cpu使用率壓到90+%並且不會有大量超時異常為止。
- timeout:壓力測試時,cpu使用率到90%+,統計單次請求時間分布,取90分位(具體可上下浮動)。
這里只是參數設置建議,實際工作中需要根據具體情況具體分析。但是總體應該遵循:在用戶容忍響應時間內達到吞吐量最大化。
總結
遇到線上問題時最忌慌亂,人在慌亂的時候通常會采取錯誤的處理方式,加劇問題的影響面,所以理智應該排在第一位。希望每個小伙伴都不會遇到突發的線上問題,但是問題來了我們也不怕線上問題。