flinkcdc从业务库抽取数据到paimon。
一:主键模型:Primary Key Table
1、主键由一组列组成,这些列包含每条记录的唯一值。paimon通过对每个bucket中的主键进行排序来强制执行数据排序,允许用户通过对主键应用过滤条件来实现高性能。主键表是paimon作为流式数据湖的核心,他可以接收上游来自数据库CDC或者flink streaming产生的Changelog,里面包含insert,update,delte的数据,建表关键字是 PRIMARY KEY (字段) NOT ENFORCED
2、主键表的compaction默认在flink sink中自动完成,它会在LSM中生产一个写放大和读放大的基本平衡。但默认的compaction可能会存在阻塞写,针对该弯头可以开启全一步compation,如下配置: 'num-sorted-run.stop-trigger' = '2147483647',
'sort-spill-threshold' = '10',
-- 'changelog-producer.lookup-wait' = 'false' -- 此参数针对'changelog-producer' = 'lookup'
3、paimon支持多作业同时写入,但是并不支持多作业同时 Compaction,所以你可以给写入作业配置 write-only 为 true,避免写入作业进行后台 compaction,然后启动单独的 Dedicated Compaction Job。
-- 注意点:1.comment不能带双引号,只能带单引号
-- 2.BIGINT,INT,tinyint 不能带括号,如INT(20)
-- 3.不能用datetime,可以改用timestamp(3)
CREATE TABLE paimon_dev.dwd_lbu_fms.dwd_lbu_mbi_bil_income (
ic_id BIGINT COMMENT 'ID',
partition_id INT comment '分区字段',
bs_id INT COMMENT '业务数据ID',
bsn_number varchar(150) COMMENT '业务单号',
customer_id int COMMENT '结算客户ID',
fk_code varchar(60) COMMENT '费用类型',
amount decimal(18, 2) COMMENT '原币金额',
currency_code varchar(9) COMMENT '原币币种',
pirce_type varchar(9) COMMENT '本位币(人民币、美元)',
rate decimal(18, 4) COMMENT '换算成本位币汇率',
PRIMARY KEY (ic_id,partition_id) NOT ENFORCED
)
COMMENT 'SS表'
PARTITIONED BY (partition_id)
WITH (
'bucket' = '5', -- default 1
'bucket-key' = 'ic_id',
'sequence.field' = '__doris_sequence_ts_dt__',
-- 当同时insert两条以上相同主键的数据时,可以按__doris_sequence_ts_dt__时间最大的为最新的合并数据
'full-compaction.delta-commits' = 'full-compaction', -- 完全压缩
'changelog-producer' = 'full-compaction', -- 在compaction后产生完整的changelog
'changelog-producer.compaction-interval' = '2 min', -- compaction间隔时间
'merge-engine' = 'partial-update', -- 默认deduplicate
'partial-update.ignore-delete' = 'true', -- 忽略DELETE数据,避免运行报错
'partition.expiration-time' = '7d',--分区的过期间隔。如果分区的生存期超过这个值,它将过期。
'partition.expiration-check-interval' = '1d',--分区过期的检查间隔,默认1h
'partition.timestamp-formatter' = 'yyyyMMdd', -- 分区格式,默认 'yyyy-MM-dd HH:mm:ss' and 'yyyy-MM-dd',多字段分区也可以设置为 '$year-$month-$day $hour:00:00'
'partition.timestamp-pattern' = '$create_on',
-- 主键表的 Compaction 默认在 Flink Sink 中自动完成,它会在LSM中生成一个 写放大与读放大的基本平衡。但默认的后台运行的 Compaction可能会阻塞写,因此可以
-- 开启全异步Compaction,打开后永远不会阻塞 Write 的正常写入
'num-sorted-run.stop-trigger' = '2147483647',
'sort-spill-threshold' = '10',
--'changelog-producer.lookup-wait' = 'false' -- 此参数针对'changelog-producer' = 'lookup'
'write-only' = 'true'-- Paimon 支持多作业同时写入,但是并不支持多作业同时 Compaction,所以你可以给写入作业配置 write-only 为 true,避免写入作业进行后台compaction,然后启动单独的 Dedicated Compaction Job。可以参考【专用压缩】
);
BUCKET
bucket是最小的读写存储单元,每个bucket目录都包含一个LSM树。
存储桶数量过多会导致小文件过多,存储桶数量过少会导致写入性能较差。
(1):固定桶
不支持跨分区更新数据;
固定桶是指bucket>0.一般默认1;
Bucket 个数会影响并发度,影响性能,所以你需要根据表的数据量来合理定义出一个 bucket 个数,一般情况下,建议每个bucket中的数据大小约为 200MB-1GB。
PS:随着数据增加,可能会又调整的场景,通过如下方式:
a.直接重建表,一般推荐
b.也可以保留已经写入的数据,详见文档 Rescale Bucket,https://paimon.apache.org/docs/0.6/maintenance/rescale-bucket/
'bucket' = '5'
'bucket-key' = 'bsn_number' ,一般要加上该参数,不加则默认是按全部的表字段hash去分捅
(2):动态桶
动态桶bucket=-1,
数据如果是已经存在主键,将会落入旧的存储桶中,新的主键将落入新的存储桶。存储桶和主键的分布取决于数据到达的顺序。Paimon 会维护一个索引,以确定哪个主键对应于哪个桶。Paimon 会自动扩展bucket的数量。有两个参数你需要关心:
- 'dynamic-bucket.target-row-num':控制一个桶的目标数据量。
- 'dynamic-bucket.assigner-parallelism':控制初始化bucket的数量。
普通动态桶(不跨分区)
定义:更新不跨分区(没有分区,或者主键包含所有分区字段)
性能:
a.一般来说,没有性能损失,但会有一些额外的内存消耗,一个分区中的1亿个条目会多占用1 GB的内存,不再活动的分区不会占用内存。
b.对于更新率较低的表,建议使用此模式以显著提高易用性。
Merge Engines
当Paimon接收器接收到两个或多个具有相同主键的记录时,它会将它们合并为一个记录,以保持主键的唯一性。通过指定合并引擎表属性,用户可以选择如何将记录合并在一起。
一般默认Deduplicate,即'merge-engine' = 'deduplicate '
(1)Deduplicate:宽表模型
'merge-engine' = 'deduplicate '
Paimon将只保留最新的记录,并丢弃具有相同主键的其他记录。
具体来说,如果最新的记录是DELETE记录,则具有相同主键的所有记录都将被删除。
(2)Partial Update:宽表模型
'merge-engine' = 'partial-update'
可以部分更新列,但是null没法覆盖原来有值的列
PS:
a.对于流式查询,部分更新合并引擎必须与查找或完全压缩变更日志生成器一起使用。(也支持'input'变更日志生成器,但仅返回输入记录。)即需要'changelog-producer' = 'full-compaction','changelog-producer.compaction-interval' = '2 min'把这个两个参数加上
b.默认情况下,部分更新不能接受删除记录,您可以选择以下解决方案之一:
配置"部分更新。忽略删除"以忽略删除记录。'partial-update.ignore-delete' = 'true'
配置"序列组"以收回部分列。'sequence.field' = 'binlog_time'
CREATE TABLE if not EXISTS paimon.dw.order_detail
(
`order_id` string
,`product_type` string
,`binlog_time` bigint
,PRIMARY KEY (order_id) NOT ENFORCED
)
WITH (
'bucket' = '20', -- 指定20个bucket
'bucket-key' = 'order_id',
'sequence.field' = 'binlog_time', -- 记录排序字段
'changelog-producer' = 'full-compaction', -- 选择 full-compaction ,在compaction后产生完整的changelog
'changelog-producer.compaction-interval' = '2 min', -- compaction 间隔时间
'merge-engine' = 'partial-update',
'partial-update.ignore-delete' = 'true' -- 忽略DELETE数据,避免运行报错
);
部分更新聚合:
'fields.amount.sequence-group' = '聚合字段名称',
'fields.聚合字段名称.aggregate-function' = '聚合类型,例如sum',
(3)Aggregation:聚合模型
除主键以外的列都可以指定一个聚合函数,相同主键的数据就可以按照列字段指定的聚合函数进行相应的预聚合,如果不指定则默认为 last-non-null-value ,空值不会覆盖。Agg 表引擎也需要结合 Lookup 或者 full-compaction 的 Changelog Producer 一起使用,需要注意的是除了 SUM 函数,其他的 Agg 函数都不支持 Retraction,为了避免接收到 DELETE 和 UPDATEBEFORE 消息报错,需要通过给指定字段配置 'fields.${field_name}.ignore-retract'='true' 忽略。
CREATE TABLE MyTable (
product_id BIGINT
,price DOUBLE
,sales BIGINT
,PRIMARY KEY (product_id) NOT ENFORCED)
WITH ('merge-engine' = 'aggregation',
'changelog-producer' = 'full-compaction', -- 选择 full-compaction ,在compaction后产生完整的changelog
'changelog-producer.compaction-interval' = '2 min', -- compaction 间隔时间
'fields.price.aggregate-function' = 'max',
'fields.sales.aggregate-function' = 'sum');
Partitions:分区
注意:分区字段必须是主键字段的子集