hudi 目前支持两种表类型,分别是 cow 表和 mor 表,详情见 https://hudi.apache.org/docs/table_types
举个栗子简单介绍两者个实现区别:
主键在 hudi 中是一等公民,需要提供主键以支持去重等功能,并且确保同一张表或者分区下不会有主键重复的数据
支持多个字段,逗号分隔
hudi 根据主键去重,需要判断是否将旧的数据更新掉,会通过 primaryKey 进行判断,比较大就更新,一般是 ts 时间戳。如果不设置,默认每次都会用最新的数据更新替换
建表时指定 location 才会以 hive 中外表的方式进行处理,如果 sql 只有 external 没有 location,依然按内表处理
基本 sql case
create table hudi_cow_pt_tbl (
id bigint,
name string,
ts bigint,
dt string,
hh string
) using hudi
options (
type = 'cow',
primaryKey = 'id',
preCombineField = 'ts'
)
partitioned by (dt, hh)
location '/tmp/hudi/hudi_cow_pt_tbl';
注意:这里只会列出需要用户配置或者常用的,其它的可以访问 https://hudi.apache.org/docs/configurations
这里先介绍下 hudi 的文件组织管理(cow)
从离线任务简单分析,如图下图,假设任务 5 分钟运行一次,每次会生成一个 commit
这时候,file_1 有三个版本,2 也有三个,3有 1 个,4有一个
然后,根据 timeline 和 多个版本的数据文件,基于此我们就可以实现附加的功能
上面提到 active timeline,就有非 active timeline,叫做 archive timeline,hudi 会根据其参数进行归档。所有以上的附加功能基于的都是 active timeline,所以要合理控制 active timeline 的大小
可能有疑问,我需要历史全量数据岂不是要保持所有 timeline 为 active。hudi 会保证每个 file 至少一个版本,所以不用保持所有 timeline,毕竟数据存储成本会比较高。
了解了上面的原理,那么就需要通过一定的参数配置解决某些问题:
clean 配置用来清理不需要的数据文件版本,减少数据冗余,默认每次任务完成都会触发判断是否需要清理
参数名 | 默认值 | 描述 |
---|---|---|
hoodie.clean.automatic | true | 每次任务完成 commit 后会自动根据策略配置清理历史数据 |
hoodie.cleaner.policy | KEEP_LATEST_COMMITS | clean 的清理策略,三种如下,KEEP_LATEST_COMMITS:保留最近几次提交所引用的对应版本的数据文件、KEEP_LATEST_BYHOURS:保留最近几个小时所引用的对应版本的数据文件、KEEP_LATEST_FILE_VERSIONS:保留最近几个版本的数据文件 |
hoodie.cleaner.commits.retained | 10 | 保留最近 10 次 active timline 引用的对应版本的数据文件 |
hoodie.cleaner.hours.retained | 24 | 保留最近 24 hr active timeline 引用的对应版本的数据文件 |
hoodie.clean.trigger.strategy | NUM_COMMITS | 每次任务完成是触发 clean,需要通过这个判断是否有必要执行 clean 操作,目前只有数量策略 |
hoodie.clean.max.commits | 1 | NUM_COMMITS 策略下,只有距离上一次 clean 的策略满足大于等于 max.commits 才需要 clean |
archive 用来将 active timeline 进行归档,防止 active timline 过大影响 hudi 元数据访问的性能
参数名 | 默认值 | 描述 |
---|---|---|
hoodie.archive.automatic | true | 每次任务完成 commit 后会自动根据配置 archive 历史 time instance |
hoodie.keep.max.commits | 30 | 控制 active timeline instance 的最大值 |
hoodie.keep.min.commits | 20 | 控制 active timeline instance 的最小值,这个值必须大于 hoodie.cleaner.commits.retained |
对于 mor 表,还有一项特殊的属性,就是 compact config,配置 mor 表的 log 和 base file 的合并策略,mor 组织结构如下:
分为两个文件结构:
参数名 | 默认值 | 描述 |
---|---|---|
hoodie.compact.inline | false | 每次任务完成 commit 后是否触发 compact 合并判断 |
hoodie.compact.inline.trigger.strategy | NUM_COMMITS | 是否合并触发策略,NUM_COMMITS:满足任务完成次数TIME_ELAPSED:满足距离上次完成时间NUM_AND_TIME:两个条件都必须满足NUM_OR_TIME:两个条件满足一个即可 |
hoodie.compact.inline.max.delta.commits | 5 | 距离上次 compaction 的最大提交次数,大于等于合并 |
hoodie.compact.inline.max.delta.seconds | 3600 | 大于等于时间合并 |
hoodie.compact.schedule.inline | false | 每次任务完成是否生成 compact plan 用于异步任务合并 |
参数名 | 默认值 | 描述 |
---|---|---|
hoodie.table.base.file.format | PARQUET | 建议 parquet,如果要用别的,建议先联系下研发 |
hoodie.parquet.max.file.size | 125829120 | parquet 文件大小,默认值 100M |
hoodie.parquet.compression.codec | gzip | |
hoodie.copyonwrite.record.size.estimate | 1024 | 每行数据的大小,通过 |
hoodie.parquet.small.file.limit | 104857600 | 100M,小于这个值是小文件,新增的数据会优先往小文件里写 |
参数名 | 默认值 | 描述 |
---|---|---|
hoodie.datasource.write.hive_style_partitioning | false | 如果为 true,分区 path 会和 hive 一样,dt=20210101,而不是 20210101 |
索引使用场景有两个,一个是快速定位 recordKey 所在的文件,一个是加速数据查询,减少 scan 的数据文件,这里涉及的是快速定位 recordKey
参数名 | 默认值 | 描述 |
---|---|---|
hoodie.index.type | BLOOM |
默认使用 bloom 索引,还支持:HBASE, INMEMORY, BLOOM, GLOBAL_BLOOM, SIMPLE, GLOBAL_SIMPLE, BUCKET |
hoodie.bloom.index.update.partition.path | true | 对于 global_bloom,假设历史分区已存在对应的 record key,如果是 true,删除历史分区对应的数据,加到新的分区,如果是 false,更新历史的数据 |
hoodie.simple.index.update.partition.path | true | 用于 global_simple,效果同上 |
注意:对于分区表,非 global 索引只能确保分区能唯一
create table if not exists h3(
id bigint,
name string,
price double,
ts bigint,
dt string
) using hudi
options (
primaryKey = 'id',
type = 'cow',
preCombineField = 'ts',
hoodie.cleaner.policy = 'KEEP_LATEST_COMMITS',
hoodie.cleaner.commits.retained = '48',
hoodie.keep.min.commits = '50',
hoodie.keep.max.commits = '60',
hoodie.copyonwrite.record.size.estimate = '10',
hoodie.datasource.write.hive_style_partitioning = 'true'
)
partitioned by (dt)
location '/user/prod_datalake_test/datalake_test/hive/h3';
对于 mor 表来说,compact 时机影响 ro 表的数据新鲜度,对于 ro 查询只能查询 base file,不会查询 log file (Query types),并且可以提升查询性能
注意:12 小时 合并一次,代表 第 12 次倍数的周期任务运行时间必定会比其它周期任务执行时间长,如果有一定的忧虑,可以进行异步合并计划生成,异步合并计划执行
create table if not exists h3(
id bigint,
name string,
price double,
ts bigint,
dt string
) using hudi
options (
primaryKey = 'id',
type = 'mor',
preCombineField = 'ts',
hoodie.cleaner.policy = 'KEEP_LATEST_COMMITS',
hoodie.cleaner.commits.retained = '48',
hoodie.keep.min.commits = '50',
hoodie.keep.max.commits = '60',
hoodie.copyonwrite.record.size.estimate = '10',
hoodie.datasource.write.hive_style_partitioning = 'true',
hoodie.compact.inline.trigger.strategy = 'TIME_ELAPSED',
hoodie.compact.inline.max.delta.seconds = '43200'
)
partitioned by (dt)
location '/user/prod_datalake_test/datalake_test/hive/h3';