文 | 陳肅 DataPipeline CTO
隨著企業應用複雜性的上升和微服務架構的流行,資料正變得越來越以應用為中心。
服務之間僅在必要時以介面或者訊息佇列方式進行資料互動,從而避免了構建單一資料庫叢集來支撐不斷增長的業務需要。以應用為中心的資料持久化架構,在帶來可伸縮性好處的同時,也給資料的融合計算帶來了障礙。
由於資料散落在不同的資料庫、訊息佇列、檔案系統中,計算平臺如果直接訪問這些資料,會遇到可訪問性和資料傳輸延遲等問題。在一些場景下,計算平臺直接訪問應用系統資料庫會對系統吞吐造成顯著影響,通常也是不被允許的。
因此,在進行跨應用的資料融合計算時,首先需要將資料從孤立的資料來源中採集出來,彙集到可被計算平臺高效訪問的目的地,此過程被稱為ETL,即資料的抽取(Extract)、轉換(Transform)和載入(Load)。
ETL並不是什麼新鮮事物。
該領域的傳統公司,例如Informatica,早在1993年就已經成立,並且提供了成熟的商業化解決方案。開源工具,例如Kettle、DataX等,在很多企業中也得到了廣泛的應用。
傳統上,ETL是通過批量作業完成的。即定期從資料來源載入(增量)資料,按照轉換邏輯進行處理,並寫入目的地。根據業務需要和計算能力的不同,批量處理的延時通常從天到分鐘級不等。在一些應用場景下,例如電子商務網站的商品索引更新,ETL需要儘可能短的延遲,這就出現了實時ETL的需求。
在實時ETL中,資料來源和資料目的地之間彷彿由管道連線在一起。資料從源端產生後,以極低的延遲被採集、加工,並寫入目的地,整個過程沒有明顯的處理批次邊界。
實時ETL,又被稱為Data Pipeline模式。
阿里提出了“資料中臺”的概念。即資料被統一採集,規範資料語義和業務口徑形成企業基礎資料模型,提供統一的分析查詢和新業務的資料對接能力。
資料中臺並不是新的顛覆式技術,而是一種企業資料資產管理和應用方法學,涵蓋了資料整合、資料質量管理、後設資料+主資料管理、數倉建模、支援高併發訪問的資料服務介面層開發等內容。
在資料中臺建設中,結合企業自身的業務需求特點,架構和功能可能各不相同,但其中一個最基本的需求是資料採集的實時性和完整性。資料從源端產生,到被採集到資料彙集層的時間要儘可能短,至少應做到秒級延遲,這樣中臺的資料模型更新才可能做到近實時,構建在中臺之上依賴實時資料流驅動的應用(例如商品推薦、欺詐檢測等)才能夠滿足業務的需求。
以阿里雙十一為例,在極高的併發情況下,訂單產生到大屏統計資料更新延遲不能超過5s,一般在2s內。
中臺對外提供的資料應該是完整的,源端資料的Create、Update和Delete都要能夠被捕獲,不能少也不能多,即資料需要有端到端一致性的能力(Exactly Once Semantic,EOS)。
當然,EOS並非在任何業務場景下都需要,但從平臺角度必須具備這種能力,並且允許使用者根據業務需求靈活開啟和關閉。
在構建實時資料整合平臺時,就一些技術選型問題,建議做以下考量:
一、資料來源變化捕獲
源資料變化捕獲是資料整合的起點,獲取資料來源變化主要有三種方式:
-
基於日誌的解析模式;
-
基於增量條件查詢模式;
-
資料來源主動Push模式。
基於日誌的解析模式常用於各種型別的資料庫,例如MySQL的Binlog、Oracle的Redo&Achieve Log、SQL Server Change Tracking & CDC等。
不同資料庫日誌解析的原理差別很大,以MySQL Binlog模式為例,解析程式本身是一個Slave,能夠實時收到MySQL Master的資料流推送,並解析還原成DDL和DML操作。而SQL Server的CT模式下,增量是通過定期查詢Change Tracking表實現的。
基於增量條件的查詢模式不依賴於源端開啟日誌記錄,但對於資料來源通常有額外的格式要求。例如,資料庫表或文件物件需要有標誌更新時間的欄位,這在一些業務系統中是無法滿足的。
資料來源主動Push模式的常見形式為業務插碼,即應用系統通過打點或者配置切面的方式,將資料變化封裝為事件,額外傳送一份給資料整合平臺。這種方式一般需要對源端系統程式碼進行一定程度的修改。
通常而言,基於資料庫的日誌進行增量捕獲應當被優先考慮。其具備以下幾個顯著優點:
-
能夠完整獲取資料變化的操作型別,尤其是Delete操作,這是增量條件查詢模式很難做到的;
-
不依賴特別的資料欄位語義,例如更新時間;
-
多數情況下具備較強的實時性。
當然,事物都具有兩面性。開啟資料庫日誌通常會對源庫效能產生一定的影響,需要額外的儲存空間,甚至一些解析方法也會對源庫資源造成額外消耗。因此,實施過程中需要在DBA的配合下,根據資料庫特點和解析原理進行DB部署規劃。
推薦使用資料庫的複製和災備能力,在獨立伺服器對從庫進行日誌解析。此外,當資料庫產生批量更新時,會在短時間內產生大量日誌堆積,如果日誌留存策略設定不當,容易出現資料丟失。這些都需要根據具體的業務資料增長特點,在前期做好規劃,並在上線後根據業務變化定期進行評估和調整。
資料來源主動push模式下,由於事件傳送和業務處理很難做到事務一致性,所以當出現異常時,資料一致性就無從保證,比較適合對於資料一致性要求不高的場景,例如使用者行為分析。
二、執行環境
無論採用何種資料變化捕獲技術,程式必須在一個可靠的平臺執行。該平臺需要解決分散式系統的一些共性問題,主要包括:水平擴充套件、容錯、進度管理等。
1. 水平擴充套件
程式必須能夠以分散式job的形式在叢集中執行,從而允許在業務增長時通過增加執行時節點的方式實現擴充套件。
因為在一個規模化的企業中,通常要同時執行成百上千的job。隨著業務的增長,job的數量以及job的負載還有可能持續增長。
2. 容錯
分散式執行環境的執行節點可能因為過載、網路連通性等原因無法正常工作。
當節點出現問題時,執行環境需要能夠及時監測到,並將問題節點上的job分配給健康的節點繼續執行。
3. 進度管理
job需要記錄自身處理的進度,避免重複處理資料。另外,job會因為上下游系統的問題、網路連通性、程式bug等各種原因異常中止,當job重啟後,必須能夠從上次記錄的正常進度位置開始處理後繼的資料。
有許多優秀的開源框架都可以滿足上述要求,包括Kafka Connect、Spark、Flink等。
Kafka Connect是一個專注資料進出Kafka的資料整合框架。Spark和Flink則更為通用,既可以用於資料整合,也適用於更加複雜的應用場景,例如機器學習的模型訓練和流式計算。
就資料整合這一應用場景而言,不同框架的概念是非常類似的。
首先,框架提供Source Connector介面封裝對資料來源的訪問。應用開發者基於這一介面開發適配特定資料來源的Connector,實現資料抽取邏輯和進度(offset)更新邏輯。
其次,框架提供一個分散式的Connector執行環境,處理任務的分發、容錯和進度更新等問題。
不同之處在於,Kafka Connect總是將資料抽取到Kafka,而對於Spark和Flink,Source Connector是將資料抽取到記憶體中構建物件,寫入目的地是由程式邏輯定義的,包括但不限於訊息佇列。
但無論採用何種框架,都建議首先將資料寫入一個彙集層,通常是Kafka這樣的訊息佇列。
單就資料來源採集而言,Kafka Connect這樣專注於資料整合的框架是有一定優勢的,這主要體現在兩方面:
首先是Connector的豐富程度,幾乎所有較為流行的資料庫、物件儲存、檔案系統都有開源的Connector實現。
尤其在資料庫的CDC方面,有Debezium這樣優秀的開源專案存在,降低了應用的成本。
其次是開發的便捷性,專有框架的設計相較於通用框架更為簡潔,開發新的Connector門檻較低。Kafka Connect的runtime實現也較為輕量,出現框架級別問題時debug也比較便捷。
儘管目前版本的Kafka Connect還不支援資料採集後進入Kafka的EOS保證,但通過對runtime的修改,利用Kafka事務訊息也能夠實現這一點。相信Kafka Connect未來的版本也會很快提供官方的支援。
三、資料彙集層
當各類資料從源端抽取後,首先應當被寫入一個資料彙集層,然後再進行後繼的轉換處理,直至將最終結果寫入目的地。資料彙集層的作用主要有兩點:
首先,資料彙集層將異構的資料來源資料儲存為統一的格式,並且為後繼的處理提供一致的訪問介面。這就將處理邏輯和資料來源解耦開來,同時遮蔽了資料抽取過程中可能發生的異常對後繼作業的影響。
其次,資料彙集層獨立於資料來源,可被多次訪問,亦可根據業務需要快取全部或一定期限的原始資料,這為轉換分析提供了更高的靈活度。當業務需求發生變化時,無需重複讀取源端資料,直接基於資料彙集層就可以開發新的模型和應用。資料彙集層可基於任意支援海量/高可用的檔案系統、資料倉儲或者訊息佇列構建,常見的方案包括HDFS、Hbase、Kafka等。
針對實時ETL場景,推薦使用Kafka或類似具有海量資料持久化能力的訊息佇列來做資料彙集層,這會為後繼的流式處理提供便捷。同時,利用Kafka的資料回收機制,可以根據業務需要自動保留一定時間或大小的原始資料。
四、資料轉換
資料轉換是一個業務性很強的處理步驟。
當資料進入彙集層後,一般會用於兩個典型的後繼處理場景:數倉構建和資料流服務。
數倉構建包括模型定義和預計算兩部分。資料工程師根據業務分析需要,使用星型或雪花模型設計資料倉儲結構,利用資料倉儲中介軟體完成模型構建和更新。
開源領域,Apache Kylin是預聚合模式OLAP代表,支援從HIVE、Kafka、HDFS等資料來源載入原始表資料,並通過Spark/MR來完成CUBE構建和更新。
Druid則是另一類預聚合OLAP的代表。在Druid的表結構模型中,分為時間列、維度列和指標列,允許對任意指標列進行聚合計算而無需定義維度數量。Druid 在資料儲存時便可對資料進行聚合操作,這使得其更新延遲可以做到很低。在這些方面,Baidu開源的Palo和Druid有類似之處。
一個普遍的共識是,沒有一個OLAP引擎能同時在資料量,靈活性和效能這三個方面做到完美,使用者需要基於自己的需求進行取捨和選型。預計算模式的OLAP引擎在查詢響應時間上相較於MPP引擎(Impala、SparkSQL、Presto等)有一定優勢,但相對限制了靈活性。
如前文所述,源端採集的資料建議放入一個彙集層,優選是類似Kafka這樣的訊息佇列。包括Kylin和Druid在內的資料倉儲可以直接以流式的方式消費資料進行更新。
一種常見的情形為:原始採集的資料格式、粒度不一定滿足資料倉儲中表結構的需要,而數倉提供的配置靈活度可能又不足夠。這種情況下需要在進入數倉前對資料做額外的處理。
常見的處理包括過濾、欄位替換、巢狀結構一拆多、維度填充等,以上皆為無狀態的轉換。有狀態的轉換,例如SUM、COUNT等,在此過程中較少被使用,因為數倉本身就提供了這些聚合能力。
資料流服務的構建則是基於流式計算引擎,對彙集層的資料進一步加工計算,並將結果實時輸出給下游應用系統。這涉及到流式計算引擎的選擇:Spark Streaming、Flink、還是Kafka Streams?
關於三個引擎的對比,網上有很多資料,在此不再贅述。
選型過程中有幾點值得特別關注:
1. 延遲性
Spark對流的支援是MicroBatch,提供的是亞秒級的延遲,相較於Flink和Kafka Streams在實時性上要差一些。
2. 應用模式
Spark和Flink都是將作業提交到計算叢集上執行,需要搭建專屬的執行環境。
Kafka Streams的作業是以普通Java程式方式執行,本質上是一個呼叫Kafka Streaming API的Kafka Consumer,可以方便地嵌入各種應用。
但相應的,使用者需要自己解決作業程式在不同伺服器上的分發問題,例如通過K8s叢集方案進行應用的容器化部署。如果使用KSQL,還需要部署KSQL的叢集。
3. SQL支援
三者都提供Streaming SQL,但Flink的SQL支援要更為強大些,可以執行更加複雜的分組聚合操作。
4. EOS
Flink對於資料進出計算叢集提供了框架級別的支援,這是通過結合CheckPoint機制和Sink Connector介面封裝的二階段提交協議實現的。
Kafka Streams利用Kafka事務性訊息,可以實現“消費-計算-寫入Kafka“的EOS,但當結果需要輸出到Kafka以外的目的地時,還需要利用Kafka Connect的Sink Connector。
遺憾的是,Kafka Connect不提供Kafka到其它型別Sink的EOS保證,需要使用者自己實現。
Spark Streaming與Kafka Streams類似,在讀取和計算過程中可以保證EOS,但將結果輸出到外部時,依然需要額外做一些工作來確保資料一致性。常見的方式包括:利用資料庫的事務寫入機制將Offset持久化到外部、利用主鍵保證冪等寫入、參考二階段提交協議做分散式事務等。
小結
本文簡要討論了一些構建面向實時資料的整合平臺在技術選型方面的考量點。
資料來源變化捕獲是資料整合的起點,結合日誌的解析、增量條件查詢模式和資料來源主動Push模式,最終構建出一個資料彙集層。在這個階段,推薦考慮Kafka Connect這類面向資料整合的專有框架,可以有效縮短研發週期和成本。
資料彙集層建議構建在訊息佇列之上,為後繼的加工處理提供便利。如果需要全量持久化長期儲存,建議結合使用訊息佇列和分散式檔案系統分別做實時資料和全量資料的儲存。
流式處理能力是實時資料整合平臺必要的元件。結合企業技術棧特點,選用包括Flink、Spark Streaming、Kafka Streams等流行的引擎在多數情況下都能夠滿足要求。
端到端資料的EOS是資料整合中的一個難題,需要使用者根據業務實際需求、資料本身的特性、目的地特點case by case去解決。