天天看點

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

作者:SelectDB

作者|NearFar X Lab 團隊 洪守偉、陳超、周志銀、左益、武超

整理|SelectDB 内容團隊

導讀: 無錫拈花雲科技服務有限公司(以下簡稱拈花雲科)是由中國創意文旅內建商拈花灣文旅和北京滴普科技有限公司共同孵化組建的。拈花雲科以數字化思維為導向,緻力于成為文旅目的地數智化服務商。2022 年底,拈花雲科 NearFar X Lab 團隊在資料需求的驅動下,開始調研并引進 Apache Doris 作為新架構下的資料倉庫選型方案。本文主要介紹了拈花雲科資料中台架構從 1.0 到 2.0 的演變過程,以及 Apache Doris 在傳遞型項目和 SaaS 産品中的應用實踐,希望本文分享的内容能對大家有所啟發。

業務背景

拈花雲科的服務對象主要是國内各個景區、景點,業務範圍涵蓋文旅行業的多個闆塊,如票務、交通、零售、住宿、餐飲、演繹、遊樂、影院、KTV、租賃、服務、會務、康樂、康養、電商、客服、營銷、分銷、安防等。多業務線條下使用者對于資料使用的時效性需求差異較大,需要我們能夠提供實時、準實時、T+1 的業務支撐能力。同時根據大部分景區為國有化的特點,我們也需要具備能夠提供私有化傳遞部署及 SaaS 化資料中台産品解決方案的雙重服務支撐能力。

資料中台 1.0 - Lambda

早期建構資料中台時,為了優先滿足 B 端使用者資料整合的需求,以穩定資料輸出為出發點,是以我們基于行業中比較成熟的 Lambda 架構形成了資料中台 1.0 。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

在資料中台 1.0 架構中分為三層,分别為 Batch Layer,Speed Layer 和 Serving Layer。其中,Batch Layer 用于批量處理全部的資料,Speed Layer 用于處理增量的資料,在 Serving Layer 中綜合 Batch Layer 生成的 Batch Views 和 Speed Layer 生成的 Realtime Views,提供給使用者查詢最終的結果。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

Batch Layer: 在我們早期的實施類項目中,單純以離線 T+1 進行資料支援的項目占了絕大多數。但實施類項目在實作 Lambda 架構的過程中也會面臨很多問題。比如資料采集環節,由于項目本身原因業務系統不能開放 DB 的 Binlog 供資料倉庫采集,是以隻能以 JDBC 的方式完成增量或全量的資料同步,而通過該方式同步的資料往往會由于系統人工補充資料、時間戳不規範等問題産生同步資料差異的情況發生,最終隻能通過額外的資料對比邏輯進行校驗,以保證其資料的一緻性。

Speed Layer: 項目受成本限制較大,大面積基于流的實時計算對于不論是從硬體成本、部署成本還是實施成本、維護成本等角度均難以支撐。基于該原因,在實施類項目中隻有部分業務會進行基于流的實時統計計算,同時滿足流計算條件的業務上遊系統也必須同時滿足同步 Binlog 的使用需求。

Serving Layer: 大部分的預計算結果存儲在 MySQL 中提供 Report 支援,部分實時場景通過 Merge Query 對外提供 Ad-Hoc 的查詢支援。

随着時間的推移,大量的項目傳遞使用增多,架構的問題也逐漸開始顯現:

  • 開發和維護成本高:該架構需要維護兩套代碼,即批處理和實時處理的代碼,這無疑增加了開發和維護的成本。
  • 資料處理複雜度高:Lambda 架構需要處理多個層次的資料,包括原始資料、批處理資料和實時處理資料,需要對不同的資料進行清洗、轉換和合并,資料處理的複雜度較高。
  • 實時計算支援有限:業務方對于資料時效性要求越來越高,但是該架構能力有限,無法支援更多、更高要求的的實時計算。
  • 資源使用率低:離線資源較多,但我們僅在淩晨後的排程時間範圍内使用,資源使用率不高。
  • 受成本制約:該架構對于我們部分使用者而言使用成本較高,難以起到降低成本提高效率的作用。

新架構的設計目标

基于以上架構問題,我們希望實作一套更加靈活的架構方案,同時希望新的架構可以滿足日益增高的資料時效性要求。在新方案實作之前,我們必須先對目前的業務應用場景和項目類型進行分析。

我們業務應用場景分為以下四類,這四類場景的特點和需求分别是:

  • 看闆類:包括 Web/移動端資料看闆和大屏可視化,用于展示景區重要場所的資料,如業務播報(實時在園人數監控、車船排程管理等)、應急管理監控(客流密度監控、景區消防預警、景區能耗監控等)。其組成特點一般為業務彙總名額和監控名額報警,對資料時效性要求較高。
  • 報表類:資料報表以圖表形式展示,主要服務于各業務部門的一線業務人員。會更多關注垂直業務的資料覆寫程度,會有鑽取需求(也可能通過不同報表來展現不同資料粒度)。一般以景區的業務部門為機關建構報表欄目和分析主題,除财務結算類報表外,一般可接受 T+1 的報表時效。
  • 分析類:自助分析基于較好的資料模型表(資料寬表)實作,對分析人員有一定的資料了解和操作需求,基于我們提供的 BI 分析平台,業務人員可基于此資料範圍通過拖拽的方式組合出自己的資料結果,靈活度較高。該場景對資料時效要求不高,更多關注業務資料沉澱和與往期曆史資料的對比分析側重架構的 OLAP 能力。
  • 服務類:一般對接三方系統,由資料中台提供資料計算結果。如畫像标簽等資料,通過資料接口控制權限提供對外資料服務與其它業務系統內建,需要新架構能夠提供穩定的資料服務。

接着我們對項目類型的特點和需求也進行了分析,并确定新架構需要同時提供實施類項目和 SaaS 産品的資料中台支撐能力:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

資料中台 2.0 - Apache Doris

結合以上需求,我們計劃對原有架構進行更新,并對新架構的 OLAP 引擎進行選型。在對比了 ClickHouse 等 OLAP 引擎後(社群有非常多的對比文章參考,這裡不過多贅述),最終選擇了 Apache Doris 作為資料中台 2.0 的基座。同時,在資料的同步、內建及計算環節,我們也建構了多套方案來适配以 Apache Doris 為核心的計算鍊路,以應對不同類型的實施類項目及 SaaS 産品需求。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

資料中台 2.0 的核心思路是将 Apache Doris 作為核心的資料倉庫,并将其作為實時資料同步中心、核心資料計算中心。資料內建環節将專注于資料同步,而計算交由 Apache Doris 完成或由 Doris 輔助計算引擎完成。同時,我們将在提供多種資料同步至 Apache Doris 的方案以應對不同的項目需求。在這個架構下,我們支援實作實時、準實時、T+1 的計算場景支援,以滿足不同業務場景的需求。

新架構資料流轉:

  1. 資料同步內建:架構 2.0 有多種資料同步方式,我們主要借助 Doris Unique Key 模型完成資料的同步更新。
Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All
  1. 數倉分層計算:根據項目資源情況分 View/實體表單來建構後面的資料層級(DWD、DWS、ADS)。業務較輕或時效性很高時,通過 View 方式來實作邏輯層面的 DWD,通過這種方式為下遊 Ad-hoc 提供寬表查詢支援,Doris的謂詞下推及 View 優化的能力為使用視圖查詢帶來了便利。而當業務較重時,通過實體表單 + 微批任務進行實作,按照排程依賴關系逐層完成計算,針對使用場景對表單進行優化。
  2. 資料計算時效:新架構下的資料時效受具體資料計算鍊路中的三個方面限制,分别是資料采集時效、批次計算時效、資料查詢耗時。在不考慮網絡吞吐、消息積壓、資源搶占的情況下:

(實施類項目經常會遇到第三方不提供 Binlog 的情況,是以這裡把通過批次采集資料也作為一個 case 列出來)

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

在 Doris 中為了達到更好的計算時效,基于 Doris 的資料計算流程相比在 Hive 中的計算流程可以進行一定的簡化,這樣可避免過多的備援計算設計,以此提高計算産出效率。

  1. 補充架構能力:
  • Hadoop:根據不同的項目資源及資料情況來決定是否引入 Hadoop 補充大規模離線計算場景。以實施類項目為例,Doris 可以涵蓋大部分核心業務資料計算場景。
  • MySQL:基于預計算的結果資料可以推送到下遊 MySQL 中以供 Report 查詢,進而分散 Doris 計算查詢的資源消耗,這樣可以将資源充分留給核心且時效性要求高的應用或高頻批次任務。如果計算資源充足,Doris 也可以直接作為應用層的加速查詢 DB,而無須引入其它 DB。

新架構收益

通過引入 Apache Doris,我們成功建構了高時效、低成本的資料中台 2.0,并成功滿足了傳遞型項目和 SaaS 産品兩種需求場景下的使用需求。新架構的收益如下:

  • 資料時效性提升:架構 1.0 中大部分業務為 T+1 的支援方式,而在新架構下大部分業務都可實作實時或小時級計算支援。
  • 資源使用率提高:在架構 1.0 中,離線資源在白天大部分時間處于閑置狀态。而在新架構下,資料同步、計算(增量/全量)和查詢均在同一叢集下完成,進而提高了資源使用率。相較于部署一套 CDH,同等資源成本下,部署一套 Doris 可以帶來更多的收益。
  • 運維管理成本降低:在原有架構下,實時統計需求需要維護非常長的計算鍊路。而在新架構下,所有計算僅需在一個資料庫中完成,更加簡單、高效且易于維護。
  • 易于業務擴充:Doris 的節點擴充操作非常便捷,這對于業務的增量支援非常友好。

新架構的落地實踐

我們在 2022 年底首次在測試環境中部署了 Apache Doris 1.1.5 版本,并進行了一些業務資料的導入測試和新架構的可行性驗證。在測試後,我們決定在生産環境中落地實踐 Apache Doris。第一次生産環境部署時,我們使用了當時最新的 1.2.2 版本。目前,新項目已更新到 1.2.4 版本并使用。Apache Doris 作為新架構下的核心系統,在整個架構中發揮着重要的作用。下面我們将從模型選擇、資源規劃、表結構同步、計算場景實作、運維保障等幾個角度分享我們基于 Doris 的項目落地經驗,希望為正在準備落地 Doris 方案的讀者帶來一些參考。

模型選擇

資料模型我們主要應用了 Doris 提供的 Unique 模型和 Aggregate 模型。

Unique 模型

對于 ODS 層的表單來說,我們需要 Doris Table 與源系統資料保持實時同步。為了保證資料同步的一緻性,我們采用了 Unique 模型,該模型會根據主鍵來對資料進行合并。在 1.2.0 版本之前,Unique 模型是 Aggregate 模型的一種特例,使用了 Merge On Read 的實作方式,這種實作方式下 count(*)的查詢效率較低。而在 1.2.0 版本推出之後,采用了新的 Merge On Write 的資料更新方式,在 Unique Key 寫入過程中,Doris 會對新寫入的資料和存量資料進行 Merge 操作,進而大幅優化查詢性能。在 Merge 過程中,Doris 會查找 Unique Key 索引,并使用 Page Cache 來優化索引查找效率。是以在使用 1.2 版本中,建議打開 Doris BE 的 Page Cache(在 be.conf檔案中增加配置項 disable_storage_page_cache = false)。另外在很多情況下,Unique 模型支援多種謂詞的下推,這樣表單也可以支援從源表直接建立視圖的查詢方式。

Aggregate 模型

在某些場景下(如次元列和名額列固定的報表查詢),使用者隻關心最終按次元聚合後的結果,而不需要明細資料的資訊。針對這種情況,我們建議使用 Aggregate 模型來建立表,該模型以次元列作為 Aggregate Key 建表。在導入資料時,Key 列相同的行會聚合成一行(目前 Doris 支援 SUM、REPLACE、MIN、MAX 四種聚合方式)。

Doris 會在三個階段對資料進行聚合:

  • 資料導入的 ETL 階段,在每一批次導入的資料内部進行聚合;
  • 底層 BE 進行資料 Compaction 的階段;
  • 資料查詢階段。

聚合完成之後,Doris 最終隻會存儲聚合後的資料,這種明細表單資料的預聚合處理大大減少了需要存儲和管理的資料量。當新的明細資料導入時,它們會和表單中存儲的聚合後的資料再進行聚合,以提供實時更新的聚合結果供使用者查詢。

資源管理

在生産環境中,我們使用一套 Doris 資料倉庫支撐了多個下遊資料應用系統的使用。這些應用系統對資料通路的資源消耗能力不同,對應的業務重要等級也不相同。為了能夠更好管理應用資源的使用,避免資源沖突,我們需要對應用賬号進行劃分和資源規劃,以保證多使用者在同一 Doris 叢集内進行資料操作時減少互相幹擾。而 Doris 的多租戶和資源隔離功能,可以幫助我們更合理地配置設定叢集資源。Doris 對于資源隔離控制有兩種方式,一是叢集内節點級别的資源組劃分,二是針對單個查詢的資源限制。這裡主要介紹下叢集内節點級别的資源組劃分過程。

第一步:需要梳理規劃各場景的用途、重要等級及資源需求等,舉例說明:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

第二步:對節點資源進行劃分、給節點打上 tag 标簽:

alter system modify backend "10.10.101.1:9050" set ("tag.location" = "group_a");
alter system modify backend "10.10.101.2:9050" set ("tag.location" = "group_a");
alter system modify backend "10.10.101.3:9050" set ("tag.location" = "group_b");
alter system modify backend "10.10.101.4:9050" set ("tag.location" = "group_b");
alter system modify backend "10.10.101.5:9050" set ("tag.location" = "group_c");
alter system modify backend "10.10.101.6:9050" set ("tag.location" = "group_c");
           

第三步:給應用下的表單指定資源組分布,将使用者資料的不同副本分布在不同資源組内

create table flume_etl<table>
(k1 int, k2 int)
distributed by hash(k1) buckets 1
properties(
   "replication_allocation"="tag.location.group_a:2, tag.location.group_b:1"
)

create table cdc_etl<table>
```
   "replication_allocation"="tag.location.group_b:2, tag.location.group_c:1"

create table etl<table>
```
   "replication_allocation"="tag.location.group_a:1, tag.location.group_c:2"

create table mkui_readonly<table>
```
   "replication_allocation"="tag.location.group_a:2, tag.location.group_c:1"

create table SaaS_readonly<table>
```
   "replication_allocation"="tag.location.group_a:1, tag.location.group_b:1, tag.location.group_c:1"

create table dev<table>
```
   "replication_allocation"="tag.location.group_a:1, tag.location.group_b:1, tag.location.group_c:1"
           

第四步:設定使用者的資源使用權限,來限制某一使用者的查詢隻能使用其指定資源組中的節點來執行。

set property for 'flume_etl' 'resource_tags.location' = 'group_a';
set property for 'cdc_etl' 'resource_tags.location' = 'group_b';
set property for 'etl' 'resource_tags.location' = 'group_c';
set property for 'mkui_readonly' 'resource_tags.location' = 'group_a';
set property for 'SaaS_readonly' 'resource_tags.location' = 'group_a, group_b, group_c';
set property for 'dev' 'resource_tags.location' = 'group_b';
           

值得一提的是,與社群交流中我們得知在即将釋出的 Apache Doris 2.0 版本中還基于 Pipeline 執行引擎增加了 Workload Group 能力。該能力通過對 Workload 進行分組管理,以保證記憶體和 CPU 資源的精細化管控。通過将 Query 與 Workload Group 相關聯,可以限制單個 Query 在 BE 節點上的 CPU 和記憶體資源的百分比,并可以配置開啟資源組的記憶體軟限制。當叢集資源緊張時,将自動 Kill 組内占用記憶體最大的若幹個查詢任務以減緩叢集壓力。當叢集資源空閑時,一旦 Workload Group 使用資源超過預設值時,多個 Workload 将共享叢集可用空閑資源并自動突破阙值,繼續使用系統記憶體以保證查詢任務的穩定執行。更詳細的 Workload Group 介紹可以參考:https://doris.apache.org/zh-CN/docs/dev/admin-manual/workload-group/

create workload group if not exists etl_group
properties (
   "cpu_share"="10",
   "memory_limit"="30%",
   "max_concurrency" = "10",
   "max_queue_size" = "20",
   "queue_timeout" = "3000"
);
           

批量建表

初始化完成 Doris 的建表映射往往需要建構許多表單,而單獨建表低效且易出錯。為此,我們根據官方文檔的建議使用 Cloudcanal 進行表結構同步來批量建表,大大提高了資料初始化的效率。

建表時需要注意的是:以 MySQL 為例,MySQL 資料源映射到 Doris 表結構的過程中需要進行一定的表結構調整。在 MySQL 中varchar(n) 類型的字段長度是以字元個數來計算的,而 Doris 是以位元組個數計算的。是以,在建表時需要将 Doris varchar 類型字段的長度調整到 MySQL 對應字段長度的 3 倍。在使用 Unique 模型時需要注意建表時 UNIQUE KEY 列要放在 Value 列前面聲明,且保證有序排列和設定多副本配置。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

除了以上方式,日前新釋出的 Doris-Flink-Connector 1.4.0 版本中已內建了 Flink CDC、實作了從 MySQL 等關系型資料庫到 Apache Doris 的一鍵整庫同步功能,使用者無需提前在 Doris 中建表、可以直接使用 Connector 快速将多個上遊業務庫的表結構及資料接入到 Doris 中。推薦大家嘗試使用。相關連結:https://mp.weixin.qq.com/s/Ur4VpJtjByVL0qQNy_iQBw

計算實作

根據我們對架構 2.0 的規劃,我們将所有計算轉移在 Doris 中完成。然而在支撐實時和準實時的場景下,具體的技術實作會有所不同,主要差別如下:

實時計算

如上文提到我們會以實時資料采集 + Doris 視圖模型的方式提供實時計算結果,而為了在計算過程中達到更高的資料時效支援,應該盡量減少不必要的資料備援設計。如傳統資料倉庫會按照 ODS->DWD->DWS->ADS 等分層逐層計算落表。而在實時計算場景下可以适當進行裁剪,裁剪的依據為整體查詢時效的滿足情況。此外,在實際的業務場景中也會有多層視圖嵌套調用的情況。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

準實時計算

在業務能接受的準實時場景下(10分鐘、30分鐘、小時級),可以通過實體表單 + 微批任務實作計算,計算過程按照排程層級依賴關系逐層完成。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

通過 Java UDF 生成增量/全量資料

在實際業務中,存在增量/全量的日、月、年等不同時間頻度資料生成需求。我們通過 Doris 的 Java UDF 功能(1.2 版本後支援) + 排程系統傳參的方式實作了一套腳本動态的生成增量/全量及日、月、年等不同的名額彙總。

實作思路:

  • period_type:計算頻度 D/W/M/Y 代表計算日、周、月、年
  • run_type:INC(增量)/ DF(全量)是通過傳遞begin_date,end_datel 來篩選 business_date資料進行彙總。
    • 增量滿足:begin_date(對應計算頻度開始日期) <= business_date <= end_date (對應計算頻度結束日期)
    • 全量滿足:begin_date(寫死一個業務最小日期) <= business_date <= end_date (對應計算頻度結束日期)

基于以上思路實作etlbegindate函數來傳回不同計算頻度下增量、全量的 begin_date

etlbegindate(run_type,period_type,end_date)
           

為了在統計不同頻度時能夠生成對應頻度的識别id 字段,我們還需要實作一個periodid 函數

periodid(period_type,business_date)
           

該函數的主要功能為:

  • period_type = 'D' 傳回 business_date 所在日, 'YYYYMMDD' 格式的 period_id 字段
  • period_type = 'W' 傳回 business_date 所在周的起始日期, 'YYYYMMDDYYYYMMDD' 格式的 period_id 字段
  • period_type = 'M' 傳回 business_date 所在月,'YYYYMM' 格式的 period_id 字段
  • period_type = 'Y' 傳回 business_date 所在年,'YYYY' 格式的 period_id 字段

結合 etlbegindate 與 periodid 兩個函數,假定目前時間為 2023 年 6 月 16 日則相應的實作如下:

SQL 腳本使用函數示例

-- 示例Demo
 select ${period_type}                          as period_type -- 統計頻度 D/W/M/Y
       ,period_id(${period_type},business_date) as period_id   -- 時間頻度ID
       ,count(goods_id)                         as goods_cnt   -- 商品數
  where business_date >= etlbegindate(${run_type},${period_type},${end_date})
    and business_date <= ${end_date}
group by period_id
           

運作排程前參數配置:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

任務運作結果示例:W/M/Y 是的實作方式一緻,隻是資料傳回的 period_id 格式會按照上文描述的格式輸出。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

基于以上方法,我們高效地為公司 SaaS 産品建構了相應的資料名額庫應用。

基于 Doris 的大表優化

我們的業務涉及基于使用者頁面通路和景區裝置日志資訊的統計分析業務,這類名額計算需要處理大量日志資料。接下來,我們将介紹如何利用 Doris 提供的功能對資料進行優化處理。

資料分區分桶:

Doris 支援兩級分區,第一級叫做 Partition,支援 Range Partitioning 和 List Partitioning 兩種分區政策。第二級分區叫做 Bucket,支援 Hash Partitioning 分區政策。

對于使用者浏覽行為的埋點事件表,我們按照時間做為分區(Range Partitioning):

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

在實際應用中,業務的曆史冷資料可以按年進行分區,而近期的熱資料可以根據資料量增幅按照日、周、月等進行分區。另外,Doris 自 1.2.0 版本後支援批量建立 RANGE 分區,文法簡潔靈活。

從 Doris 1.2.2 版本開始,Doris 支援了自動分桶功能,免去了在分桶上面的投入,一個分桶在實體層面為一個 Tablet,官方文檔建議 Tablet 大小在 1GB - 10GB 之内,Y是以對于小資料量分桶數不應太多。自動分桶的開啟隻需要建表時新增一個屬性配置:

DISTRIBUTED BY HASH(openid) BUCKETS AUTO PROPERTIES ("estimate_partition_size" = "1G")
           

Like Query 和 SEQUENCE_COUNT 介紹

Like Query

在使用埋點日志資料進行漏鬥分析時,需要針對某些特定 URL 資料進行彙總分析。這些 URL 中帶有參數資訊,以 String 或者 Varchar 類型存儲為例,在計算過程中需要對含有特定參數的資料進行篩選。

根據該 Issue:https://github.com/apache/doris/pull/10355,我們了解到 Doris 對于 like/not like 有一定的優化處理,操作符可以下推到存儲引擎進行資料過濾。是以在這個場景下,我們嘗試使用 like 操作符對資料進行篩選處理。

另外在 Apache Doris 2.0 版本中将增加 Ngram BloomFilter 索引,使用該索引可以用來提升 Like Query 的性能,未我們也将進行更新使用。Doris 提供了gram_size 和 bf_size兩個參數進行配置,示例如下:

CREATE TABLE `test_ngrambf` (
  `id` int(11),
  `str` varchar(32),
  INDEX idx_str (`str`) USING NGRAM_BF PROPERTIES("gram_size"="3", "bf_size"="256")
) ENGINE=OLAP
DUPLICATE KEY(`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);

mysql> INSERT INTO test_ngrambf VALUES (1, 'hello world'), (2, 'ngram test');
Query OK, 2 rows affected (0.18 sec)
{'label':'insert_fbc5d3eca7204d52_965ce9de51508dec', 'status':'VISIBLE', 'txnId':'11008'}

mysql> SELECT * FROM test_ngrambf WHERE str LIKE '%hel%';
+------+-------------+
| id   | str         |
+------+-------------+
|    1 | hello world |
+------+-------------+
1 row in set (0.03 sec)

mysql> SELECT * FROM test_ngrambf WHERE str LIKE '%abc%';
Empty set (0.02 sec)

mysql> SELECT * FROM test_ngrambf WHERE str LIKE '%llm%';
Empty set (0.04 sec)
           

下面對 Ngram BloomFilter 索引的原理作簡要介紹:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

假如将“hello world"存入 Bloom Filter 中,将gram_size 配置為 3,這時會将"hello world"分為["hel", "ell", "llo",...]分别進行存儲,每個 gram 通過 N 個哈希函數 h1, h2, ..., hn 映射到 Bloom Filter中,對應的索引值設為 1。當處理where column_name like 'hel'這樣的查詢語句時,'hel'會經過相同哈希函數的映射和 Bloom Filter 進行比較,如果映射出的索引和 Bloom Filter 的索引的值都是 1,那麼判斷'hel'在Bloom Filter 中(True Positive),但也存在一定機率會将本來不在 Bloom Filter 中的元素判斷為在集合中(False Positive),比如上圖中的'llm',但将其判斷為不在 Bloom Filter 中的元素(True Negative)一定不會存在,比如圖中的過濾條件like 'abc'。

在實際使用 Ngram BloomFilter 索引時有一些注意事項:

  • 使用 Ngram BloomFilter 索引時需要根據實際查詢情況合理配置gram_size的大小。小的gram_size 支援搜尋查詢更多的 String,但是同時也帶來更多數量的 ngram 和需要應用更多的哈希函數,這将會增大 False Positive 的機率。
  • 因為存在 False Positive 的可能性,Ngram BloomFilter 索引不能被用來處理 column_name != 'hello'或者 column_name not like '%hello%'這樣使用負運算符的過濾條件。

SEQUENCE_COUNT

針對使用者留存或漏鬥分析等名額的計算,可以使用 Doris 提供的 SEQUENCE_COUNT(pattern, timestamp, cond1, cond2, ...) 函數。這裡 pattern 參數用來指定使用者一系列浏覽行為的事件鍊,比如:

-- 計算使用者浏覽商品、加入購物車以及支付這一連串事件的數量
SELECT SEQUENCE_COUNT('(?1)(?2)(?3)', timestamp, event = 'view_product', event = 'add_cart', event = 'pay') FROM user_event;
           

通過 SEQUENCE_COUNT 可以非常友善地計算我們指定的事件鍊的數量。

Doris Borker 的協同計算

業務中存在部分大資料量的曆史資料統計需求,針對這部分需求我們進行了協同計算處理

  • FlinkCDC 讀取 Binglog 實時同步資料到 Doris 明細表
  • Doris 明細表會存儲近 30 日熱資料(需要進行 TTL 管理)
  • Doris 每日通過 Borker Export 同步一份日增量資料至 HDFS,并加載至 Hive 中
  • Hive 中儲存所有明細資料,資料初始化生成計算結果在 Hive 中完成 Borker Load 至 Doris
  • Doris 在生成結果資料時僅生成目前日期資料,每天的增量生成沉澱為曆史結果
  • 當業務有需要時通過 Borker Export 加載 Hive 全量計算結果重新整理 Doris 結果表
  • 當業務有基于此明細資料的新開發需求時,可在 Hive 中計算完成初始化結果至 Doris
Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

資料導出(Export): Export 是 Doris 提供的一種将資料導出的功能。該功能可以将使用者指定的表或分區的資料以文本的格式,通過 Broker 程序導出到遠端存儲上,如 HDFS 或對象存儲(支援 S3 協定) 等。使用者送出一個 Export 作業後,Doris 會統計這個作業涉及的所有 Tablet,然後對這些 Tablet 進行分組,每組生成一個特殊的查詢計劃。這些查詢計劃會讀取所包含的 Tablet 上的資料,然後通過 Broker 将資料寫到遠端存儲指定的路徑中。

資料導入(Broker load): Broker Load 是 Doris 的一種異步資料導入方式,可以導入 Hive、HDFS 等資料檔案。Doris 在執行 Broker Load 時占用的叢集資源比較大,一般适合資料量在幾十到幾百 GB 級别下使用。同時需要注意的是單個導入 BE 最大的處理量為 3G,如果超過 3G 的導入需求就需要通過調整B roker Load 的導入參數來實作大檔案的導入。

聯邦查詢在資料分析場景下的嘗試

由于上遊資料源較多,我們僅對常用的資料表單進行了資料倉庫采集模組化,以便更好地進行管理和使用。對于不常用到的資料表單,我們沒有進行入倉,但業務方有時會臨時提出未入倉資料的統計需求,針對這種情況,我們可以通過 Doris 的 Multi-Catalog 進行快速響應、完成資料分析 ,待需求常态化後再轉換成采集模組化的處理方式。

Multi-Catalog 是 Doris 1.2.0 版本中推出的重要功能。該功能支援将多種異構資料源快速的接入 Doris,包括 Hive、Iceberg、Hudi、MySQL、Elasticsearch 和 Greenplum 等。使用 Catalog 功能,可以在 Doris 中統一的完成異構資料源之間的關聯計算。Doris 1.2.0 以後的版本官方推薦通過 Resource 來建立 Catalog,這樣在多個使用場景下可以複用相同的 Resource。下面是 Doris 本地表與通過 Multi-Catalog 映射的遠端表單組合完成關聯計算的場景示例。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

Multi-Catalog 帶來的收益:

  • 更高的靈活性:通過 Multi-Catalog,使用者可以靈活地管理不同資料源的資料,并在不同的資料源之間進行資料交換和共享。這可以提高資料應用的可擴充性和靈活性,使其更适應不同的業務需求。
  • 高效的多源管理:由于 Multi-Catalog 可以管理多個資料源,使用者可以使用多個 Catalog 來查詢和處理資料,解決了使用者跨庫通路不便的問題,進而提高資料應用的效率。

社群中已經有非常多的夥伴基于 Multi-Catalog 功能落地了應用場景。另外如果要深度使用該功能,建議建立專門用于聯邦計算的 BE 節點角色,當查詢使用 Multi-Catalog 功能時,查詢會優先排程到計算節點。

運維保障

守護程序

為了保障 Doris 程序的持續運作,我們按照 Doris 官網的建議在生産環境中将所有執行個體都的守護程序啟動,以保證程序退出後自動拉起。我們還安裝部署了Supervisor 來進行程序管理,Supervisor 是用 Python 開發的一套通用的程序管理程式,可以将一個普通的指令行程序變為背景 Daemon 并監控程序狀态,當程序異常退出時自動重新開機。使用守護程序後,Doris 的程序變成了 Supervisor 的子程序,Supervisor 以子程序的 PID 來管理子程序,并可以在異常退出時收到相應的信号量。

配置 Supervisor 時的注意事項:

  • 通過 supervisorctl status查詢出來的程序 id 不是 Fe、Be、Broker 的程序 ID,而是啟動它們的 Shell 程序 ID。在 start_xxx.sh中會啟動真正的 Doris 程序,是以才有了程序樹的說法。
  • stopasgroup=true ;是否停止子程序、killasgroup=true ;是否殺死子程序,需要保證這兩個參數為true,否則通過 supervisorctl控制 Doris 的背景程序是無效的,這也是通過 Supervisor 守護 Doris 程序的關鍵。

配置完 Supervisor 後則通過守護程序的方式來管理 FE、BE、Borker……

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

由于 Superviosr 自帶的 Web UI 不支援跨機器管理,當多節點時管理非常不便,這裡可以使用 Cesi 來對 Supervisor 進行合并管理:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

Grafana 監控報警

關于 Doris 的運作監控,我們按照官網相關内容部署了 Prometheus 和 Grafana ,并進行監控項的采集。同時對于一些關鍵名額進行了預報警,利用企微 Bot 完成資訊推送。

以下為測試環境示例圖:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

叢集CPU空閑情況:

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

叢集記憶體使用情況: 之前發現叢集存在記憶體洩露

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

BDBJE 寫入情況: 超過秒級可能會出現中繼資料寫入延遲的問題

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

開始排程運作的 Tablet 數量: 正常情況該值基本為 0 或個位數,出現波動的 Tablet 說明可能在進行 Recovery 或 Balance。

Apache Doris 在拈花雲科的統一資料中台實踐,One Size Fits All

除此之外,我們還使用 QPC/99th Latency……等名額來檢視監測叢集服務能力,建議可以在 Doris 監控的基礎上額外加入叢集機器的監控,因為我們的機器部署在VM中,曾經出現過硬碟問題、記憶體問題、網絡波動、專線異常等情況,多一層報警機制就多一份穩定性保障。

總結收益

通過新架構的成功搭建,實作了以 Apache Doris 為核心資料倉庫 + OLAP 引擎的使用方式(All in One),有效縮減了資料處理流程,大大降低了投遞型項目的實施成本。在舊架構下,需要部署、适配、維護非常多的元件,無論是實施還是運維都會比較繁重。相比之下,新架構下的 Doris 易于部署、擴充和維護,組合方案也靈活多變。在我們近半年的使用時間内,Doris 運作非常穩定,為項目傳遞提供了強有力的計算服務保障能力。

此外,基于 Apache Doris 豐富的功能、完善的文檔,我們可以針對離線和線上場景進行高效且細緻的資料開發和優化。通過引入 Doris 我們在資料服務時效性方面也有了大幅提高,目前我們已經成功地落地了多個資料項目,并孵化出了一個基于 Doris 的 SaaS 産品。同時,Doris 擁有一個成熟活躍的社群,SelectDB 技術團隊更是為社群提供了一支全職的技術團隊,推動産品疊代、解決使用者問題,也正是這強有力的技術支援,幫助我們更快上線生産,快速解決了我們在生産運用中遇到的問題。

未來規劃

未來,我們将密切關注 Apache Doris 社群的發展,并計劃建構基于 K8S 的 Doris 服務方式。在項目傳遞場景下,常常需要進行整套環境的部署。目前,我們已經在 K8S 上內建了 2.0 版本架構下除 Doris 以外的其他資料服務元件。随着 Doris 社群 2.0 版本全面支援 K8S 的計劃,我們也會将方案內建到我們的新體系中,以友善後期的項目投遞。除此之外,我們還将結合 Doris 的功能特性提煉基于 Doris 的數倉方法論,優化開發過程。Doris 是一個包容性非常好的存儲計算引擎,而想要将原有的資料倉庫開發内容全部适配在 Doris 上還需要不斷的學習、優化與調整,以充分發揮 Doris 的優勢,同時我們也将在此基礎上沉澱一套與之相比對的開發規範。

最後,我非常推薦大家使用 Apache Doris 作為資料項目的解決方案。它具有功能強大、包容性強、社群活躍、疊代更新快等優勢,這些優勢将助推你的項目達成目标。在此,我要感謝 Apache Doris 社群和 SelectDB 的同學們給予我們的支援和幫助,也祝願 Apache Doris 社群越來越壯大。