四大語言,八大框架|滴滴全鏈路壓測解決之道

背景

滴滴出行創立於2012年,是全球領先的一站式多元化出行平台。經歷過各種燒錢補貼大戰、多次合併,滴滴成為繼阿里之後,國內第二個日訂單量超過千萬的公司。

業務飛速增長,IT系統面臨的挑戰通常更甚於業務,因為不僅需求規模增加,技術人員數量增加,面臨問題的複雜度也增加:

2016年的滴滴,正在經歷這樣的階段,一方面日單量從百萬衝到千萬,另一方面IT系統屢次出現線上故障,穩定性建設成為支撐業務發展的重要保障。在此背景下,滴滴啟動了全鏈路壓測項目。

壓測方案

滴滴的業務與普通電商差別較大,一次典型的用戶打車流程是這樣的:乘客發單,0-3分鐘內派給附近的司機,司機搶單後,去接乘客,到達目的地。這不但要求司乘的位置相近,而且交易必須是實時的。

基於滴滴業務的特殊性,同時借鑒了業內的經驗,我們制定了滴滴的全鏈路壓測方案,一句話描述就是:在線上環境,針對全業務核心鏈路,以數據隔離的方式進行壓測,如下圖表示:

線上環境: 基於阿里等公司之前的經驗,壓測在線上環境進行,線上最大的優點就是環境真實,不需要擔心配置不一致、結果是否可以同比例放大等問題,壓測的結果自然也更為精確。但在線上做壓測,需要保證安全性,風險不言而喻:不能搞垮線上系統。壓測的時間窗口限定在低峰期;監控必須給力,在系統出現單點故障前,要能夠提前預警,萬一真的出現故障,必須緊急停止壓力,最短時間內進行恢復。

全業務核心鏈路: 支持計程車、專車快車、順風車等幾個主要的業務線,覆蓋主要的業務場景,以計程車為例,從乘客打開App輸入上車點、目的地、發單,到司機出車、搶單、接乘客上車、到達目的地,甚至取消訂單等完整流程:

數據隔離: 壓測方案的核心是數據隔離,壓測司乘要與真實司乘區分,壓測訂單不能與真實訂單混淆,絕不能把真實乘客的單派給虛擬司機等問題。下面將專門介紹壓測的數據隔離方案。

1. 數據隔離方案

與其談隔離方案,不如讓我們想像幾種數據隔離不好的場景:

  1. 某真實司機的歷史訂單突然多了一些假訂單,積分、券、餘額等出錯;
  2. 某真實乘客的訂單被派給了虛擬司機,乘客一直在等待司機來接;
  3. 某城市的BI報表出錯,莫名其妙的多了一些訂單,貌似財務也對不上;
  4. 某城市的運力估計及動調出現異常波動;
  5. 清理虛擬訂單及相關數據時,不小心誤刪了真實訂單和數據......

虛擬訂單方案:隔離不好的場景,光是想想就不寒而慄,可以讓我們輕易排除這種看似最簡單的方案:使用真實司機乘客,發送虛擬訂單。虛擬訂單通過ID或者標誌欄位進行區分,派單時做特殊處理。這種方式對業務有較大的侵入性,不僅是修改派單那麼簡單,還需要從各個維度適時地屏蔽司乘與虛擬訂單的關係,如訂單歷史、通知推送、積分統計等,不但多而且是強依賴,顯然不是一種合理的方案。

提升虛擬的層次: 每個城市啟用一批虛擬的乘客,發送虛擬訂單,派發給虛擬司機,司乘及訂單上通過ID或者標誌欄位進行區分。這可以解決司乘及訂單強依賴的問題。但從城市的角度看,需要隔離真實司乘與虛擬司乘,又會涉及到城市的動態調價、供需預測、BI統計等各個方面的隔離。

再提升虛擬的層次:與傳統電商不同,Uber、滴滴這樣的出行平台,都是按城市運營的,通過配置的方式開城,從而實現業務的橫向快速擴展。那有沒有可能在中國開闢一個甚至多個虛擬的城市呢,壓測只在虛擬城市進行呢? 開闢虛擬城市,可以避免前面提到的諸多問題,尤其是隔離問題,但需要考慮虛擬乘客發布路線、虛擬司機地圖導航的問題,城市的位置、道路怎麼模擬?乾脆再進一步,虛擬一個完整的中國了,看似比較瘋狂,但這就是滴滴全鏈路壓測時的隔離方案:

在某虛擬國家,有很多虛擬的城市,每個虛擬城市都有一群虛擬的司機和乘客,他們使用虛擬的手機號和客戶端,進行線上交易,由此產生了虛擬的訂單。

仍然要解決位置、道路的問題,我們把中國的坐標全部偏移到太平洋,「太平洋足夠大,完全容得下中美兩個國家」,那一個中國自然不再話下。虛擬城市的位置、道路,把真實城市偏移一定的經緯度就可以。

2. 壓測流量標記方案

考慮這樣的場景:在新開闢的虛擬城市,某虛擬的乘客要打車,他打開虛擬的手機端,輸入目的地,點擊「立即預約」,請求發送到滴滴的後台系統,後台應該怎麼樣處理? 談論方案之前,不如先了解一下現狀:

傳說有一種系統叫別人家的系統,有一個語言叫別人家的語言,有一種協議叫別人家的協議,正所謂人比人氣死人,回頭看看自己家的,雖然與很多前輩不敢相提並論,但已號稱四大語言八大框架,這個鍋得讓歷史遺留問題來背,而這段歷史,只有短短的幾年而已。

也有好消息,與google的dapper、阿里的鷹眼類似,滴滴內部有一套自己的trace系統,專門用來跟蹤系統之間調用鏈路,其基本原理如下圖所示:

但並不全是好消息,全鏈路壓測啟動的時候,Trace系統在滴滴內部並未完全推廣,不少系統不支持。壓測流量標記方案面臨兩重選擇:

  1. 每個系統使用業務ID或標記來判斷壓測流量,只要能拿到司乘、訂單等業務數據,系統就可以正確區分;
  2. 擴展Trace通路,在通路上添加壓測標記,統一使用Trace來判斷壓測流量。

最終我們選擇了方案2,不但與業務完全解耦,還可以避免方案1中某些系統或介面無法拿到業務標記的情況。而且這種方式,客觀上也可以推進Trace通路在公司的應用。

做不到語言和框架收斂,盡量讓中間件收斂,為每種語言提供一個基礎組件類庫,中間件盡量收斂到該類庫。

於是結合全鏈路壓測,開始了內部系統痛苦的改造之路,最終基於Trace通路的壓測標記在主要系統之間可以跑通。

3. 工具端方案

鏈路已通,該考慮工具端的實現方案了,內部我們管工具端叫做虛擬的「司機端」和「乘客端」,可以用來模擬批量甚至大量的用戶,而不僅僅是一個用戶。

分散式的虛擬司乘端: 滴滴的客戶端與後台通信,不僅僅有HTTP協議,還有TCP長連接,甚至還有Thrift協議。拿司機來說,接單等消息是通過TCP長連接下發的,意味著TCP長連接協議是必須的,而且需要為每個司機維護一個長連接。

考慮到需要模擬的司乘數量,虛擬的司機端、乘客端是分散式部署的,每個司乘端從數據中心獲取司乘用戶,包含基本信息、乘客路線、司機起始位置等信息,並且模擬批量司乘的發單等行為。使用數據中心的目的是,當端需要擴展時,拉取的司乘不能重複,不然重複登錄可能導致被踢下線。

可動態調整的業務模型: 虛擬端要模擬相對複雜、實時的交易模型,並且需要模擬不同的業務場景,以順風車舉例,平日高峰期的訂單多為市內訂單,而節假日的跨城訂單比率增加很多。如何在不改代碼的情況下可以壓測不同的業務場景?我們實現了可動態調整的業務模型。

該模型中,司乘基本的交易過程、狀態變化可以通過模型編輯完成,通過權重,可以調整用戶本地單、跨城單的比例。即使更多的業務場景,只需生成業務模型即可支持。

更多實現細節: 當然除了上面提到的,方案上還有很多細節需要考慮。為了與線上實際場景更貼近,我們從線上高峰期截取了一段時間內的乘客路線和司機位置,分階段壓測時,逐漸投放更多的司乘到虛擬城市,但這樣有一個問題。

假設A城市有1萬司機,高峰期有1萬乘客在發單,他們都是隨機而均勻分布的,如果把全部司機瞬間投放完成,所有乘客立即發單,絕大多數訂單應該是可以派出並完成交易的。

但是考慮分階段投放的場景:投放1%的司乘,上百名司機,上百個訂單,雖然司機位置、乘客路線來自線上真實訂單的採樣,由於位置的隨機性,成單量可能很少。即使投放了10%,上千名司乘,實際成單量也遠遠達不到1000個。

而我們分階段投放要求的10%,不光是投放數量達到線上10%,也期望成單量等數據同步達到10%,這樣才能驗證工具端方案是否合理、線上壓力是否正常。

在這裡,我們採用了一個簡單的演算法:東單是北京的一個熱點區域,第一個司機、乘客投放在東單,基本上可以保證成單;前1000名司機、乘客投放在東單附近,成單量雖不能上千,但比完全隨機要好很多。控制好司乘投放的位置,基本可以保證成單量與投放數量成比例增長。

壓測實錄

2016年上半年是滴滴Uber合併前最後的瘋狂,運營活動頻繁,業務峰值不斷攀升,平台出現的線上事故也較為多些。

從2016年中項目啟動,經過多次嘗試、探索,終於在線上成功進行了全鏈路壓測。為了不影響線上業務,壓測的窗口期選擇在凌晨,並且嚴格掌控壓測節奏,把壓測過程劃分成幾個不同階段,逐漸提升壓力,邊壓測邊監控後台系統的壓力:

幾個主要的業務線先後進行了十餘次壓測,並發現一些線上問題,如某API介面耗時明顯增長;長連接伺服器的參數配置有誤;分單服務codis訪問超時;日誌過多導致分單演算法超時等。

除了驗證線上系統的穩定性,全鏈路壓測項目還帶來一些附加的收益:

  1. 不同語言下的基礎組件類庫趨向收斂,Trace通道覆蓋了更多模塊。
  2. 建立了一套完整隔離的線上環境,未來可以在線上做更多正確性驗證。

現在的滴滴,越來越重視平台穩定性,對事故的預警、降級處理和事故處理預案越來越成熟,事故時長也明顯縮短,但仍然存在單點故障、魯棒性不高等潛在風險。展望將來,期望全鏈路壓測能在更多領域發揮作用:線上環境的故障注入和故障演練;線上灰度發布環境的正確性驗證;線上系統的容量預估等。


推薦閱讀:

滴滴與 Uber 中國合併,給用戶帶來的影響有哪些?
為什麼阿里認為滴滴快的合併很失敗,對阿里是錯誤?
滴滴若用打車券償還小藍單車押金將再傷害用戶 市場格局難改
關於網約車新政,你們吐槽的姿勢基本不對
TMD想上市?先問問你家公關吧

TAG:滴滴出行 | DevOps | 云计算平台 |