巴別時代基於 Apache Paimon 的 Streaming Lakehouse 的探索與實踐

ApacheFlink發表於2023-05-04

摘要:本文主要介紹巴別時代基於 Apache Paimon(Incubating) 構建 Streaming Lakehouse 的生產實踐經驗。我們基於 Apache Paimon(Incubating) 構建 Streaming Lakehouse 的落地實踐主要分為三期:

第一期是在調研驗證的基礎上進行數倉分層,並且上線一些簡單的業務驗證效果;第二期是實現流式數倉的基礎設施建設,以便優先替換當前基於 Apache Kafka 構建的實時數倉;第三期主要是完善 Paimon 的生態建設,包括資料資產、資料服務等平臺服務建設,主要目標是提供完整的基於 Apache Paimon(Incubating) 端到端的平臺服務能力。目前基本完成第一期的數倉分層,同時進行資料質量驗證,基本可以滿足業務需求。

我們基於 Apache Paimon(Incubating) 構建 Streaming Lakehouse 的落地實踐主要分為三期:第一期是在調研驗證的基礎上進行數倉分層,並且上線一些簡單的業務驗證效果;第二期是實現流式數倉的基礎設施建設,以便優先替換當前基於 Apache Kafka 構建的實時數倉;第三期主要是完善 Paimon 的生態建設,包括資料資產、資料服務等平臺服務建設,主要目標是提供完整的基於 Apache Paimon(Incubating) 端到端的平臺服務能力。目前基本完成第一期的數倉分層,同時進行資料質量驗證,基本可以滿足業務需求。

點選進入 Apache Paimon 官網

1. 業務背景

基於 Apache Kafka 構建的實時數倉過程中我們遇到一些痛點,例如中間層資料不可分析,資料保留時間短等問題,同時我們的實時數倉是基於 Flink+Kafka+Redis+ClickHouse 構建的,難以查詢和分析 Kafka 的中間層資料和 Redis 的維表資料。目前只有 ADS 層資料最終寫入到 ClickHouse 裡才能分析,但是 ClickHouse 對於資料更新支援的不是很好,所以我們需要透過寫入重複資料的方式以達到更新的效果,ClickHouse 去重表執行操作也是非同步的,這就需要在業務端進行資料去重,大大增加了業務 SQL 的複雜度,也有一定程度的效能損耗,並且 ClickHouse 不支援事務,很難做到 Flink 到 ClickHouse 端到端的資料一致性保障。

基於以上痛點,我們希望能夠藉助當下比較流行的資料湖儲存方案簡化我們的數倉架構,提高資料分析的效率,降低資料儲存和開發成本,最終選擇 Apache Paimon 作為湖倉底座,主要是基於以下幾個方面的考量:

  • Apache Paimon(Incubating) 基於 LSM 的強大的資料更新能力正是我們需要的,基於PK進行資料更新以及 Partial Update 的部分更新和 Aggregate 表的預聚合能力能夠大大簡化我們的業務開發的複雜度。
  • Apache Paimon(Incubating) 當時作為 Apache Flink 的子專案,對於 Flink 整合的成熟度也是我們所考量的,Apache Paimon(Incubating) 支援所有的 Flink SQL 語法,對於 Flink 整合的優先支援是較其他資料湖框架優勢的地方。
  • Flink Forward Asia 2021 的主題演講裡,Apache Flink 中文社群發起人王峰老師提出流式數倉的概念,即整個數倉的資料全部實時流動起來,Paimon 就是在此背景下推出的流批一體的儲存,是 Flink 在推動流批一體演進中儲存領域上的重要一環,流式數倉作為新型數倉架構演進的一種方案,而 Paimon 作為流式湖倉的標杆,毋庸置疑成為構建流式數倉的首選,隨著社群不斷髮展和框架本身的成熟,Paimon 將成為 Streaming Lakehouse 領域的標準。
  • 調研測試過程中發現之前遇到的業務問題和需求透過在社群群中提問,能夠得到社群各位老師的耐心答疑,反饋的相關問題能夠得到社群的快速響應和 Bug 修復,促成最終選擇 Apache Paimon(Incubating) 方案,打消使用 Apache Paimon(Incubating) 的諸多疑慮。

在此特別鳴謝之信老師、曉峰老師以及 Paimon 社群的各位開發者的支援。

2. 數倉架構

目前我們完成基於 Paimon 的數倉分層的設計,包括 ODS,DWD,DIM 層的搭建以及 DWS 層一些業務模型的建設,整體架構如下:

1

2.1 資料來源

我們的資料來源主要包括前端和後端打點日誌以及業務資料庫的 Binlog,打點日誌按專案透過 Filebeat 採集到 Kafka 對應的 Topic, 然後透過 Flink SQL 同步到湖倉的 ODS 層,業務庫的資料透過 FlinkCDC 整庫同步到湖倉的 ODS 層的 Paimon 表。

2.2 湖倉建設

湖倉主要基於 Apache Paimon(Incubating) 構建,各層都是透過 Flink SQL 進行資料的準實時同步。ODS 層採用 Paimon 的 Append Only 表,保留資料原貌不做更新。DIM 層採用 Paimon 的 PK 表,部分維表需要使用 Partial Update 能力保留最新的維表資料。

DWD 層也採用 Paimon 的 PK 表,ODS 層的表資料經由 Flink SQL 做 ETL 清洗,並透過 Retry Lookup Join 關聯維表拉寬後寫入到 DWD 層對應的 Paimon 表裡,由於維表資料可能晚於事實資料到達湖倉,存在 Join 不上的情況,所以這裡需要增加重試機制。DWS 層主要是分主題進行數倉建模,目前主要採用 Paimon 的 Agg 表進行一些預聚合模型及大寬表的建設,ADS 層主要將 DWS 層的結果資料和 DWD 層的一些明細表資料流讀到 ClickHouse 線上系統,提供線上服務使用。

2.3 線上系統

透過 Flink SQL 將 DWS 層的結果資料和 DWD 的一些明細表資料近實時地流讀到 ClickHouse 線上系統進行 OLAP 分析,提供 BI 實時報表,大屏展示以及使用者行為分析系統等使用,同時擴充套件 Paimon 的 Presto 聯結器,資料分析師可以使用 Presto 引擎進行 Adhoc 查詢和資料撈取工作。

2.4 平臺服務

我們的湖倉目前使用 Paimon 的 Hive Catalog, 基於 HMS 做後設資料的統一管理,其中資料開發是基於 Dinky 做得二次開發,使用 Dinky 在 Flink SQL 開發這塊兒的能力,資料指標基於不同型別的遊戲進行梳理,以便構建統一的指標體系。後面考慮基於 Paimon 構建資料資產以及資料服務。

3. 生產實踐

介紹業務生產實踐之前,首先介紹一些 Paimon 的正確使用姿勢,以便更好理解以下的業務建表實踐。

Merge Engine

指定 Merge Engine 的作用是把寫到 Paimon 表的多條相同 PK 的資料合併為一條,使用者可以透過 merge-engine 配置項選擇以何種方式合併同 PK 的資料。

Paimon 支援的 Merge Engine 包括:

  • deduplicate:如果使用者建表時不指定 merge-engine 配置,建立的 PK 表預設的 Merge Engine 是 deduplicate 即只保留最新的記錄,其他的同 PK 資料則被丟棄,如果最新的記錄是 DELETE 記錄,那麼相同 PK 的所有資料都將被刪除。
  • partial-update:如果使用者建表時指定'merge-engine' = 'partial-update',那麼就會使用部分更新表引擎,可以做到多個 Flink 流任務去更新同一張表,每條流任務只更新一張表的部分列,最終實現一行完整的資料的更新,對於需要拉寬表的業務場景,partial-update 非常適合此場景,而且構建寬表的操作也相對簡單。這裡所說的多個 Flink 流任務並不是指多個 Flink Job 併發寫同一張 Paimon 表,這樣需要拆分 Compaction 任務,就不能在每個 Job 的 Writer 端做 Compaction, 需要一個獨立的 Compaction 任務,比較麻煩。目前推薦將多條 Flink 流任務 UNION ALL 起來,啟動一個 Job 寫 Paimon 表。這裡需要注意的是,對於流讀場景,partial-update 表引擎需要結合 Lookup 或者 full-compaction 的 Changelog Producer 一起使用,同時 partial-update 不能接收和處理 DELETE 訊息,為了避免接收到 DELETE 訊息報錯,需要透過配置 'partial-update.ignore-delete' = 'true' 忽略 DELETE 訊息。
  • aggregation:如果使用者建表時指定 'merge-engine' = 'aggregation',此時使用聚合表引擎,可以透過聚合函式做一些預聚合,每個除主鍵以外的列都可以指定一個聚合函式,相同主鍵的資料就可以按照列欄位指定的聚合函式進行相應的預聚合,如果不指定則預設為 last-non-null-value ,空值不會覆蓋。Agg 表引擎也需要結合 Lookup 或者 full-compaction 的 Changelog Producer 一起使用,需要注意的是除了 SUM 函式,其他的 Agg 函式都不支援 Retraction,為了避免接收到 DELETE 和 UPDATEBEFORE 訊息報錯,需要透過給指定欄位配置 'fields.${field_name}.ignore-retract'='true' 忽略。

Changelog Producer

Changelog 主要應用在流讀場景,在數倉各層的建設過程中,我們需要流讀上游的資料寫入到下游,完成各層之間的資料同步,做到讓整個數倉的資料全實時地流動起來。如果上游流讀的 Source 是業務庫的 Binlog 或者 Kafka 等訊息系統的訊息,直接生成完整的 Changelog 以供流讀的。

但是目前數倉分層是在 Paimon 裡做的,資料以 Table Format 的形式儲存在檔案系統上,如果下游的 Flink 任務要流讀 Paimon 表資料,需要儲存幫助生成 Changelog(成本較低,但延遲相對較高),以便下游流讀的,這時就需要我們在建表時指定 Paimon 的 Changelog Producer 決定以何種方式在何時生成 Changelog。如果不指定則不會在寫入 Paimon 表的時候生成 Changelog,那麼下游任務需要在流讀時生成一個物化節點來產生 Changelog。這種方式的成本相對較高,同時官方不建議這樣使用,因為下游任務在 State 中儲存一份全量的資料,即每條資料以及其變更記錄都需要儲存在狀態中。

Paimon 支援的 Changelog Produer 包括:

  • none:如果不指定,預設就是 none,成本較高,不建議使用。
  • input:如果我們的 Source 源是業務庫的 Binlog ,即寫入 Paimon 表 Writer 任務的輸入是完整的 Changelog,此時能夠完全依賴輸入端的 Changelog, 並且將輸入端的 Changelog 儲存到 Paimon 的 Changelog 檔案,由 Paimon Source 提供給下游流讀。透過配置 'changelog-producer' = 'input',將 Changelog Producer 設定為 input 。
  • lookup:如果我們的輸入不是完整的 Changelog, 並且不想在下游流讀時透過 Normalize 節點生成 Changelog, 透過配置 'changelog-producer' = 'lookup',透過 Lookup 的方式在資料寫入的時候生成 Changelog,此 Changelog Produer 目前處於實驗狀態,暫未經過大量的生產驗證。
  • full-compaction:除了以上幾種方式,透過配置 'changelog-producer' = 'full-compaction' 將 Changelog Producer 設定為 full-compaction,Writer 端在 Compaction 後產生完整的 Changelog,並且寫入到 Changelog 檔案。透過設定 changelog-producer.compaction-interval 配置項控制 Compaction 的間隔和頻率,不過此引數計劃棄用,建議使用 full-compaction.delta-commits,此配置下預設為1 即每次提交都做 Compaction。

Append Only Table

建表時配置 'write-mode' = 'append-only',使用者可以建立 Append Only 表。Append Only 表採用追加寫的方式,只能插入一條完整的記錄,不能更新和刪除,也無需定義主鍵。Append Only 表主要用於無需更新的場景,例如 ODS 層資料將 Kafka 埋點日誌資料解析後寫入到 Paimon 表,保留原貌不做任何更新,此時推薦採用 Paimon 的 Append Only 表。

需要注意的是由於 Append Only 表沒有主鍵,使用者必須指定 bucket-key,否則採用整行資料做 Hash 效率偏低。

3.1 ODS 層入湖

3.1.1 業務庫資料入湖

業務庫資料入湖,我們使用的是 FlinkCDC 的整庫同步,目前是基於 Dinky 實現的 FlinkCDC 到 Paimon 的整庫同步能力(這裡要特別鳴謝文末老師的支援),可以自動建表,多表或整庫同步業務庫資料到 Paimon 的對應庫。由於我們是每個專案一個業務庫,所以在 Paimon 中也是按專案建庫,與 MySQL 中業務庫對應,以下是部分專案的圖示:

2

入湖 SQL:

下面以一個專案的入湖 SQL為例:

EXECUTE CDCSOURCE cdc_demo WITH (
    'connector' = 'mysql-cdc',
    'hostname' = 'localhost',
    'port' = '3306',
    'username' = 'username',
    'password' = 'password',
    'checkpoint' = '30000',
    'scan.startup.mode' = 'initial',
    'source.server-time-zone' = 'Asia/Tokyo',
    'parallelism' = '4',
    'database-name' = 'demo',
    'sink.connector' = 'sql-catalog',
    'sink.catalog.name' = 'fts_hive',
    'sink.catalog.type' = 'fts_hive',
    'sink.catalog.uri' = 'thrift://localhost:9083',
    'sink.bucket' = '4',
    'sink.snapshot.time-retained' = '24h',
    'table-list' = 'A01,A02,A03,A04,A05',
    'sink.changelog-producer' = 'input',
    'sink.catalog.warehouse' = 'hdfs://cluster/warehouse/table_store',
    'sink.sink.db' = 'fts_ods_db_demo'
);

FlinkCDC 整庫同步目前還是基於單表單 Task 的形式, 執行效果如下所示:

3

3.1.2 日誌資料入湖

日誌入湖是透過 Flink SQL 將 Kafka 中的日誌資料同步到 ODS 層的 Paimon 表,ODS 層埋點日誌沒有確定型別,避免由於型別轉換過濾掉資料,這裡以使用者登入日誌為例,介紹日誌資料入湖:

入湖 SQL:

--CREATE TABLE
create table t_ods_table(
      ......
    gn string,
    dt string 
 ) partitioned by (gn,dt) 
WITH (
    'bucket' = '8',
    'bucket-key' = 'id',
    'write-mode' = 'append-only', --建立 Append Anly 表
    'snapshot.time-retained' = '24h'
);

--INSERT
create table default_catalog.default_database.role_login (
    message string,
    fields row < project_id int,
    topic string,
    gn string >
) with (
    'connector' = 'kafka',
    'topic' = 'topic',
    'properties.bootstrap.servers' = '${kafka_server}',
    'properties.group.id' = 'topic_group',
    'scan.startup.mode' = 'earliest-offset',
    'format' = 'json'
);
insert into
    fts_ods_log.t_ods_table
select
      ......
      cast(SPLIT_INDEX(message, '|', 5) as int) log_create_unix_time,
    fields.gn gn,
    FROM_UNIXTIME(
        cast(SPLIT_INDEX(message, '|', 5) as int),
        'yyyy-MM-dd'
    ) dt
from
    default_catalog.default_database.role_login
where
  try_cast(SPLIT_INDEX(message, '|', 5) as int) is not null
  and cast(SPLIT_INDEX(message, '|', 5) as int) between 0 and 2147483647;

日誌資料入湖的執行效果如下所示:

4

3.2 DIM 層入湖

DIM 層資料主要是將 ODS 層多個業務庫的相同表的資料同步到 DIM 層對應的表,比如 fts_ods_db_A 和 fts_ods_db_B 都有同名的表 A01,需要 ODS 不同業務庫中同名的表同步 DIM 層的 fts_dim 庫中的 t_dim_A01 表中,該表的更新頻率較低且資料量較小。也有的是業務庫表和日誌表資料透過 Partial Update 能力拉寬後形成的維表。這裡以 tdim_A01 表為例,介紹 DIM 層資料入湖:

入湖 SQL:

--CREATE TABLE
create table t_dim_A01(
    ......
    gn string,
    PRIMARY KEY (gn,lid) NOT ENFORCED
) WITH (
    'bucket' = '4',
    'snapshot.time-retained' = '24h'
);
--INSERT
insert into
    fts_dim.t_dim_A01
select
    'AA' as gn,
    ......
from
    fts_ods_db_A.A01
union all
select
    'BB' as gn,
    ......
from
    fts_ods_db_B.A01
......

3.3 DWD 層入湖

DWD 層資料入湖是透過 Flink SQL 清洗過濾,關聯維表後形成寬表寫入到 DWD 層的 Paimon 表。維表也是在 Paimon 中,所以這裡很方便透過 Lookup Join 關聯維表,由於維表資料可能會晚於事實表資料到達 Paimon, 所以使用 Retry Lookup Join,如果事實表一開始關聯不上維表,可以增加一些重試,以便能夠關聯上維表資料,這裡以使用者登入表為例。

入湖 SQL:

--CREATE TABLE
create table t_dwd_table(
    ......
    id string,
    gn string,
    dt string,
    PRIMARY KEY (gn, id, log_create_unix_time, dt) NOT ENFORCED
) partitioned by (gn, dt) WITH (
    'bucket' = '8',
    'bucket-key' = 'id',
    'changelog-producer' = 'full-compaction',
    'changelog-producer.compaction-interval' = '54s',
    'snapshot.time-retained' = '24h'
);
--INSERT
create view default_catalog.default_database.t_table_view as (
    select
        ......
        PROCTIME() proc_time,
        gn,
        dt
    from
        fts_ods_log.t_ods_table
    where
        AA is not null
        and try_cast(BB as int) is not null
        and try_cast(CC as int) is not null
)
insert into
    fts_dwd.t_dwd_table
select
    /*+ LOOKUP('table'='fts_dim.t_dim_A01', 'retry-predicate'='lookup_miss', 'retry-strategy'='fixed_delay', 'fixed-delay'='10s','max-attempts'='30'),
     LOOKUP('table'='fts_dim.t_dim_A02', 'retry-predicate'='lookup_miss', 'retry-strategy'='fixed_delay', 'fixed-delay'='10s','max-attempts'='30'),
     LOOKUP('table'='fts_dim.t_dim_A03', 'retry-predicate'='lookup_miss', 'retry-strategy'='fixed_delay', 'fixed-delay'='10s','max-attempts'='30')*/
    ......
    cast(d.open_date_time as int) open_date_time,
    cast(d.merge_server_time as int) merge_server_time,
    CONCAT(a.aa, a.bb) id,
    a.gn,
    a.dt
from
    default_catalog.default_database.t_table_view as a
    left join fts_dim.t_dim_A01 for SYSTEM_TIME AS OF a.proc_time as b on a.AA = b.AA
    and a.BB = b.BB
    left join fts_dim.t_B01 for SYSTEM_TIME AS OF a.proc_time as c on a.AA = c.AA
    and a.BB = c.BB
    left join fts_dim.t_dim_C01 for SYSTEM_TIME AS OF a.proc_time as d on a.AA = d.AA
    and a.BB = d.BB;

3.4 DWS 層入湖

DWS 主要是分主題,按不同的維度進行聚合,我們也有一些寬表需要有聚合的列,也放在 DWS 層構建。這裡以角色域的一張角色寬表為例,介紹 DWS 層使用 Paimon 的 Agg 表做預聚合的場景。

角色寬表的建表語句如下:

CREATE TABLE t_dws_role(
    ......
    gn string,
    id bigint,
    aa int,
    bb int,
    acc int,
    PRIMARY KEY (gn, id) NOT ENFORCED
) WITH (
    'bucket' = '16',
    'bucket-key' = 'id',
    'merge-engine' = 'aggregation', --指定使用 Agg 表引擎
    'changelog-producer' = 'full-compaction', --指定 changelog producer 為 full-compaction
    'changelog-producer.compaction-interval' = '40s', --指定 campaction 的間隔為40秒
    'fields.aa.aggregate-function' = 'max',
    'fields.bb.aggregate-function' = 'min',
    'fields.acc.aggregate-function' = 'sum',
      'fields.aa.ignore-retract' = 'true', --忽略掉 retract,避免接收到 DELETE 訊息出錯
     ......
    'snapshot.time-retained' = '24h' --指定 snapshot 檔案保留24小時
);

角色寬表需要由 DWD 層的多張表關聯生成。基於 Paimon 的 Agg 表引擎建立,PK 為 gn + id 構成的聯合主鍵, 只要我們需要關聯的表與角色表有相同的主鍵就可以很方便的做到部分更新和預聚合,所以角色表,登入登出表等都比較好處理,但是登錄檔和前端日誌表是沒有 roleid的,沒法直接寫入角色寬表做處理,因為主鍵不同。

這裡我們首先想到是不是可以透過流 Join 的形式,分別給登錄檔和前端日誌表添上 roleid, 這樣就與角色表有相同的 PK, 就可以更新和聚合了。但是流 Join 的方式需要儲存的狀態就相對要大。

所以我們最終是透過 Paimon 的 Partial Update 將登錄檔和前端日誌表做成一張維表,然後 Flink SQL 流讀 DWD 層角色表寫入角色寬表的時候和維表做 Lookup Join, 最終補全一些欄位。由於登錄檔和前端日誌表的資料都可能先於角色表的資料到達 Paimon,所以需要用 Retry Lookup Join,保證能夠 Join 上。

還有需要做特殊處理的就是訂單表,比如角色寬表中有累積付費欄位,來自於訂單表,每個角色的累積付費需要用訂單表中的充值金額做 SUM 聚合,但是訂單表可能出現重複資料,比如發現訂單資料有問題或是缺數,都可能在 CDC 端進行重跑來修復或補全資料,由於 DWD 層的訂單表是 PK 表,過來重複資料就會在changelog 檔案中儲存 -U 和 +U 的記錄,這樣 Flink SQL 流讀訂單表寫到角色寬表做聚合時,過來重複的資料就會重複求和,計算結果就不準了,這裡使用 audit_log 系統表過濾 Changelog, 只要 +I 的記錄,過濾掉 -U 和 +U 的記錄,忽略掉更新的訂單資料,這樣也會存在一定的問題,比如丟失訂單的更新資料,不過充值金額一般是極少更新的。

audit_log 系統表使用示例:

SELECT * FROM MyTable$audit_log where rowkind='+I'

下面先介紹下注冊表和 foreend 表透過 Partial Update 構建維表的示例:

建表語句:

CREATE TABLE t_dim_table (
    gn string,
    ......
    PRIMARY KEY (gn, id) NOT ENFORCED
) WITH (
    'bucket' = '8',
    'bucket-key' = 'id'
    'merge-engine' = 'partial-update', --指定 merge engine 為部分更新列
    'changelog-producer' = 'full-compaction', --指定 changelog producer 為 full-compaction
    'changelog-producer.compaction-interval' = '48s', --compaction 間隔48秒
    'snapshot.time-retained' = '24h',
      'partial-update.ignore-delete' = 'true' --忽略 DELETE 資料
);

插入 SQL:

--省略 Flink SQL 引數設定
INSERT INTO 
        fts_dim.t_dim_table
SELECT 
    gn,
    id,
    ......
    CAST(NULL AS STRING),
    CAST(NULL AS STRING),
    unix_timestamp()
FROM
      fts_dwd.t_dwd_table
UNION ALL
SELECT 
      gn,
      id,
    CAST(NULL AS STRING),
    CAST(NULL AS INT),
    ......
    unix_timestamp()
FROM
      fts_dwd.t_dwd_foreend 
WHERE pid <> '0'

執行效果如下所示:

5

可以看到,在資料寫入頻率比較高,Compaction時間間隔設定的比較短的時候,Writer端存在一定的壓力,經常處於Busy狀態。

角色寬表入湖 SQL:

--省略 Flink SQL 引數設定
CREATE view default_catalog.default_database.t_view AS
SELECT
    ......
    id,
    gn,
    PROCTIME() AS proc_time
FROM
    fts_dwd.t_dwd_table
--插入資料
INSERT INTO
    fts_dws.t_dws_role
SELECT
    ......
    id,
    CAST(NULL AS STRING),
    unix_timestamp(),
FROM
    (
        SELECT
            /*+ LOOKUP('table'='fts_dim.t_dim_register', 'retry-predicate'='lookup_miss', 'retry-strategy'='fixed_delay', 'fixed-delay'='10s','max-attempts'='30')*/
            a.*,
            b.aa,
            b.bb
        FROM
            (
                  SELECT
                    *
                FROM
                    default_catalog.default_database.t_view
            ) AS a
            LEFT JOIN fts_dim.t_dim_table for SYSTEM_TIME AS OF a.proc_time AS b ON a.AA = b.AA
            AND a.BB = b.BB
    )
UNION ALL
SELECT
    ......
    createt_time,
    unix_timestamp(),
    CAST(NULL AS INT)
FROM
    fts_dwd.`t_dwd_o_table$audit_log`
WHERE
    rowkind = '+I'
UNION ALL
......

寬表入湖執行效果如下:

6

可以看到,第一個 Source 因為用到了 Retry Lookup Join, 後面來的資料在排隊,需要等前面的資料 Join 上或是重試次數用完,後面的資料才會處理,很多情況下這個節點處於 Busy 狀態,導致效率很低。

3.5 ADS 層流讀到 ClickHouse

--CREATE TABLE
CREATE TABLE t_role (
      gn string,
      id string,
    ......
) WITH (
    'connector' = 'clickhouse',
    'url' = 'clickhouse://localhoust:8123',
    'database-name' = 'streaming_warehouse',
      'table-name' = 't_role_all',
    'use-local' = 'false',
      'is-changelog' = 'true',
      'sink.batch-size' = '5000',
    'sink.flush-interval' = '2000',
    'sink.max-retries' = '3',
    'username' = 'username',
    'password' = 'password'
);
-- INSERT
INSERT INTO
    t_role
SELECT
    *
FROM
    fts_dws.t_dws_role
WHERE
    is_role = 1

綜上所述,基於 Apache Paimon(Incubating) 構建 Streaming Lakehouse 能夠解決我們當前實時數倉中間層資料不可分析,保留時間短,問題排查困難、資料更新處理複雜等痛點,並能夠將 Hive 離線數倉 T+1 的延遲縮小到分鐘級,上線後將會優先替換實時數倉,後期慢慢賦能離線業務,用流批一體的計算引擎+流批一體的儲存做到真正的流批一體的湖倉體驗。

4. 實踐總結

  • 使用 full-compaction Changelog Producer 時,changelog-producer.compaction-interval 和 checkpoint interval 設定值較小,比如一分鐘以下時,Writer 端在寫入資料和 Compaction 時的壓力較大,需要較大的資源,如果任務暫停一段時間,再從 Savepoint 恢復時,Writer 端反壓嚴重,需不斷調整資源。後面考慮測試 lookup Changelog Producer,和 full-compaction Changelog Producer 對比,測試是否可以滿足生產環境低延遲流讀場景需求。
  • 當數倉某一層的資料出現問題,需要透過 Time Travel 重新讀取某個快照或是某個時間點開始的資料修復問題,此時需要 Snaphot 檔案保留時間能夠滿足問題回溯週期,但是目前 Checkpoint Interval 設定較小,寫入資料延遲較小,導致 Snapshot 保留時間越長,生成越多的小檔案,存在小檔案過多的問題。
  • 目前的 Retry Lookup Join 是有序的,如果前面一條資料一直 Join 不上,那麼後面來的資料也會排隊,並不會處理,需要一直等到前面的資料Join上維表資料或重試次數用完,這樣造成資料處理效率很低,此時如果使用 Unordered Output,則需要 Paimon 實現非同步 Lookup Join,目前社群正在支援:(https://github.com/apache/incubator-paimon/issues/848)。

5. 未來規劃

  • 完善基於 Apache Paimon(Incubating) 的流式數倉的建設。
  • 最佳化 Presto 查詢,幫助基於 Paimon 進行即席查詢發揮作用。
  • 目前 Paimon 需要對接 BI 報表或是分析系統的資料都是事先流讀到 ClickHouse, 然後再於 ClickHouse 進行視覺化展示,後面考慮是否直接在 Paimon 裡預聚合完結果資料,與前端互動直接查詢 Paimon,減少資料處理鏈路以及降低複雜度。
  • 完善基於 Apache Paimon(Incubating) 的平臺服務建設。

6. Paimon 資訊

作者簡介

石在虎,大資料研發工程師,專注於實時計算,對資料湖和資料整合有著濃厚的興趣

史亞光,大資料平臺工程師,專注於資料整合與平臺開發,對流式數倉和資料湖有著濃厚的興趣

點選進入 Apache Paimon 官網


更多內容


活動推薦

阿里雲基於 Apache Flink 構建的企業級產品-實時計算 Flink 版現開啟活動:
0 元試用 實時計算 Flink 版(5000CU*小時,3 個月內)
瞭解活動詳情:https://free.aliyun.com/?pipCode=sc

image.png

相關文章