服務中有“推”有“拉”,該如何分析線上問題?

haolujun發表於2018-01-04

背景

隨著佇列技術越來越成熟,很多公司都把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分位(具體可上下浮動)。
    這裡只是引數設定建議,實際工作中需要根據具體情況具體分析。但是總體應該遵循:在使用者容忍響應時間內達到吞吐量最大化。

總結

遇到線上問題時最忌慌亂,人在慌亂的時候通常會採取錯誤的處理方式,加劇問題的影響面,所以理智應該排在第一位。希望每個小夥伴都不會遇到突發的線上問題,但是問題來了我們也不怕線上問題。

相關文章