背景
在某些業務場景下,我們需要一個標誌來衡量hudi數據寫入的進度,比如:Flink 實時向 Hudi 表寫入數據,然後使用這個 Hudi 表來支持批量計算並通過一個 flag 來評估它的分區數據是否完整從而進一步寫入分區數據進行分區級別的ETL,這也就是我們通常說的流轉批
。
EventTime計算原理
圖中Flink Sink包含了兩個算子。第一個writer 算子,它負責把數據寫入文件,writer在checkpoint觸發時,會把自己寫入的最大的一個時間傳到commit算子中,然後commit算子從多個上游傳過來的時間中選取一個最小值作爲這一批提交數據的時間,並寫入HUDI表的元數據中。
案例使用
我們的方案是將這個進度值(EventTime)存儲爲 hudi 提交(版本)元數據的屬性裏,然後通過訪問這個元數據屬性獲取這個進度值。在下游的批處理任務之前加一個監控任務去監控最新快照元數據。如果它的時間已經超過了當前的分區時間,就認爲這個表的數據已經完備了,這個監控任務就會成功觸發下游的批處理任務進行計算,這樣可以防止在異常場景下數據管道或者批處理任務空跑的情況。
下圖是一個flink 1分鐘級別入庫到HUDI ODS表, 然後通過流轉批計算寫入HUDI DWD表的一個執行過程。
US調度系統輪詢邏輯
如何解決亂序到來問題, 我們可以通過設置spedGapTime來設置允許延遲到來的範圍默認是0 不會延遲到來。
Maven pom 依賴
針對此功能特性的Hudi依賴版本如下
<dependencies>
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-flink1.13-bundle</artifactId>
<version>0.12.1</version>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-flink1.15-bundle</artifactId>
<version>0.12.1</version>
</dependency>
</dependencies>
如何設置EventTime
能夠解析的字段類型及格式如下:
類型 | 示例 |
---|---|
TIMESTAMP(3) | 2012-12-12T12:12:12 |
TIMESTAMP(3) | 2012-12-12 12:12:12 |
DATE | 2012-12-12 |
BIGINT | 100L |
INT | 100 |
Flink API
用戶只需要設置flink conf指定時間字段作爲時間推進字段
Map<String, String> options = new HashMap<>();
// 這裏省略其他表字段
options.put(FlinkOptions.EVENT_TIME_FIELD.key(), "ts");
HoodiePipeline.Builder builder = HoodiePipeline.builder(targetTable)
.column("id int not null")
.column("ts string")
.column("dt string")
.pk("id")
.partition("dt")
.options(options);
Flink SQL
通過設置hoodie.payload.event.time.field
指定需要計算的eventtime的字段
create table hudi_cow_01(\n" +
" uuid varchar(20),\n" +
" name varchar(10),\n" +
" age int,\n" +
" ts timestamp(3),\n" +
" PRIMARY KEY(uuid) NOT ENFORCED\n" +
")\n" +
" with (\n" +
// 這裏省略其他參數
" 'hoodie.payload.event.time.field' = 'ts'\n"
")
如何讀取EventTime
Spark SQL
call show_commit_extra_metadata(table => 'hudi_tauth_test.hudi_cow_01', metadata_key => 'hoodie.payload.event.time.field');
Java API
代碼獲取片段如下
Option<HoodieCommitMetadata> commitMetadataOption = MetadataConversionUtils.getHoodieCommitMetadata(metaClient, currentInstant);
if (!commitMetadataOption.isPresent()) {
throw new HoodieException(String.format("Commit %s not found commitMetadata in Commits %s.", currentInstant, timeline));
}
// 獲取到當前版本的時間進度
String eventTime = commitMetadataOption.get().getExtraMetadata().get(FlinkOptions.EVENT_TIME_FIELD.key());
System.out.println("current eventTime: " + eventTime);
輸出結果如下
current eventTime: 1667971364742