穩定性是技術團隊的命根子,滴滴也在搞全鍊路壓測了。雖然才四五年,滴滴内部已經有了衆多系統,而且号稱四大語言,八大架構,改造成本可想而知。
如何做到釜底抽薪,支援線上環境的全鍊路壓測?而且與一般電商不同,滴滴的交易是實時的,乘客發單,附近需要有司機能立即接單,順風車尤為複雜,研發壓測工具又面臨着怎樣的挑戰?
滴滴出行創立于 2012 年,是全球領先的一站式多元化出行平台。經曆過各種燒錢補貼大戰、多次合并,滴滴成為繼阿裡之後,國内第二個日訂單量超過千萬的公司。

2016 年的滴滴,正在經曆這樣的階段,一方面日單量從百萬沖到千萬,另一方面 IT 系統屢次出現線上故障,穩定性建設成為支撐業務發展的重要保障。在此背景下,滴滴啟動了全鍊路壓測項目。
壓測方案
滴滴的業務與普通電商差别較大,一次典型的使用者打車流程是這樣的:乘客發單,0-3 分鐘内派給附近的司機,司機搶單後,去接乘客,到達目的地。這不但要求司乘的位置相近,而且交易必須是實時的。
基于滴滴業務的特殊性,同時借鑒了業内的經驗,我們制定了滴滴的全鍊路壓測方案,一句話描述就是:線上上環境,針對全業務核心鍊路,以資料隔離的方式進行壓測,如下圖所示:
線上環境
基于阿裡等公司之前的經驗,壓測線上上環境進行,線上最大的優點就是環境真實,不需要擔心配置不一緻、結果是否可以同比例放大等問題,壓測的結果自然也更為精确。
但線上上做壓測,需要保證安全性,風險不言而喻:不能搞垮線上系統。這就需要将壓測的時間視窗限定在低峰期;監控必須給力,在系統出現單點故障前,要能夠提前預警,萬一真的出現故障,必須緊急停止壓力,最短時間内進行恢複。
全業務核心鍊路
它支援計程車、專車、快車、順風車等幾個主要的業務線,覆寫主要的業務場景,以計程車為例,從乘客打開 APP 輸入上車點、目的地、發單,到司機出車、搶單、接乘客上車、到達目的地,甚至取消訂單等完整流程。
流程圖如下所示:
資料隔離
壓測方案的核心是資料隔離,需要做到壓測司乘要與真實司乘區分,壓測訂單不能與真實訂單混淆,絕不能把真實乘客的單派給虛拟司機等問題。
下面将專門介紹壓測的資料隔離方案。
01資料隔離方案
與其談隔離方案,不如讓我們想象幾種資料隔離不好的場景:
- 某真實司機的曆史訂單突然多了一些假訂單,積分、券、餘額等出錯。
- 某真實乘客的訂單被派給了虛拟司機,乘客一直在等待司機來接。
- 某城市的 BI 報表出錯,莫名其妙的多了一些訂單,貌似财務也對不上。
- 某城市的運力估計及動調出現異常波動。
- 清理虛拟訂單及相關資料時,不小心誤删了真實訂單和資料......
虛拟訂單方案
隔離不好的場景,光是想想就不寒而栗,可以讓我們輕易排除這種看似最簡單的方案:使用真實司機乘客,發送虛拟訂單。
虛拟訂單通過 ID 或者标志字段進行區分,派單時做特殊處理。這種方式對業務有較大的侵入性,不僅是修改派單那麼簡單,還需要從各個次元适時地屏蔽司乘與虛拟訂單的關系,如訂單曆史、通知推送、積分統計等,不但多而且是強依賴,顯然不是一種合理的方案。
提升虛拟的層次
每個城市啟用一批虛拟的乘客,發送虛拟訂單,派發給虛拟司機,司乘及訂單上通過 ID 或者标志字段進行區分。
這可以解決司乘及訂單強依賴的問題。但從城市的角度看,需要隔離真實司乘與虛拟司乘,又會涉及到城市的動态調價、供需預測、BI 統計等各個方面的隔離。
再提升虛拟的層次
與傳統電商不同,Uber、滴滴這樣的出行平台,都是按城市營運的,通過配置的方式開城,進而實作業務的橫向快速擴充。
那有沒有可能在中國開辟一個甚至多個虛拟的城市呢,壓測隻在虛拟城市進行呢? 開辟虛拟城市,可以避免前面提到的諸多問題,尤其是隔離問題,但需要考慮虛拟乘客釋出路線、虛拟司機地圖導航的問題,城市的位置、道路怎麼模拟?
幹脆再進一步,虛拟一個完整的中國了,看似比較瘋狂,但這就是滴滴全鍊路壓測時的隔離方案。
在某虛拟國家,有很多虛拟的城市,每個虛拟城市都有一群虛拟的司機和乘客,他們使用虛拟的手機号和用戶端,進行線上交易,由此産生了虛拟的訂單。
這裡仍然要解決位置、道路的問題,我們把中國的坐标全部偏移到太平洋,“太平洋足夠大,完全容得下中美兩個國家”,那一個中國自然不再話下。至于虛拟城市的位置、道路,把真實城市偏移一定的經緯度就可以。
02壓測流量标記方案
考慮這樣的場景:在新開辟的虛拟城市,某虛拟的乘客要打車,他打開虛拟的手機端,輸入目的地,點選“立即預約”,請求發送到滴滴的背景系統,背景應該怎樣處理?
談論方案之前,先了解一下現狀:
傳說有一種系統叫别人家的系統,有一個語言叫别人家的語言,有一種協定叫别人家的協定。
正所謂人比人氣死人,回頭看看自己家的,雖然與很多前輩不敢相提并論,但已号稱四大語言八大架構,這個鍋得讓曆史遺留問題來背,而這段曆史,隻有短短的幾年而已。
也有好消息,與 Google 的 Dapper、阿裡的鷹眼類似,滴滴内部有一套自己的 Trace 系統,專門用來跟蹤系統之間的調用鍊路,其基本原理如下圖所示:
但并不全是好消息,全鍊路壓測啟動的時候,Trace 系統在滴滴内部并未完全推廣,不少系統不支援。
壓測流量标記方案面臨兩重選擇:
- 每個系統使用業務 ID 或标記來判斷壓測流量,隻要能拿到司乘、訂單等業務資料,系統就可以正确區分。
- 擴充 Trace 通路,在通路上添加壓測标記,統一使用 Trace 來判斷壓測流量。
最終我們選擇了方案 2,不但與業務完全解耦,還可以避免方案 1 中某些系統或接口無法拿到業務标記的情況。而且這種方式,客觀上也可以推進 Trace 通路在公司的應用。
做不到語言和架構收斂,盡量讓中間件收斂,為每種語言提供一個基礎元件類庫,中間件盡量收斂到該類庫。
于是結合全鍊路壓測,開始了内部系統痛苦的改造之路,最終基于 Trace 通路的壓測标記在主要系統之間可以跑通。
03工具端方案
鍊路已通,該考慮工具端的實作方案了,内部我們管工具端叫做虛拟的“司機端”和“乘客端”,可以用來模拟批量甚至大量的使用者,而不僅僅是一個使用者。
分布式的虛拟司乘端: 滴滴的用戶端與背景通信,不僅僅有 HTTP 協定,還有 TCP 長連接配接,甚至還有 Thrift 協定。
拿司機來說,接單等消息是通過 TCP 長連接配接下發的,意味着 TCP 長連接配接協定是必須的,而且需要為每個司機維護一個長連接配接。
考慮到需要模拟的司乘數量,虛拟的司機端、乘客端是分布式部署的,每個司乘端從資料中心擷取司乘使用者,包含基本資訊、乘客路線、司機起始位置等資訊,并且模拟批量司乘的發單等行為。
使用資料中心的目的是,當端需要擴充時,拉取的司乘不能重複,不然重複登入可能導緻被踢下線。
可動态調整的業務模型: 虛拟端要模拟相對複雜、實時的交易模型,并且需要模拟不同的業務場景,以順風車舉例,平日高峰期的訂單多為市内訂單,而節假日的跨城訂單比率增加很多。
如何在不改代碼的情況下可以壓測不同的業務場景?我們實作了可動态調整的業務模型。
該模型中,司乘基本的交易過程、狀态變化可以通過模型編輯完成,通過權重,可以調整使用者本地單、跨城單的比例。即使更多的業務場景,隻需生成業務模型即可支援。
更多實作細節: 當然除了上面提到的,方案上還有很多細節需要考慮。為了與線上實際場景更貼近,我們從線上高峰期截取了一段時間内的乘客路線和司機位置,分階段壓測時,逐漸投放更多的司乘到虛拟城市,但這樣有一個問題。
假設 A 城市有 1 萬司機,高峰期有 1 萬乘客在發單,他們都是随機而均勻分布的,如果把全部司機瞬間投放完成,所有乘客立即發單,絕大多數訂單應該是可以派出并完成交易的。
但是考慮分階段投放的場景:投放 1% 的司乘,上百名司機,上百個訂單,雖然司機位置、乘客路線來自線上真實訂單的采樣,由于位置的随機性,成單量可能很少。即使投放了 10%,上千名司乘,實際成單量也遠遠達不到 1000 個。
而我們分階段投放要求的 10%,不光是投放數量達到線上 10%,也期望成單量等資料同步達到 10%,這樣才能驗證工具端方案是否合理、線上壓力是否正常。
在這裡,我們采用了一個簡單的算法:東單是北京的一個熱點區域,第一個司機、乘客投放在東單,基本上可以保證成單;前 1000 名司機、乘客投放在東單附近,成單量雖不能上千,但比完全随機要好很多。
控制好司乘投放的位置,基本可以保證成單量與投放數量成比例增長。
壓測實錄
2016 年上半年是滴滴 Uber 合并前最後的瘋狂,營運活動頻繁,業務峰值不斷攀升,平台出現的線上事故也較為多些。
從 2016 年中項目啟動,經過多次嘗試、探索,終于線上上成功進行了全鍊路壓測。為了不影響線上業務,壓測的視窗期選擇在淩晨,并且嚴格掌控壓測節奏,把壓測過程劃分成幾個不同階段,逐漸提升壓力,邊壓測邊監控背景系統的壓力:
幾個主要的業務線先後進行了十餘次壓測,并發現了一些線上問題,如某 API 接口耗時明顯增長;長連接配接伺服器的參數配置有誤;分單服務 codis 通路逾時;日志過多導緻分單算法逾時等。
除了驗證線上系統的穩定性,全鍊路壓測項目還帶來一些附加的收益:
- 不同語言下的基礎元件類庫趨向收斂,Trace 通道覆寫了更多子產品。
- 建立了一套完整隔離的線上環境,未來可以線上上做更多正确性驗證。
現在的滴滴,越來越重視平台穩定性,對事故的預警、降級處理和事故處理預案越來越成熟,事故時長也明顯縮短,但仍然存在單點故障、魯棒性不高等潛在風險。
展望将來,期望全鍊路壓測能在更多領域發揮作用:
- 線上環境的故障注入和故障演練。