位元組跳動是怎麼做全鏈路壓測的?

語言: CN / TW / HK

背景

全鏈路壓測指的是基於實際的生產業務場景、系統環境,模擬海量的使用者請求和資料對整個業務鏈進行壓力測試,並持續調優的過程。常用於複雜業務鏈路中,基於全鏈路壓力測試發現服務端效能問題。

隨著公司業務的不斷擴張,使用者流量在不斷提升,研發體系的規模和複雜性也隨之增加。線上服務的穩定性也越來越重要 ™,服務效能問題,以及容量問題也越發明顯。為了及時暴露服務的各種穩定性問題,我們了引入了基於線上全鏈路壓測的工具、研發體系。

本文主要介紹位元組跳動的服務端全鏈路壓測體系,以及位元組跳動各種業務的全鏈路壓測實踐。

壓測方案

網路架構

  • 目的

理解業務的請求在網路中是如何流轉的,整個過程經過了哪些節點。業務請求經過的所有節點,都是壓測的物件。在壓測過程中,都需要關注其效能表現。

  • 請求流轉

下圖一個典型的網路架構,使用者請求通過 CDN 溯源,經過 TTGW,TLB,AGW,然後才到達業務服務 PSM。(TTGW 是頭條的高效能 4 層負載均衡閘道器,TLB 是七層負載均衡服務,AGW 是頭條統一業務 Api 接入層)

壓測目的與方案

在全鏈路壓測體系第一步,壓測人員必須明確壓測目的,當明確壓測目的後才能選擇一個合理的壓測方案。一個完整合理的方案可以提高全鏈路壓測效率,減少沒有意義的工作,節約了時間成本,對後續其他模組的壓測或常態化壓測提供了一定借鑑。

  • 目的:在結合業務背景前提下,使用者清晰把握明確性能測試的目的是什麼?根據不同場景分類,有著不同目的,常見的場景如下:

場景分類 主要目的 典型場景 主要特點
能力驗證 驗證在給定的軟硬體條件下,系統能否具有預期表現 當前服務已經部署了 n 臺機器,能否支援 50 萬用戶同時線上訪問

1、軟硬體環境都已經確定

2、有明確的效能目標

3、需要根據業務場景來構造壓測資料和請求

容量規劃 關注如何使系統具有我們要求的效能 春節活動需要 X 億人同時線上訪問,系統需要如何除錯?(效能優化,設計優化,資源預估)

1、它是一種探索性測試

2、常用於瞭解系統現狀

3、需要根據系統現狀,對未來系統進行一個預估和規劃

效能調優 主要用於對系統性能進行調優 系統響應越來越慢,此時該如何處理?

1、對於程式碼級的優化,單例項壓測即可

2、對於系統整體設計優化,需要叢集壓測,保證叢集負載維持在一定水位

缺陷發現重現 發現/重現效能缺陷 服務執行緒死鎖,記憶體洩漏等

1、需要對效能問題分類

2、針對每類問題構造對應的資料和壓測策略

效能基準比較 系統新版本的效能驗證 新版本的程式碼改動,是否有降低了系統性能,是否符合上線要求

1、有版本效能基準

2、固定環境因素的影響

3、AAB Diff 4、diff 置信度

壓測目標

在網路架構圖中,明確展示了各系統各司其職,它們分別負責將使用者請求做相應處理並將請求流轉至下游服務。因此,根據壓測方案的目的,選擇一個合理的壓測目標,可以減少大量的壓測工作,提高壓測效率。

目的 壓測目標 典型場景
壓測頻寬 從 CDN、TLB 處發壓 春節活動需要 X 億人同時線上訪問,鏈路頻寬是否足夠?
壓測業務邏輯 從匯聚機房、核心機房、衛星機房的 AGW 和業務服務發壓 使用者零點秒殺,是否能夠保障商品、訂單等系統一切正常?
壓測非同步訊息 從 MQ producer 處發壓 非同步訊息佇列是否能夠滿足高壓力場景?

環境隔離

在位元組內部,線下測試環境是不允許壓測的,由於線下資源不足,與線上環境差異大,壓測出來的結論並不能充分保證線上的效能情況。因此本文指的壓測都是在線上環境的壓測。下文將重點介紹位元組的全鏈路壓測環境。

壓測標記

為了區分線上流量與壓測流量,使服務可以針對壓測流量做定製業務邏輯,服務架構體系在服務框架與服務治理層面設定了壓測標記。

目的:

  • 對於框架與服務治理體系而言,壓測標記可以用於區分流量屬性,並且做相應拒絕/通過操作。

  • 對於業務服務內部而言,壓測標記可以讓業務方識別壓測流量並做相應的業務邏輯處理。

原理:

  • 通過特殊欄位 stress_tag,對壓測流量進行染色,且壓測標記對應的 value 不為空的流量。

  • 服務框架通過解析請求的 stress_tag,對介面上下文注入壓測識別符號,並透傳至下游服務,完成全鏈路壓測標記透傳。

生效條件:

  • 壓測前必須做服務改造。在全鏈路中,所有服務必須將上下文透傳至下游,保證壓測標記能被框架識別且透傳。

壓測開關

為了強化壓測流量的管理,服務治理體系引入了壓測開關的概念。壓測開關作為總控制,所有服務框架必須判斷壓測開關是否開啟,若開啟才能允許通過壓測流量,若關閉則只能拒絕壓測流量。

目的:

  • 保護線上服務,避免線上服務在沒有準備好的情況下,或不能壓測的情況,受到壓測流量的襲擊

  • 壓測緊急處理,對於線上服務負載過大時,且無法停止壓測流量時,可以通過壓測開關攔截所有壓測流量,避免出現線上故障

原理:

  • 壓測開關的表達方式是 etcd 的配置值,每個服務都會有一個特定的壓測開關 key,value 為 on 表示開啟狀態,off 為關閉狀態。儲存服務的壓測開關 key 各有不同。

  • 每個服務每個叢集都有一個壓測開關(key = psm/cluster),控制該叢集的壓測流量

  • 計算服務的壓測開關狀態都是由框架和 Mesh 來判斷的,儲存服務的壓測開關狀態則是由儲存服務的 SDK 來判斷的

  • 壓測開關沒有開啟時,壓測流量會被服務框架或儲存 SDK 拒絕

生效條件:

  • 壓測前必須開啟整條呼叫鏈中所有服務的壓測開關,否則壓測流量會被框架/SDK 拒絕。(開關可以在 Rhino 壓測平臺開啟)

儲存隔離方案

對於壓測資料的儲存,必須將線上資料與壓測資料做隔離,否則會導致壓測資料量過大影響線上資料正常存取。

目的:

  • 將壓測過程中產生的測試髒資料與線上真實資料做隔離,防止汙染線上真實儲存。

  • 儲存隔離後,可以測試出預期儲存條件下的效能。

原理:

  • 各儲存系統的 SDK 會對輸入的上下文識別壓測識別符號,若存在壓測標記,則走影子表儲存,否則走線上儲存。

  • 部分 SDK 另外提供壓測開關判斷,使用者需開啟儲存服務的壓測開關方可存到影子表中。

生效條件:

  • 壓測前必須對程式碼做相應改造,並升級至最新版本的儲存 SDK

平臺搭建

Rhino 壓測平臺

它是一個多功能壓測平臺,支援多種場景、模式的發壓。Rhino 統一管理了壓測任務、壓測資料、發壓機、壓測結果。集成了 Bytemesh、User、Trace、Bytemock、Bytecopy 等多個系統。

Rhino 壓測平臺支援以下能力

Rhino 壓測平臺
壓測協議支援 HTTP/HTTPS/protobuf/Thrift/其他所有(plugin)/TCP
發壓能力

日常發壓例項數<400,2021 春節壓測峰值 QPS=7000w

發壓機可以無限水平擴容

多機房支撐 CN/SG/US
壓測環境 支援線上線下環境壓測,支援多泳道泳道壓測
壓測資料

使用者構造 fake 資料

csv 檔案資料流量

錄製回放:錄製資料儲存在 hdfs,可以多次改寫,回放。不受時間限制

研發流量整合 接入 Devops,釋出前,對 stress 叢集進行壓測
效能 diff 支援不同壓測結果的 diff,支援 diff 壓測基線
壓測報告 客戶端監控、服務端監控、下游監控、效能 profile,告警監控,效能分析
壓測風險

壓力太大,有將服務及下游打掛的風險

壓測鏈路中存在寫介面,如果沒有改造,有資料汙染的風險

風險控制

壓測標記 & 壓測開關

鏈路梳理 & 壓測周知

告警監控自動停止壓測流量

壓測方式

Fake 資料壓測

流量錄製回放

線上單例項流量排程

壓測方式

根據不同業務的場景、以及壓測的方案,業務方需要制定不同的發壓方式,以達到壓測預期效果。下面將介紹 Rhino 平臺提供的四種發壓方式,業務方需根據自身業務特點,選擇適合的方式發壓。

Fake 流量

Fake 流量壓測是指使用者自行構造壓測請求進行壓測。Rhino 平臺支援 HTTP、Thrift 兩種協議的 Fake 流量發壓。

原理:

Fake 流量模式適合針對請求引數簡單的介面壓測,同時也適合針對特定請求進行壓測。Rhino 平臺會為每個請求注入壓測標記。

典型場景:

  • 新服務上線之前進行壓測。

  • 為了重現某種場景下造成的效能問題,構造特定引數的請求發壓。

  • 線上 http/thrift 服務已經在執行,且介面引數比較單一,快速壓測介面

  • 接入公司 passport lib 後,使用壓測賬號進行壓測

自定義外掛發壓

為了支援更多的協議與更復雜的壓測場景,Rhino 平臺支援了 GoPlugin 發壓模式。

原理:

依賴 golang 的 plugin 功能,執行時載入 plugin 檔案,並加以執行

GoPlugin 發壓模式適合靈活構造請求資料、支援自定義協議、支援自定義發壓場景,相當於所有發壓場景都可以通過程式碼實現。注意 Rhino 平臺對於 GoPlugin 模式不會注入壓測標記,使用者需在外掛內加上壓測標記。

典型場景:

  • 壓測自定義協議的服務,如 websocket、gRPC 等

  • 壓測自定義的場景,如請求一個介面後等待 2s 再次請求第二個介面、請求第一個介面對返回值做相應的計算轉換再請求第二個介面等

  • 自定義的壓測資料構造,比如從 DB、服務等獲取壓測請求資料

  • 自定義的壓測目標:比如要壓測訊息佇列,可以通過構造一個 GoPlugin 對 producer 發壓

流量錄製回放

為了使壓測更貼近線上請求,Rhino 平臺支援了流量錄製回放的發壓模式,平臺經過線上流量採集、線上流量改寫為壓測請求、壓測流量回放三個步驟,將線上請求回放到壓測目標中。

原理:

依賴 bytecopy 的採集流量能力,要求服務已經部署到線上,開啟 mesh,且有流量可以採集。

典型場景:

  • 構造壓測請求比較複雜,且服務已經上線,線上有流量可供採集

  • 壓測需要模擬線上請求的分佈,避免 hot key,如搜尋 query

  • 希望將線上流量放大 N 倍,錄製線上流量並回放到特定壓測目標

  • 希望錄製線上流量,同時執行復雜的改寫規則用於回放

流量排程

對於服務維度而言,如果想測試服務能承載多少 QPS,每個介面的 QPS 分佈情況,流量排程是一個比較合適的壓測方式。Rhino 平臺支援了單例項的流量排程模式壓測。

原理:

scheduler 修改被測例項的 consul 權重,使流量不斷打到目標例項中,而其他例項流量相應的減少,保持服務的總流量不變。壓測的請求完全來自線上流量,不使用壓測標識,因此壓測流量的流轉、儲存均保持線上模式。同時 scheduler 會監控目標例項的服務指標,當服務指標到達閾值後將停止壓測,將 consul 權重恢復至初始值。

典型場景:

  • 希望評估當前服務能夠承載多少 qps,每個介面分別承載多少 qps,可將壓測結果用於服務容量評估

  • 不希望對程式碼做壓測改造,快速增加單例項的壓力

壓測方式對比

下面將上述壓測方式在壓測目標、壓測場景、優缺點維度下做對比,方便業務方選擇合適的方式用於壓測。

壓測方法 Fake 流量壓測 (Http &Thrift) 自定義壓測(Plugin) 自定義壓測(Plugin) 流量排程
作用目標 叢集或單例項 叢集或單例項 叢集或單例項 單例項
壓測場景 單介面/多介面(場景/流量配比) 單介面/多介面(任何形式) 單介面/多介面(場景/流量配比) 服務維度
應用場景

線上/線上 http thrfit 介面

新上線的服務

壓測方案為明確性能優化計劃

線上/線上任意協議介面介面

單服務複雜壓測場景

跨多個服務混合場景

壓測資料構造複雜,要求資料多樣性強

線上資料快速壓測

單例項容量測試
缺點 壓測資料構造形式單一

對使用者程式碼能力要求較高

任務需要自行除錯

需要線上服務有流量

服務開啟 mesh 開關

線上流量充足

單例項不能線性反應整條鏈路的效能

監控

為了使壓測結果更準確、使被測服務在壓測過程中更安全,Rhino 平臺開發了一套壓測專用的報警監控體系。分為實時客戶端監控、被測服務端監控、Ms 報警監控。

實時監控

公司的服務監控體系是基於 metrics 的 30s 一次聚合,但是對於壓測任務而言,意味著觀察壓測狀態需要等待 30s 的延時,這基本上是不能忍受的。因此 Rhino 平臺支援了發壓客戶端維度的秒級監控,使使用者可以及時觀察壓測狀態,當壓測出現異常時可以立即停止壓測。

實現方案:

服務端監控

Rhino 支援服務端角度的全鏈路監控,包括服務監控、機器資源監控、上下游監控。目前使用的是 grafana 面板展示,將全鏈路每個服務 metrics、機器 influxdb 資料聚合展示到 grafana 中。未來將使用 Argos 展示服務端監控資料。

Ms 報警監控

此外,Rhino 平臺還支援監控 ms 告警規則,當被測服務或下游服務觸發了告警規則後,壓測任務便自動停止,防止造成線上事故。

實現方案:

分析&優化

最後,壓測完成後,如何分析壓測問題,並作出相應優化通常是業務方最關注的問題。下文將列舉幾種分析方法,以及常見的效能問題及優化方式。

分析方法

監控分析

可以從發壓客戶端監控、被測服務端監控發現異常,異常主要包括:

  • 尖刺現象,檢視錯誤日誌,抓請求重現

  • 壓力到達瓶頸,效能開始下降,介面延時上升,需要檢視 pprof 對各項指標做相應分析

  • 被測服務某一資源被打滿,檢視 cpu 耗時統計,找出耗時的模組

  • 流量/延時分佈不均,檢視 agw 是否正常分配流量,檢視儲存 sharding 是否正常

  • 流量/延時分佈不均,檢視 agw 是否正常分配流量,檢視儲存 sharding 是否正常

  • 協程數量大漲,且沒有下降趨勢,協程洩漏,檢查程式碼協程使用

Lidar 效能平臺

使用者可以通過 Lidar 效能分析平臺做服務的 pprof 分析,lidar 平臺支援分析 golang、python 語言的服務,分析的指標包括 cpu 使用率、記憶體使用、協程數、執行緒數、阻塞時間。一般分析 Top 使用率,如果 TopList 展示了不正常的元素,應該關注這個異常元素。

系統層 tracing 分析

  • 基於宿主機系統層面的 cpu、topN 函式分析

常見問題

  1. 服務的 CPU 陡然升高,RPC 呼叫和 consul、etcd 訪問頻繁超時,以及 goroutine 數目大漲。

  • 可能是頻繁建立 kitc client,每個呼叫建立一次。正確用法是隻初始化一次 client,重複使用

  1. 呼叫 http 介面,協程洩漏

  • 可能是 http connection 未釋放,常見的程式碼問題是 http.Body 未 Close

  1. 記憶體 RSS 一直升高,沒有下降趨勢,記憶體洩漏

  • 記憶體洩漏可以根據 pprof top list 檢視最高使用的函式/物件,並作出優化調整

  1. 效能瓶頸為寫資料庫

  • 可以嘗試加入寫 proxy 解決

  1. redis 連線超時

  • 需要增加 redis client 連線數

  1. 發壓壓力很高,但被測服務 cpu 卻一直未跑滿

  • 有可能是用到了鎖,需要 profile 排查一下

加入我們

位元組跳動環境治理與容災團隊,負責整個位元組跳動線下環境治理與效能工具建設,支援抖音、TikTok、頭條、西瓜、番茄小說、電商、遊戲、教育等眾多產品線。我們致力於通過技術中臺、與基礎架構團隊合作等方式,幫助業務提升服務端測試效率,團隊下產品包括位元組環境治理、全鏈路壓測平臺、資料構造平臺、推薦 Mock 平臺等。歡迎更多同學加入我們,構建行業頂尖的服務端工具。感興趣可以聯絡郵箱 [email protected] 並註明 環境治理與容災方向

點個在看殺個 Bug ❤