滴滴實時計算髮展之路及平台架構實踐

  • 2019 年 10 月 4 日
  • 筆記

點擊上方「zhisheng」,選擇「設為星標」

公眾號內回復「Flink」可以下載 Flink 相關的資料

滴滴的核心業務是一個實時在線服務,因此具有豐富的實時數據和實時計算場景。本文將介紹滴滴實時計算髮展之路以及平台架構實踐。

一、實時計算演進

隨著滴滴業務的發展,滴滴的實時計算架構也在快速演變。到目前為止大概經歷了三個階段:

  • 業務方自建小集群階段;
  • 集中式大集群、平台化階段;
  • SQL化階段。

下圖標識了其中重要的里程碑,稍後會給出詳細闡述:

在2017年以前,滴滴並沒有統一的實時計算平台,而是各個業務方自建小集群。其中用到的引擎有Storm、JStorm、Spark Streaming、Samza等。業務方自建小集群模式存在如下弊端:

  • 需要預先採購大量機器,由於單個業務獨佔,資源利用率通常比較低;
  • 缺乏有效的監控報警體系;
  • 維護難度大,需要牽涉業務方大量精力來保障集群的穩定性;
  • 缺乏有效技術支援,且各自沉澱的東西難以共享。

為了有效解決以上問題,滴滴從2017年年初開始構建統一的實時計算集群及平台。

技術選型上,我們基於滴滴現狀選擇了內部用大規模數據清洗的Spark Streaming引擎,同時引入On-YARN模式,並利用YARN的多租戶體系構建了認證、鑒權、資源隔離、計費等機制。

相對於離線計算,實時計算任務對於穩定性有著更高的要求,為此我們構建了兩層資源隔離體系:

  • 第一層是基於CGroup做進程(Container)級別的CPU及記憶體隔離;
  • 第二層是物理機器級別的隔離。

我們通過改造YARN的FairScheduler使其支援Node Label。達到的效果如下圖所示:

普通業務的任務混跑在同一個Label機器上,而特殊業務的任務跑在專用Label的機器上。

通過集中式大集群和平台化建設,基本消除了業務方自建小集群帶來的弊端,實時計算也進入了第二階段。

伴隨著業務的發展,我們發現Spark Streaming的Micro Batch模式在一些低延時的報警業務及在線業務上顯得捉襟見肘。於是我們引入了基於Native Streaming模式的Flink作為新一代實時計算引擎。

Flink不僅延時可以做到毫秒級,而且提供了基於Process Time/Event Time豐富的窗口函數。基於Flink我們聯合業務方構架了滴滴流量最大的業務網關監控系統,並快速支援了諸如乘客位置變化通知、軌跡異常檢測等多個線上業務。

二、實時計算平台架構

為了最大程度方便業務方開發和管理流計算任務,我們構建了如圖所示的實時計算平台:

在流計算引擎基礎上提供了StreamSQL IDE、監控報警、診斷體系、血緣關係、任務管控等能力。各自的作用如下:

  • StreamSQL IDE。下文會介紹,是一個Web化的SQL IDE;
  • 監控報警。提供任務級的存活、延時、流量等監控以及基於監控的報警能力;
  • 診斷體系。包括流量曲線、Checkpoint、GC、資源使用等曲線視圖,以及實時日誌檢索能力。
  • 血緣關係。我們在流計算引擎中內置了血緣上報能力,進而在平台上呈現流任務與上下游的血緣關係;
  • 任務管控。實現了多租戶體系下任務提交、啟停、資產管理等能力。通過Web化任務提交消除了傳統客戶機模式,使得平台入口完全可控,內置參數及版本優化得以快速上線。

三、實時規則匹配服務建設

在滴滴內部有大量的實時運營場景,比如「某城市乘客冒泡後10秒沒有下單」。針對這類檢測事件之間依賴關係的場景,用Fink的CEP是非常合適的。

但是社區版本的CEP不支援描述語言,每個規則需要開發一個應用,同時不支援動態更新規則。為了解決這些問題,滴滴做了大量功能擴展及優化工作。功能擴展方面主要改動有:

  • 支援wait運算元。對於剛才例子中的運營規則,社區版本是表達不了的。滴滴通過增加wait運算元,實現了這類需求;
  • 支援DSL語言。基於Groovy和Aviator解析引擎,我們實現了如下圖所示的DSL描述規則能力:
  • 單任務多規則及規則動態更新。由於實時運營規則由一線運營同學來配置,所以規則數量,規則內容及規則生命周期會經常發生變化。這種情況每個規則一個應用是不太現實的。為此我們開發了多規則模式且支援了動態更新。

除了功能拓展之外,為了應對大規模運營規則的挑戰,滴滴在CEP性能上也做了大量優化,主要有:

  • SharedBuffer重構。基於Flink MapState重構SharedBuffer,減少每次數據處理過程中的狀態交互。同時剝離規則和用戶數據極大降低每次匹配的時候從狀態中反序列化的數據量;
  • 增加訪問快取(已貢獻社區)。快取SharedBuffer數據中每次處理所需要更新的引用計數,延緩更新;
  • 簡化event time語義處理。避免key在很分散情況下每次watermark更新時要遍歷所有key的數據;
  • 復用conditionContext(已貢獻社區)。減少條件查詢時對partialMatch元素的反覆查詢。

以上優化將CEP性能提升了多個數量級。配合功能擴展,我們在滴滴內部提供了如圖所示的服務模式:

業務方只需要清洗數據並提供規則列表API即可具備負責規則的實時匹配能力。

目前滴滴CEP已經在快車個性化運營、實時異常工單檢測等業務上落地,取得了良好的效果。

四、StreamSQL建設

正如離線計算中Hive之於MapReduce一樣,流式SQL也是必然的發展趨勢。通過SQL化可以大幅度降低業務方開發流計算的難度,業務方不再需要學習Java/Scala,也不需要理解引擎執行細節及各類參數調優。

為此我們在2018年啟動了StreamSQL建設項目,在社區Flink SQL基礎上拓展了以下能力:

  • 擴展DDL語法。如下圖所示,打通了滴滴內部主流的消息隊列以及實時存儲系統:
  • StreamSQL內置打通消息隊列及實施存儲 通過內置常見消息格式(如json、binlog、標準日誌)的解析能力,使得用戶可以輕鬆寫出DDL語法,並避免重複寫格式解析語句。
  • 拓展UDF。針對滴滴內部常見處理邏輯,內置了大量UDF,包括字元串處理、日期處理、Map對象處理、空間位置處理等。
  • 支援分流語法。單個輸入源多個輸出流在滴滴內部非常常見,為此我們改造了Calcite使其支援分流語義。
  • 支援基於TTL的join語義。傳統的Window Join因為存在window邊界數據突變情況,不能滿足滴滴內部的需求。為此我們引入了TTL State,並基於此開發了基於TTL Join的雙流join以及維表join。
  • StreamSQL IDE。前文提到平台化之後我們沒有提供客戶機,而是通過Web提交和管控任務。因此我們也相應開發了StreamSQL IDE,實現Web上開發StreamSQL,同時提供了語法檢測、DEBUG、診斷等能力。

目前StreamSQL在滴滴已經成功落地,流計算開發成本得到大幅度降低。預期未來將承擔80%的流計算業務量。

五、總結

作為一家出行領域的互聯網公司,滴滴對實時計算有天然的需求。

過去的一年多時間裡,我們從零構建了集中式實時計算平台,改變了業務方自建小集群的局面。為滿足低延時業務的需求,成功落地了Flink Streaming,並基於Flink構建了實時規則匹配(CEP)服務以及StreamSQL,使得流計算開發能力大幅度降低。未來將進一步拓展StreamSQL,並在批流統一、IoT、實時機器學習等領域探索和建設。