paimon0.9记录

Apache Paimon大厂面试必备系列-基础篇 本文部分参考了Paimon官网、社区、网络分享的内容,内容较长难免有笔误,大家可自行对比官网纠错。Apache Paimon是一种流批统一的数据湖存储格式,结合Flink及Spark构建流批处理的实时湖仓一体架构。Paimon创新地将湖格式与LSM技术结合起来,给数据湖带来了实时流更新以及完整的流处理能力:实时入湖:Paimon支持包括MySQL在内的多种数据库系统的实时变化同步写入,在千万级数据规模下也能保持高效率与低延迟。湖上流批一体处理:Paimon结合Flink提供了完整的流处理能力,结合Spark 阅读详情

启动paimon

-- 本地模式演示
bin/start-cluster.sh

-- 启动sqlclient
bin/sql-client.sh

示例

-- 创建catalog,每次都要创建,创建一个已经存在的catalog相当于`使用`
CREATE CATALOG fs_catalog WITH (
	'type'='paimon',
	'warehouse'='file:/data/soft/paimon/catalog'
);
 
 -- 创建之后需要use
use catalog fs_catalog ;


-- 在paimon模式下,只能创建paimon表和TEMPORARY表。
CREATE TEMPORARY TABLE word_table (
    word STRING
) WITH (
    'connector' = 'datagen',
    'fields.word.length' = '1'
);

-- 控制批流操作,此处设置为流模式
SET 'execution.runtime-mode' = 'streaming';
-- 设置checkpoint间隔,这影响到数据写入的批次大小(100秒写一次),很重要
SET 'execution.checkpointing.interval' = '10 s';

-- 流式写入
INSERT INTO word_count SELECT word, COUNT(*) FROM word_table GROUP BY word;

-- 流式查询
SELECT word,cnt / 10000 AS `interval` FROM word_count;

-- 控制批流操作,此处设置为批模式
SET 'execution.runtime-mode' = 'batch';
-- 取消checkpoin设置
RESET 'execution.checkpointing.interval';
-- 设置结果展示形式,默认: table,能设为 : tableau、changelog
SET 'sql-client.execution.result-mode' = 'tableau';

-- 批式查询
SELECT word,cnt / 10000 AS `interval` FROM word_count;

CATALOG

本地+本地

  • 元数据库在本地,数据在本地
 CREATE CATALOG fs_catalog WITH (
	'type'='paimon',
	'warehouse'='file:/data/soft/paimon/catalog'
 );

本地+hdfs

  • 元数据库在本地,数据在hdfs
CREATE CATALOG hdfs_fs_catalog WITH (
	'type'='paimon',
	'warehouse' = 'hdfs://wsl01:8020/paimon/catalog'
);

hive+hdfs

  • 元数据库在hive,数据在hdfs
  • 通过hadoop配置找到hdfs相关信息
  • hive 需要下载(根据flink版本)
    • https://repo.maven.apache.org/maven2/org/apache/flink/flink-sql-connector-hive-2.3.10_2.12/1.20.0/flink-sql-connector-hive-2.3.10_2.12-1.20.0.jar
CREATE CATALOG hive_catalog WITH (
    'type'='paimon',
    'metastore'='hive',
    'warehouse' = 'hdfs://wsl01:8020/paimon/hive',
    'hive-conf-dir'='/data/soft/hive/apache-hive-3.1.2-bin/conf',
 	'hadoop-conf-dir'='/data/soft/hadoop/hadoop-3.1.3/etc/hadoop'
 ); 

jdbc+hive

 CREATE CATALOG jdbc_catalog WITH (
    'type'='paimon',
    'metastore'='jdbc',
    'uri'='jdbc:mysql://wsl:3306/paimon?useUnicode=true&characterEncoding=UTF-8&user=root&password=root',
    'warehouse' = 'hdfs://wsl01:8020/paimon/hive'
 );

表目录

Schema

  • 记录表结构的变化历史

Snapshot

  • 快照表,paimon数据产生一次变化就会生成一个快照,有三种生成快照的方式
    • 批处理,每次sql更新操作就会形成一个快照
    • 流处理,每次checkpoint就会触发一次数据落地,形成一个快照
    • compaction,每次触发合并都会形成一个快照
      • compaction触发频率基于change-log模式
  • 快照过期策略:默认只保留1小时,但是最少会保留10个版本,1小时到了,但是快照不足10个版本也不会删除,快照没了,但是数据还在,只不过不能通过snapshot-id来查询指定快照版本的数据了
选项必需的默认类型描述
snapshot.time-retainedNo1 hDuration已完成快照的最长时间保留。
snapshot.num-retained.minNo10Integer要保留的已完成快照的最小数量。
snapshot.num-retained.maxNoInteger.MAX_VALUEInteger要保留的已完成快照的最大数量。

Manifest

  • 清单:包括多个数据文件或更改日志文件。

Bucket

  • 桶是最小的数据目录,每个桶就是一个lsm tree,如果有分区,在分区文件夹下建分桶文件夹
  • 每个存储桶(文件夹)中的建议数据大小约为 200MB - 1GB
  • 是数据存储的真正目录
  • 有两种模式
    • 动态分桶:根据每个桶最大数据行数和最大数据量动态分桶
    • 固定分桶 :根据主键的hash值进行分桶,没有主键就一个桶

Partition

  • 分区文件夹,名称不固定,根据你的分区字段和值确定
  • 来一条数据,首先要找到他的分区,然后找到他的分桶,而分区好不好找取决去,分区键和主键的关系,如果主键包含分区键,那通过主键可以直接找到分区,如果主键不包含分区键,就需要借助其他数据结构存储主键到分区的映射
    • 同分区更新表,主键包含所有分区字段,通过主键就可以确认分区
    • 跨分区更新表,主键不完整包含所有分区字段,需要借助索引
  • 如果有分区,那么分桶文件夹会存在于对应分区文件夹下

主键表

  • 主键表主键如果重复会根据策略进行更新操作,表中的数据主键是唯一的
  • 由于数据是分区、分桶目录存放的,因此数据有一个寻址过程
CREATE TABLE my_table_pk (
    user_id BIGINT,
    item_id BIGINT,
    behavior STRING,
    dt STRING,
    hh STRING,
    PRIMARY KEY (dt, hh, user_id) NOT ENFORCED
);

分桶

动态分桶

  • 每个桶的数据不应过大,因此当达到行数限制或者存储限制,就会自动创建一个新的桶。
  • 由于动态分桶无法通过固定算法计算主键和分桶的关系,因此需要维护一个索引文件记录,在写入的时候要维护index,在读取的时候要读取index,但是影响都还可以接受

固定分桶

  • 在建表的时候就需要指定桶的数量,默认就会初始化出n个分桶文件夹
  • 根据主键的hash%n,计算主键和分桶的关系,不需要额外维护索引表,效率高
  • 固定分桶的数据应当不会经常变化,如果数据变化较大导致需要缩放分桶时是一个比较复杂的操作
桶的缩放
  • ALTER TABLE 仅修改表的元数据,不会重新组织或重新格式化现有数据。必须通过 INSERT OVERWRITE 实现重新组织现有数
ALTER TABLE my_table SET ('bucket' = '4');

INSERT OVERWRITE my_table PARTITION (dt = '2022-01-01')
SELECT * FROM my_table where dt = '2022-01-01'

分区表

  • 在进行更新的时候,需要根据这条数据的目录(分区/分桶),因此可以将分区表分为同分区更新表和跨分区更新表
  • 同分区表在数据更新时只需要借助索引文件(index),将主键和桶进行绑定,不需要管主键和分区的关系,因为主键中包含分区,在数据写入是会将索引文件加载到内存,因此对于写入的效率影响几乎为0,但是需要一部分内存,不过在写入过程结束后,会释放这部分内存
  • 跨分区表在数据更新时不光需要索引文件,将主键和桶进行绑定,还需要将主键和分区绑定,因此对于跨分区表,paimon采用rocksdb进行主键-分区-分桶的绑定,这样必然会导致数据写入过程的效率受到影响(1,rocksdb加载过程,2,key-value查询过程)

同分区

CREATE TABLE my_table_pt_tonfenqu (
    user_id BIGINT,
    item_id BIGINT,
    behavior STRING,
    dt STRING,
    hh STRING,
    PRIMARY KEY (dt, hh, user_id) NOT ENFORCED
) PARTITIONED BY (dt, hh);

跨分区

CREATE TABLE my_table_pt_kuafenqu(
    user_id BIGINT,
    item_id BIGINT,
    behavior STRING,
    dt STRING,
    hh STRING,
    PRIMARY KEY (dt, hh, user_id) NOT ENFORCED
) PARTITIONED BY (dt, item_id );

借用一张图:https://developer.aliyun.com/article/1424169
在这里插入图片描述

分区过期策略

  • 按照分区值过期(需要分期字段能被parse成时间)
    • 分区值如果是多个,可以从中指定出时间字段 partition.timestamp-pattern = ‘$dt’
  • 按照分区更新时间(分区数据写入时间,分区字段可以随意)

values-time策略
partition.expiration-strategy = values-time (默认值,可以不指定)
当前时间 - 分区时间 > partition.expiration-time 则删除
partition.expiration-check-interval,检查间隔仅在流处理中适用
批处理:end-input.check-partition-expire=true 开启后(默认false 关闭),在每次任务执行后触发一次检查。如果不开起,批处理写入会永远不触发过期检查,数据永远不会过期
插入一条已经过期的数据,会立即标记为过期,进行删除

CREATE TABLE t (...) PARTITIONED BY (dt) WITH (
    'partition.expiration-time' = '7 d',
    'partition.expiration-check-interval' = '1 d',
    'partition.timestamp-formatter' = 'yyyyMMdd'   -- this is required in `values-time` strategy.
);
-- Let's say now the date is 2024-07-09,so before the date of 2024-07-02 will expire.
insert into t values('pk', '2024-07-01');

-- An example for multiple partition fields
CREATE TABLE t (...) PARTITIONED BY (other_key, dt) WITH (
    'partition.expiration-time' = '7 d',
    'partition.expiration-check-interval' = '1 d',
    'partition.timestamp-formatter' = 'yyyyMMdd',
    'partition.timestamp-pattern' = '$dt'
);

update-time策略
partition.expiration-strategy = update-time (需要明确指定)
当前时间 - 分区最后更新时间 > partition.expiration-time 则删除
partition.expiration-check-interval,检查间隔仅在流处理中适用
批处理:end-input.check-partition-expire=true 开启后(默认false 关闭),在每次任务执行后触发一次检查。如果不开起,批处理写入会永远不触发过期检查,数据永远不会过期

CREATE TABLE t_expiration_time (
    id int,
    dt string
) PARTITIONED BY (dt) WITH (
    'partition.expiration-time' = '30 s',
    'partition.expiration-check-interval' = '1 s',
    'partition.expiration-strategy' = 'update-time',
    'end-input.check-partition-expire' = 'true'
);
-- dt1分区写入一条数据
insert into t_expiration_time values(1,'dt1');

等待 1分钟后检查,数据还存在,这是因为批处理过期检查在写入操作完成后立即进行,因此检查时肯定不过期

Flink SQL> select * from t_expiration_time;
+----+-----+
| id |  dt |
+----+-----+
|  1 | dt1 |
+----+-----+
1 row in set

所以需要再次写入一条数据重新触发一次检查操作

insert into t_expiration_time values(2,'dt1');

再次等待 1分钟后检查,之前的数据还存在,这是因为,第二次的写入操作也是操作的dt1分区,因此更新了dt1分区的过期时间,所以还不会删除

Flink SQL> select * from t_expiration_time;
+----+-----+
| id |  dt |
+----+-----+
|  1 | dt1 |
+----+-----+
|  2 | dt1 |
+----+-----+
1 row in set

再次写入一条其他分区的数据重新触发一次检查操作

insert into t_expiration_time values(3,'dt2');

此时dt1分区的两条数据就被识别为过期数据删除了

Flink SQL> select * from t_expiration_time;
+----+-----+
| id |  dt |
+----+-----+
|  3 | dt2 |
+----+-----+
1 row in set

根据快照查询,发现过期删除的数据还是能查出来,那是因为数据过期了,快照还没过期,看上边的快照过期策略。

Flink SQL> select * from t_expiration_time /*+Options('scan.snapshot-id' = '1') */;
+----+-----+
| id |  dt |
+----+-----+
|  1 | dt1 |
+----+-----+
1 row in set

批处理中开启 'end-input.check-partition-expire' = 'true' 后,每次批处理操作后,触发一次过期检查
流处理中根据 'partition.expiration-check-interval' = '1 s' 周期触发过期检查
update-time模式,过期时间会一直更新,也就是一个分区在检查间隔内一直写入,这个分区的数据永远不会过期

changelog配置

CREATE TABLE my_table_pt_changelog(
    user_id BIGINT,
    item_id BIGINT,
    behavior STRING,
    dt STRING,
    hh STRING,
    PRIMARY KEY (dt, hh, user_id) NOT ENFORCED
) PARTITIONED BY (dt, item_id )
with(
	'change-log'='input'
);

none

  • 批写,批读的表适用

input

  • cdc采集表适用
  • 有完整的修改逻辑适用

lookup

  • 流式场景适用
  • 没有完整的修改逻辑
  • 数据时延要求高的场景适用

full-compaction

  • 流式场景适用
  • 没有完整的修改逻辑
  • 数据时延要求低的场景适用

非主键表


INSERT/UPDATE/DELTE

覆盖

  • 动态分区覆盖:select结果中包含的分区才会被影响,当查询结果为空时,没有查询到任何有效分区,因此不会做任何操作。
  • 静态分区覆盖:不管你的查询结果,默认覆盖所有分区,当查询结果为空时,会将所有分区数据清空。静态分区覆盖写入相当于,先做truncate动作,然后再做写入操作
-- 动态分区(默认)覆盖写入
insert overwrite mytable as select ...
-- 或者
insert overwrite mytable/*+ OPTIONS('dynamic-partition-overwrite' = 'true') */ as select ...

-- 静态分区(dynamic-partition-overwrite = false)覆盖写入
insert overwrite mytable/*+ OPTIONS('dynamic-partition-overwrite' = 'false') */ as select ...
  • 覆盖写入可以当作truncate来使用
insert overwrite mytable/*+ OPTIONS('dynamic-partition-overwrite' = 'false') */ as select * from mytable where 1=2;
  • 指定分区:可以通过 PARTITION (key1 = value1, key2 = value2, …)指定分区, 当指定分区后,覆盖写入(上述操作)只影响当前分区,否则影响所有分区
-- 动态覆盖指定分区
INSERT OVERWRITE my_table PARTITION (key1 = value1, key2 = value2, ...) SELECT ...

-- 静态清空指定分区(指定分区后,查询值中不能包含分区列)
INSERT OVERWRITE my_table /*+ OPTIONS('dynamic-partition-overwrite'='false') */ 
PARTITION (k0 = 0) SELECT k1, v FROM my_table WHERE false;

更新

  • 主键表,INSERT相同主键,会根据merge-engine策略,对指定主键的行数据进行更新操作
  • 新版本也支持UPDATE语句进行更新
    • 1、必须是主键表
    • 2、聚合引擎必须是 deduplicate or partial-update
    • 3、flink版本必须1.7及以上版本
    • 4、只适用于批处理

删除

  • 新版本支持DELETE语句
    • 1、必须是主键表
    • 2、聚合引擎必须是 deduplicate
    • 3、flink版本必须1.7及以上版本
    • 4、只适用于批处理

SELECT

批查询

  • 指定快照版本,查询指定的快照,查询快照不会展示-D的数据
SET 'execution.runtime-mode' = 'batch';
RESET 'execution.checkpointing.interval';

-- 根据快照版本
SELECT * FROM t /*+ OPTIONS('scan.snapshot-id' = '1') */;
-- 根据快照时间
SELECT * FROM t /*+ OPTIONS('scan.timestamp' = '2023-12-09 23:09:12') */;
-- 根据tag
SELECT * FROM t /*+ OPTIONS('scan.tag-name' = 'my-tag') */;
-- 根据watermark
SELECT * FROM t /*+ OPTIONS('scan.watermark' = '1678883047356') */; 
  • 根据快照范围查询
-- incremental between snapshot ids
SELECT * FROM t /*+ OPTIONS('incremental-between' = '12,20') */;

-- incremental between snapshot time mills
SELECT * FROM t /*+ OPTIONS('incremental-between-timestamp' = '1692169000000,1692169900000') */;

流查询

SET 'execution.runtime-mode' = 'streaming';

-- 只读取最新的数据
SELECT * FROM t /*+ OPTIONS('scan.mode' = 'latest') */;
-- 在当数据的基础上,只读取最新的数据
SELECT * FROM t /*+ OPTIONS('scan.mode' = 'latest-full') */;

-- 从指定快照开始读取最新数据(不包含指定快照)
SELECT * FROM t /*+ OPTIONS('scan.snapshot-id' = '1') */;
-- 从指定快照开始读取最新数据(包含指定快照)
SELECT * FROM t_partition /*+ OPTIONS('scan.mode'='from-snapshot-full','scan.snapshot-id' = '1') */;

-- 根据快照时间
SELECT * FROM t /*+ OPTIONS('scan.timestamp' = '2023-12-09 23:09:12') */;

-- 根据data文件产生时间
SELECT * FROM t /*+ OPTIONS('scan.file-creation-time-millis' = '1678883047356') */;

消费查询

  • 当 stream 读取 Paimon 表时,当上一个作业停止时,新启动的作业可以从上一个进度继续消耗
  • 读取策略有两种
    • ‘consumer.mode’ = ‘at-least-once’ 非对齐快照,至少一次语义,不丢,可能会重复,读取效率快
    • ‘consumer.mode’ = ‘exactly-once’ 对齐快照,精确一次语义,受限于checkpoint间隔,一次checkpoint出一次数据,效率慢
SET 'execution.checkpointing.interval'='60 s'
SELECT * FROM t /*+ OPTIONS('consumer-id' = 'myid', 'consumer.expiration-time' = '1 h', 'consumer.mode' = 'exactly-once') */;

--查询表的consumer情况
SELECT * FROM t$consumers;

/*
+-------------+------------------+
| consumer_id | next_snapshot_id |
+-------------+------------------+
|         myid|                1 |
+-------------+------------------+
2 rows in set
*/
  • 您可以重置具有指定 Consumer ID 和下一个快照 ID 的 Consumer,并删除具有指定 Consumer ID 的 Consumer。首先,您需要使用此 Consumer ID 停止流式处理任务,然后执行重置 Consumer Action 作业。
-- 删除consumer
 bin/flink run \
 lib/paimon-flink-action-0.9.0.jar \
 reset-consumer \
 --warehouse file:///data/soft/paimon/catalog \
 --database default \ 
 --table t \
 --consumer_id myid

-- 不删除consumer,将consumer指针切换到指定snapshot,添加下边这行
--next_snapshot <next-snapshot-id>


Lookup Join

  • lookup join 常用于关联维表、字典表,丰富主表的数据
  • lookup join 有一个明显的问题,当关联的字典表,关联数据缺失的时候,主表数据也会丢失
  • paimon也可以作为维表、字典表
CREATE CATALOG fs_catalog WITH (
	'type'='paimon',
	'warehouse'='file:/data/soft/paimon/catalog'
 );
 
use catalog fs_catalog;

-- Create a table in paimon catalog
CREATE TABLE customers (
    id INT PRIMARY KEY NOT ENFORCED,
    name STRING,
    country STRING,
    zip STRING
);

CREATE TEMPORARY TABLE orders (
    order_id INT,
    total INT,
    customer_id INT,
    proc_time AS PROCTIME()
) WITH (
  'connector' = 'kafka',
  'topic' = 'ws_test',
  'properties.bootstrap.servers' = '172.16.11.95:9092',
  'properties.group.id' = 'testGroup',
  'scan.startup.mode' = 'latest-offset',
  'format' = 'csv'
);

SET 'sql-client.execution.result-mode' = 'tableau'; 
SET 'execution.checkpointing.interval'='10 s';

SELECT o.order_id, o.total, c.country, c.zip
FROM orders AS o
-- lookup join  关联维表,一定要用左关联,否则维度信息不存在时,会导致主流丢失
LEFT JOIN customers
FOR SYSTEM_TIME AS OF o.proc_time AS c
ON o.customer_id = c.id;


重试lookup

  • 除了使用left join 防止主流丢失外,还可以使用retry-strategy 需要flink 1.16+ ,会阻塞主流,重试600次后 才能接受下一条数据
SELECT /*+ LOOKUP('table'='c', 'retry-predicate'='lookup_miss', 'retry-strategy'='fixed_delay', 'fixed-delay'='1s', 'max-attempts'='600') */
o.order_id, o.total, c.country, c.zip
FROM orders AS o
LEFT  JOIN customers
FOR SYSTEM_TIME AS OF o.proc_time AS c
ON o.customer_id = c.id;
  • 如果主表是cdc流,设置允许乱序不生效,异步重试不会异步,依然会阻塞
  • 异步重试,但是得’output-mode’=‘allow_unordered’,允许乱序
  • 通过audit_log系统表,将 CDC 流转换为 append 流即可
SELECT /*+ LOOKUP('table'='c', 'retry-predicate'='lookup_miss', 'output-mode'='allow_unordered', 'retry-strategy'='fixed_delay', 'fixed-delay'='1s', 'max-attempts'='600') */
o.order_id, o.total, c.country, c.zip
FROM orders AS o
LEFT  JOIN customers /*+ OPTIONS('lookup.async'='true', 'lookup.async-thread-number'='16') */
FOR SYSTEM_TIME AS OF o.proc_time AS c
ON o.customer_id = c.id;

lookup优化

  • 针对于每个分区都是全量数据的情况(按天分区,每天都是全量字典数据),lookup join 可以指定只扫描最新分区
SELECT o.order_id, o.total, c.country, c.zip
FROM orders AS o
LEFT JOIN customers /*+ OPTIONS('lookup.dynamic-partition'='max_pt()', 'lookup.dynamic-partition.refresh-interval'='1 h') */
FOR SYSTEM_TIME AS OF o.proc_time AS c
ON o.customer_id = c.id;
  • 对于维表,可以开启query service,来优化lookup join效率,关联维表时会优先使用query service提供的服务
<FLINK_HOME>/bin/flink run \
    /path/to/paimon-flink-action-0.9.0.jar \
    query_service \
    --warehouse <warehouse-path> \
    --database <database-name> \
    --table <table-name> \
    [--parallelism <parallelism>] \
    [--catalog_conf <paimon-catalog-conf> [--catalog_conf <paimon-catalog-conf> ...]]

ALTER

修改表

-- 修改表属性
ALTER TABLE my_table SET (
    'write-buffer-size' = '256 MB'
);
ALTER TABLE my_table RESET ('write-buffer-size');

-- 修改表名
ALTER TABLE my_table RENAME TO my_table_new;

修改字段

-- 新增字段
ALTER TABLE my_table ADD (c1 INT, c2 STRING);
-- 新增字段,指定位置
ALTER TABLE my_table ADD c INT FIRST;
-- 新增字段,指定位置
ALTER TABLE my_table ADD c INT AFTER b;
-- 删除字段
ALTER TABLE my_table DROP (c1, c2);
-- 修改字段
ALTER TABLE my_table MODIFY buy_count BIGINT COMMENT 'buy count';
-- 字段改名
ALTER TABLE my_table RENAME c0 TO c1;

Watermark

-- 新增watermark
ALTER TABLE my_table ADD (
    ts AS TO_TIMESTAMP(log_ts) AFTER log_ts,
    WATERMARK FOR ts AS ts - INTERVAL '1' HOUR
);
-- 删除watermark
ALTER TABLE my_table DROP WATERMARK;
-- 修改watermark
ALTER TABLE my_table MODIFY WATERMARK FOR ts AS ts - INTERVAL '2' HOUR

CDC

  • 支持表结构变更,但是支持的有限,
    • 不支持重命名表、删除字段,
    • 修改字段名会重新添加新字段
    • 修改字段类型时存储只能放大,不能缩小。varchar(30)->varch(20) ❌
  • 支持添加计算列 --computed_column
  • 字段类型对应
    • tinyint1-not-bool:强制tinyint(1) 转tinyint(默认转boolean)
    • to-string:所有字段类型 都变成string
  • 如果不设置,默认checkpoint间隔3分钟
    • -Dexecution.checkpointing.interval=‘180 s’

MYSQL-CDC

flink-sql-connector-mysql-cdc-3.1.x.jar
mysql-connector-java-8.0.27.jar
放到lib目录下,重启cluster

同步表

  • 支持多表接入同一张paimon表
  • 针对于mysql物理分区表,table_name支持正则匹配多个
  • 针对于mysql分库表,database_name支持正则匹配多个
  • computed_column 添加计算字段
  • metadata_column 元数据字段,来源表、库、操作
  • mysql表必须含有主键
  • paimon会自动映射mysql的主键作为自己的主键,也可以自己进行修改,但是必须保证paimon主键字段在mysql中不能为null,否则cdc任务会报错

mysql表主键id,paimon重新定义主键为id,name


bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
mysql_sync_table \
--warehouse file:///data/soft/paimon/catalog \
--database mysql_cdc \
--primary_keys 'id,name' \
--table demo_1 \
--mysql_conf hostname=wsl \
--mysql_conf username=root \
--mysql_conf password=root \
--mysql_conf database-name=test \
--mysql_conf table-name='demo3'

mysql表主键id,paimon重新定义主键为id,name,paimon定义分区键为 name

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
mysql_sync_table \
--warehouse file:///data/soft/paimon/catalog \
--database mysql_cdc \
--primary_keys 'id,name' \
--partition_keys 'name' \
--table demo_2 \
--mysql_conf hostname=wsl \
--mysql_conf username=root \
--mysql_conf password=root \
--mysql_conf database-name=test \
--mysql_conf table-name='demo3'

mysql表主键id,paimon重新定义主键为id,partition_col(计算列),paimon定义分区键为 partition_col
这样每天新增的数据会进入新的分区,但是不能修改,因为修改的话会-D +I,不同分区会重复

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
mysql_sync_table \
--warehouse file:///data/soft/paimon/catalog \
--database mysql_cdc \
--primary_keys 'id,partition_col' \
--partition_keys 'partition_col' \
--computed_column 'partition_col=date_format(create_date,'yyyy-MM-dd')' \
--table demo_3 \
--mysql_conf hostname=wsl \
--mysql_conf username=root \
--mysql_conf password=root \
--mysql_conf database-name=test \
--mysql_conf table-name='demo3' \
--table_conf bucket=-1 \
--table_conf changelog-producer=input \
--table_conf sink.parallelism=1

同步库

  • ignore_incompatible = true,自动忽略schema不兼容的表
  • mode=combined,新增表自动添加同步任务,但是不支持自动分桶
  • metadata_column 元数据信息

默认模式 mode=divided
此模式,每一个表都会生成一个task
因此新增的表,需要重启任务

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
mysql_sync_database \
--warehouse file:///data/soft/paimon/catalog \
--database mysql_cdc_all2 \
--metadata_column database_name \
--mysql_conf hostname=wsl \
--mysql_conf username=root \
--mysql_conf password=root \
--mysql_conf database-name=test \
--table_conf changelog-producer=input

combined模式 mode=combined
此模式,所有的表都会共用一个task
因此新增表后,不需要重启任务
但是不支持动态分桶,只能指定分桶数
java.lang.UnsupportedOperationException: Combine mode Sink only supports FIXED bucket mode, but ai_als_recommend_sample is HASH_DYNAMIC

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
mysql_sync_database \
--warehouse file:///data/soft/paimon/catalog \
--database mysql_cdc_all \
--mode combined \
--metadata_column database_name \
--mysql_conf hostname=wsl \
--mysql_conf username=root \
--mysql_conf password=root \
--mysql_conf database-name=test \
--table_conf bucket=2 \
--table_conf changelog-producer=input \
--table_conf sink.parallelism=2

KAFKA-CDC

Action

Merge Into action

  • 只有主键表支持
  • 不提供 -U 日志,因此不推荐对change-log=input的表进行merge into操作
CREATE CATALOG fs_catalog WITH (
	'type'='paimon',
	'warehouse'='file:/data/soft/paimon/catalog'
 );
 
use catalog fs_catalog;
create database paimon_action;
use paimon_action;
CREATE TABLE user1 (
    id INT,
    name STRING,
    age INT,
    PRIMARY KEY (id) NOT ENFORCED
);
INSERT INTO user1 VALUES(1,'张三',18),(2,'李四',29),(3,'张三',33);

CREATE TABLE user2 (
    id INT,
    name STRING,
    age INT,
    PRIMARY KEY (id) NOT ENFORCED
);
INSERT INTO user2 VALUES(2,'李四',29),(3,'张伞',39),(4,'王五',13);

user2,user1,关联条件为id,根据user2 更新 user1

  • 关联上就更新(matched-upsert)
  • user1有,user2没有的,删除(not-matched-by-source-delete)
  • user2有,user1没有的,新增(not-matched-insert)
  • --source_table 必须带着库名(要不然找不到user2)
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
merge_into \
--warehouse file:///data/soft/paimon/catalog \
--database paimon_action \
--table user1 \
--source_table paimon_action.user2 \
--on "user1.id = user2.id" \
--merge_actions matched-upsert,not-matched-by-source-delete,not-matched-insert \
--matched_upsert_condition '1=1' \
--matched_upsert_set 'name = user2.name,age = user2.age' \
--not-matched-by-source-delete-condition "true" \
--not_matched_insert_values '*'

根据mysql的表更新paimon

-- 只是展示一下不需要执行
CREATE TEMPORARY TABLE user3 (
  id INT,
  name STRING,
  age INT,
  PRIMARY KEY (id) NOT ENFORCED
) WITH (
   'connector' = 'jdbc',
   'url' = 'jdbc:mysql://wsl:3306/test',
   'username'='root',
   'password'='root',
   'table-name' = 'user3'
);

user3,user1,关联条件为id,根据user3 更新 user1

  • 关联不上就更新(not-matched-by-source-upsert)
  • 关联上就删除(matched-delete)
  • --source_table 临时表不能不能不能带着库名(要不然找不到user3)
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
merge_into \
--warehouse file:///data/soft/paimon/catalog \
--database paimon_action \
--table user1 \
--source_sql "CREATE TEMPORARY TABLE user3 (id INT,name STRING,age INT,PRIMARY KEY (id) NOT ENFORCED) WITH ('connector' = 'jdbc','url' = 'jdbc:mysql://wsl:3306/test', 'username'='root',   'password'='root','table-name' = 'user3');" \
--source_table user3 \
--on "user1.id = user3.id" \
--merge_actions matched-delete,not-matched-by-source-upsert \
--matched_delete_condition "true" \
--not_matched_by_source_upsert_condition "true" \
--not_matched_by_source_upsert_set "name='匹配不上'" 

还可以引用其他catalog的表
–source_sql 可以添加若干个

-- A --source_sql example: 
-- Create a temporary view S in new catalog and use it as source table
./flink run \
    /path/to/paimon-flink-action-0.9.0.jar \
    merge_into \
    --warehouse <warehouse-path> \
    --database <database-name> \
    --table T \
    --source_sql "CREATE CATALOG test_cat WITH (...)" \
    --source_sql "CREATE TEMPORARY VIEW test_cat.`default`.S AS SELECT order_id, price, 'important' FROM important_order" \
    --source_table test_cat.default.S \
    --on "T.id = S.order_id" \
    --merge_actions not-matched-insert\
    --not_matched_insert_values *

Delete action

Flink SQL> select * from user1;
+----+----------+-----+
| id |     name | age |
+----+----------+-----+
|  2 | 匹配不上 |  29 |
|  3 | 匹配不上 |  33 |
+----+----------+-----+

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
delete \
--warehouse file:///data/soft/paimon/catalog \
--database paimon_action \
--table user1 \
--where "id >1 or name = '匹配不上' or age >10"


Flink SQL> select * from user1;
Empty set

drop partition action

CREATE TABLE t_partition(
    user_id BIGINT,
    item_id BIGINT,
    behavior STRING,
    dt STRING,
    hh STRING,
    PRIMARY KEY (user_id) NOT ENFORCED
) PARTITIONED BY (dt, hh );

insert into t_partition values
(1,1,'sing','2024-12-12','10'),
(2,1,'sing','2024-12-13','12'),
(3,1,'sing','2024-12-14','14'),
(4,1,'sing','2024-12-15','16');

-- 提交后没有报错,但是也没有返回jobid,dashboard发现job没有创建,但是语法看着是对的,感觉是个bug
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
drop_partition \
--warehouse file:///data/soft/paimon/catalog \
--database paimon_action \
--table t_partition \
--partition "dt='2024-12-13',hh='12'" \
--partition "dt='2024-12-14',hh='14'"

compact action

  • https://paimon.apache.org/docs/0.9/maintenance/dedicated-compaction/#for-databases
  • 默认情况下,Paimon 写入器在写入记录时会根据需要进行 Compaction。这对于大多数使用案例来说已经足够了
  • 对于有些场景下,默认写compaction会导致写入冲突,比如:固定分桶同分区多任务写入(动态分桶同分区只支持单任务写入),此时需要专业的合并任务,Dedicated Compaction Job
  • 通常情况下,一个paimon数据流式写入任务包括两大任务,一个是新增,一个是异步合并,将表设置为write-only=true,并且使用专用的合并任务,能加速写入效率。
  • 可以使用 -D execution.runtime-mode=batch OR -yD execution.runtime-mode=batch (对于 ON-YARN 方案)来控制批处理或流式处理模式。如果您提交批处理作业,则所有当前表文件都将被压缩。如果您提交流式处理作业,该作业将持续监控对表的新更改并根据需要执行压缩。

表的专业合并写入
指定排序聚合策略,能优化查询速度
在这里插入图片描述

–order_strategy
–order_by <col1,col2,…>

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
compact \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_only_input

库的专业合并写入
–including_tables 指定库中的某些表

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
compact \
--warehouse file:///data/soft/paimon/catalog \
--including_databases only_input \
--mode combined

rollback_to action

  • 回滚到指定的快照版本
  • https://paimon.apache.org/docs/0.9/maintenance/manage-snapshots/#rollback-to-snapshot
<FLINK_HOME>/bin/flink run \
    /path/to/paimon-flink-action-0.9.0.jar \
    rollback_to \
    --warehouse <warehouse-path> \
    --database <database-name> \ 
    --table <table-name> \
    --version <snapshot-id> \
    [--catalog_conf <paimon-catalog-conf> [--catalog_conf <paimon-catalog-conf> ...]]

remove_orphan_files

  • 删除垃圾文件
  • https://paimon.apache.org/docs/0.9/maintenance/manage-snapshots/#remove-orphan-files
<FLINK_HOME>/bin/flink run \
    /path/to/paimon-flink-action-0.9.0.jar \
    remove_orphan_files \
    --warehouse <warehouse-path> \
    --database <database-name> \ 
    --table <table-name> \
    [--older_than <timestamp>] \
    [--dry_run <false/true>] 

TAG

在传统数仓场景中,从传统数据库中导入的事实表数据一般是全量导入,按天分区每天都存储一份全量数据,paimon对此提供了Tag机制,创建TAG时,会对当前数据做一份全量快照,在之后对表的数据进行更新也不会影响已经打完TAG的数据。

维护创建

https://paimon.apache.org/docs/0.9/maintenance/manage-tags/

-- 创建
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
create_tag \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_tags \
--tag_name first_tag

-- 删除
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
delete_tag  \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_tags \
--tag_name first_tag

-- 回滚到指定tag版本,还原当时的数据
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
rollback_to \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_tags \
--version first_tag

使用TAG

CREATE TABLE t_tags (
      age BIGINT,
      money BIGINT,
      id STRING,
      PRIMARY KEY (id) NOT ENFORCED
);
insert into t_tags values(10,1000,'1');

-- 创建第一个tag
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
create_tag \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_tags \
--tag_name first_tag

insert into t_tags values(20,2000,'2');

bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
create_tag \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_tags \
--tag_name second_tag

select * from t_tags$tags;
Flink SQL> select * from t_tags$tags;
+------------+-------------+-----------+-------------------------+--------------+-------------+---------------+
|   tag_name | snapshot_id | schema_id |             commit_time | record_count | create_time | time_retained |
+------------+-------------+-----------+-------------------------+--------------+-------------+---------------+
|  first_tag |           1 |         0 | 2024-12-19 15:05:18.802 |            1 |      <NULL> |        <NULL> |
| second_tag |           2 |         0 | 2024-12-19 15:08:14.165 |            2 |      <NULL> |        <NULL> |
+------------+-------------+-----------+-------------------------+--------------+-------------+---------------+



Flink SQL> select * from t_tags;
+-----+-------+----+
| age | money | id |
+-----+-------+----+
|  10 |  1000 |  1 |
|  20 |  2000 |  2 |
+-----+-------+----+

Flink SQL> select * from t_tags/*+ OPTIONS('scan.tag-name' = 'first_tag') */;
+-----+-------+----+
| age | money | id |
+-----+-------+----+
|  10 |  1000 |  1 |
+-----+-------+----+
1 row in set


-- 修改tag中数据
insert into t_tags_auto values(20,1000,'1');

Flink SQL> select * from t_tags;
+-----+-------+----+
| age | money | id |
+-----+-------+----+
|  20 |  1000 |  1 |
|  20 |  2000 |  2 |
+-----+-------+----+
2 rows in set

-- 查询tag,发现没有影响
Flink SQL> select * from t_tags/*+ OPTIONS('scan.tag-name' = 'first_tag') */;
+-----+-------+----+
| age | money | id |
+-----+-------+----+
|  10 |  1000 |  1 |
+-----+-------+----+
1 row in set

Branch

给表创建分支,相当于在当前数据状态下复制出来了一张新的表,新建的表叫做分支表,原表称位主表,两表互不影响,而且能够从分支表上进行合并,将分支表的数据覆盖到主表

  • 在不影响主表的情况下,新建分支表进行测试,测试成功后还可以进行合并
  • 主副分支,优先读主表,主表没有再读分支表

维护Branch

-- 创建
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
create_branch \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_branch \
--branch_name slave

-- 删除
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
delete_branch\
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_branch \
--branch_name slave
 
 -- 合并分分支到主分支
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
fast_forward \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_branch \
--branch_name stream

使用Branch

-- create Paimon table
CREATE TABLE t_branch (
    dt STRING NOT NULL,
    name STRING NOT NULL,
    amount BIGINT
) PARTITIONED BY (dt);


bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
create_branch \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_branch \
--branch_name stream


Flink SQL> select * from t_branch$branches;
+-----------------+------------------+-----------------------+-------------------------+
|     branch_name | created_from_tag | created_from_snapshot |             create_time |
+-----------------+------------------+-----------------------+-------------------------+
| stream          |           <NULL> |                <NULL> | 2024-12-19 16:15:01.000 |
+-----------------+------------------+-----------------------+-------------------------+
1 row in set

-- 写入分支表
INSERT INTO `t_branch$branch_stream` VALUES ('20240725', 'apple', 4), ('20240725', 'peach', 10), ('20240726', 'cherry', 3), ('20240726', 'pear', 6);
-- 修改分支表
ALTER TABLE t_branch$branch_stream add new_col string;
-- 写入分支表
INSERT INTO `t_branch$branch_stream` VALUES ('20240725', 'apple', 4,'new');


Flink SQL>  select * from t_branch$branch_stream;
+----------+--------+--------+---------+
|       dt |   name | amount | new_col |
+----------+--------+--------+---------+
| 20240725 |  apple |      4 |  <NULL> |
| 20240725 |  peach |     10 |  <NULL> |
| 20240725 |  apple |      4 |     new |
| 20240726 | cherry |      3 |  <NULL> |
| 20240726 |   pear |      6 |  <NULL> |
+----------+--------+--------+---------+
5 rows in set

-- 只有分支表有数据,主表没有
Flink SQL> select * from t_branch;
Empty set

-- 合并分支表(Fast Forward),删除主表的一切数据,并将分支表的一切数据拷贝到主表
bin/flink run \
lib/paimon-flink-action-0.9.0.jar \
fast_forward \
--warehouse file:///data/soft/paimon/catalog \
--database default \
--table t_branch \
--branch_name stream

-- 合并完成后,我们拥有分支表的所有信息,包括新增的schema
Flink SQL> select * from t_branch;
+----------+--------+--------+---------+
|       dt |   name | amount | new_col |
+----------+--------+--------+---------+
| 20240725 |  apple |      4 |  <NULL> |
| 20240725 |  peach |     10 |  <NULL> |
| 20240725 |  apple |      4 |     new |
| 20240726 | cherry |      3 |  <NULL> |
| 20240726 |   pear |      6 |  <NULL> |
+----------+--------+--------+---------+

系统表

查快照

SELECT * FROM my_table$snapshots;

查分区

SELECT * FROM my_table$partitions;

查标签

SELECT * FROM my_table$tags;

表配置

SELECT * FROM sys.all_table_options;
+---------------+--------------------------------+--------------------------------+-----------------+
| database_name |                     table_name |                            key |           value |
+---------------+--------------------------------+--------------------------------+-----------------+
| mysql_cdc_all |                          demo2 |                         bucket |               2 |
| mysql_cdc_all |                          demo2 |             changelog-producer |           input |
| mysql_cdc_all |                          demo2 |               sink.parallelism |               2 |
+---------------+--------------------------------+--------------------------------+-----------------+
82 rows in set

调优

写入调优

流式写入检查点间隔

  • ck检查点间隔在允许的情况下调大,ck过于频繁会导致写入性能下降
  • 或者使用批处理模式
  • 并发checkpoints改成3 (‘execution.checkpointing.max-concurrent-checkpoints’)

写入缓冲区

  • 写入缓冲区缓存大小(write-buffer-size)大小调大,默认256M,默认先放到缓冲区,缓冲区满了之后再写sorted-run
  • 开始缓冲区溢出策略(write-buffer-spillable)=true,默认不设置

并行度

  • 一个桶1g的数据量,写入并行度(sink.parallelism)要小于等于桶的数量,最好等于,默认等于上游节点并行度

本地合并

开启本地合并,用于解决频繁更新,数据倾斜问题,local-merge-buffer-size=64mb

合并策略

  • paimon是lsm tree架构,每一个sorted-run 就是一个小的Stable,当sorted-run 数量过多时,就会触发compaction,compaction 是一个资源密集型的过程为了防止sorted-run数量无限增长,当sorted-run数量达到写入停止阈值(num.sorted-run.stop-trigger)的时候就会暂停写入,默认值为达到compaction阈值+1(num-sorted-run.compaction-trigger+1),因此提高写入停止阈值就能保证停止写入不那么频繁,但是compaction的频率就会降低,会导致查询需要更多的merge on read,会影响查询的效率
    在这里插入图片描述在这里插入图片描述

文件格式

  • avro文件类型(行存储)可以提高写入吞吐量,但会降低压缩性能
  • 缺点:查询分析会变慢,如果该表有100列,但只查询了几列,则不能忽略行存储的IO。此外,压缩效率将降低,存储成本将增加。
  • 行存储的统计信息的收集有点贵,建议也关闭统计信息。
  • 如果您不想将所有文件都修改为Avro格式,至少可以考虑将前几层的文件修改为Avro格式。您可以使用 ‘file.format.per.level’ = ‘0:avro,1:avro’ 将前两层中的文件指定为Avro格式。
file.format = avro
metadata.stats-mode = none
file.format.per.level = 0:avro,1:avro

压缩比

默认情况下,Paimon 使用 1 级的 zstd,你可以修改压缩算法:
‘file.compression.zstd-level’:默认 zstd 级别为 1。对于更高的压缩率,可以配置为 9,但读写速度会明显降低。
file.compression.zstd-level = 1

压缩稳定性

如果存储桶或资源太少,完全压缩可能会导致 checkpoint 超时,这是 Flink 的默认 检查点超时为 10 分钟。
如果希望在这种情况下也能保持稳定,则可以调高检查点超时,例如:
execution.checkpointing.timeout = 60 min

内存

在 Paimon writer 中,有三个主要地方会占用内存:

  • Writer 的内存缓冲区,由单个任务的所有 writer 共享和抢占。此内存值可通过 table 属性进行调整。write-buffer-size
  • 合并多个排序运行以进行压缩时消耗的内存。可以通过选项进行调整,以更改要合并的已排序运行数。num-sorted-run.compaction-trigger
  • 如果行非常大,在进行 Compaction 时,一次读取过多的数据行会消耗大量内存。减少选项可以减轻此案例的影响。read.batch-size
  • 写入列式 ORC 文件所消耗的内存。减少该选项可以减少 ORC 格式的内存消耗。orc.write.batch-size
  • 如果文件在写入任务中自动压缩,则某些大列的字典在压缩期间可能会显著消耗内存。
  • 要禁用 Parquet 格式的所有字段的字典编码,请将 .‘parquet.enable.dictionary’= ‘false’
    要禁用 ORC 格式的所有字段的字典编码 orc.dictionary.key.threshold=‘0’,请将 .此外,设置为禁用特定列的字典编码。orc.column.encoding.direct=‘field1,field2’
  • 如果您的 Flink 作业不依赖于状态,请避免使用托管内存,您可以使用以下 Flink 参数来控制托管内存:

taskmanager.memory.managed.size=1m

  • 或者,您可以将 Flink 托管内存用于写入缓冲区以避免 OOM,请设置 table 属性:

sink.use-managed-memory-allocator=true

  • 如果写入表的数据量特别大,Committer 节点可能会占用较大的内存,这可能会导致 OOM 如果内存太小。在这种情况下,您需要增加 Committer 堆内存,但您可能不想这样做 统一增加 Flink 的 TaskManager 的内存,这可能会导致内存浪费。

  • 配置 Flink 配置 。(这是 Flink 1.18 之后的默认设置)cluster.fine-grained-resource-management.enabled: true

  • 配置 Paimon Table 选项:,例如 300 MB,具体取决于您的 。 (也支持 )sink.committer-memoryTaskManagersink.committer-cpu

最大写入吞吐量场景

  • 如果希望某种模式具有最大写入吞吐量,则可以缓慢而不是匆忙地进行Compaction。可以对表使用以下策略,适合写入过程没有过多查询请求的场景,太多Sorted Run将导致查询性能较差,甚至内存不足
    num-sorted-run.stop-trigger = 2147483647
    sort-spill-threshold = 10
    lookup-wait=false
    file.format = avro
    metadata.stats-mode = none
  • 或者开启write-only+专用压缩写入
paimon0.9 主键表的之 changelog producer 笔记 paimon解决-U的的方式是增加normalize算子,存储老数据再state中,比对后可补齐-U,所以成本高 可配置 scan.remove-normalize 取消,同时导致没-U。如果没关闭normalize算子,先发-U(小王,18,100) 再发+U(小王,18,300) 那么结果就是 18,(103-100+300)=303 这才是正确值.normalize算子开启(flink state存老数据 注意ttl要永久,否则部分-U也会丢): sink: +I -U +U -D。 阅读详情

相关推荐

【Apache Paimon】-- 2 -- 核心特性 (0.9.0)

用户可以随心所欲地更新记录。复制以保留最后一行,或部分更新,或汇总记录,或第一行,提供了很灵活的处理方式,总之可以用户自己决定。主键表合并机制详情(1)去重(Deduplicate)去重机制(deduplicate)是默认的数据合并机制。对于多条具有相同primary key的数据,Paimon结果表仅会保留最新一条数据,并丢弃其它具有primary key的数据。说明如果最新一条数据是一条delete消息,所有具有该primary key的数据都将被丢弃。

欢迎来到我的博客,一起探索代码里的世界! 1233

【徐葳】流式数据湖新秀-Apache Paimon

为什么要学习这门课程?·新一代流式数据湖技术组件深入讲解,帮助你快速构造数据湖知识体系。·为构建湖仓一体架构提供底层技术支撑。本课程将从原理、架构、底层存储细节、性能优化、管理等层面对Paimon流式数据湖组件进行详细讲解,原理+实战,帮助你快速上手使用数据湖技术。讲师介绍华为HCIP认证大数据高级工程师北京猎豹移动大数据技术专家中科院大数据研究院大数据技术专家51CTO企业IT学院优秀讲师电子工业出版社2022年度优秀作者出版书籍:《Flink入门与实战》、《大数据技术及架构图解实战派》。本课程提供配套课件、软件、试题、以及源码。课程内容介绍:1、什么是Apache Paimon2、Paimon的整体架构3、Paimon的核心特点4、Paimon支持的生态5、基于Flink SQL操作Paimon6、基于Flink DataStream API 操作Paimon7、Paimon中的内部表和外部表8、Paimon中的分区表和临时表9、Paimon中的Primary Key表(主键表)10、Paimon中的Append Only表(仅追加表)11、Changelog Producers原理及案例实战12、Merge Engines原理及案例实战13、Paimon中的Catalog详解14、Paimon中的Table详解15、Paimon之Hive Catalog的使用16、动态修改Paimon表属性17、查询Paimon系统表18、批量读取Paimon表19、流式读取Paimon表20、流式读取高级特性Consumer ID21、Paimon CDC数据摄取功能22、CDC之MySQL数据同步到Paimon23、CDC之Kafka数据同步到Paimon24、CDC高级特性之Schema模式演变25、CDC高级特性之计算列26、CDC高级特性之特殊的数据类型映射27、CDC高级特性之中文乱码28、Hive引擎集成Paimon29、在Hive中配置Paimon依赖30、在Hive中读写Paimon表31、在Hive中创建Paimon表32、Hive和Paimon数据类型映射关系33、Paimon底层文件基本概念34、Paimon底层文件布局35、Paimon底层文件操作详解36、Flink流式写入Paimon表过程分析37、读写性能优化详细分析38、Paimon中快照、分区、小文件的管理39、管理标签(自动管理+手工管理)40、管理Bucket(创建+删除+回滚)

Apache paimon 优化

当 num-sorted-run.stop-trigger 变大时,写入停顿将变得不那么频繁,从而提高写入性能。然而,为了避免Sorted Runs的无限增长,当Sorted Run的数量达到阈值时,writer将不得不暂停写入。默认情况下,当单个存储桶中的小文件超过“compaction.max.file-num”(默认50个)时,就会触发compaction。如果这里出现瓶颈(例如同时写入大量分区),可以使用write-manifest-cache缓存读取的manifest数据,以加速初始化。

ycjunhua的专栏 918

大数据组件paimon工作小记

paimon

weixin2006的博客 1746

【Apache Paimon】-- 16 -- 利用 paimon-flink-action 同步 kafka 数据到 hive paimon 表中

CDC(Change Data Capture)是一种用于捕获数据库变更的技术。它能够实时捕获数据库中的插入、更新和删除操作,并将这些变更数据传递给下游系统进行处理。

欢迎来到我的博客,一起探索代码里的世界! 734

cocos creator接入微信登陆sdk ios篇

cocos creator接入微信登陆sdk ios篇 背景已经在Android篇里面交代过了,有兴趣的朋友可以再看看Android篇 步骤 去微信开放平台下载ios平台所需要的sdk 在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id 在“info”标签栏的“LSApplicationQueriesSchemes“添加weixin 将SDK文件中...

凤小鹿的博客 6362

Paimon——官网阅读:非主键表

Paimon——官网阅读:非主键表

从知识输入到知识输出 1220

Axure RP9 利用中继器实现列表数据的切换,分页器数据的动态交互加载

Axure RP9 利用中继器制作分页组件 在原型制作中,如何实现分页数据的动态加载、分页与数据的交互,每页显示条数的设定。下面通过制作五年级一班成绩单分页列表,分享给大家,适合有一定axure使用基础的人员,如有更好的方案,请多多指教。 最终效果图: 步骤1:首先利用中继器画出成绩单列表,并绑定成绩单数据。 步骤2:画出每页显示条数控制下拉框,利用中继器画出分页组件 步骤3:新增全局标量maxpage(显示的最多页码),minpage(显示的最小页码),i(循环计数),j(最循环数),selectpa

shandongmike的博客 6819

初识Apache Paimon

Apache Paimon得益于Flink在流计算的迅猛发展,集百家长,避百家短,充分融合了Hudi和Iceberg很多优秀的设计,区别于过去类似于Hudi\Iceberg数据湖计算框架以批为主的思想,Paimon的愿景是打造一个真正的流式数据湖。Flink 社区希望能够将 Flink 的 Streaming 实时计算能力和 Lakehouse 新架构优势进一步结合,推出新一代的 Streaming Lakehouse 技术,促进数据在数据湖上真正实时流动起来,并为用户提供实时离线一体化的开发体验。

weixin_43631284的博客 1万+

保姆级教程:在Windows 10/11上安装配置KNIME 5.8.0(含中文文本库更新)

本文提供在Windows 10/11系统上安装配置KNIME 5.8.0的详细指南,包括中文文本库更新和性能优化方案。从环境准备、安装流程到中文文本处理能力强化,逐步指导用户搭建高效的数据分析环境,特别针对国内网络环境和中文用户需求提供实用解决方案。

weixin_29081101的博客 671

波克 上海 Unity开发笔试题 2024

主要分为四部分,如果没有准备好,不要点击笔试链接,进入就会自动开始。

z2014z的博客 3397

Paimon 表定时 Compact 数据流程与逻辑详解

摘要 Apache Paimon 的 Compact 机制是流式数据湖存储系统的核心功能,主要用于优化文件管理、空间利用和查询性能。本文详细解析了其架构设计、触发机制和执行流程: 架构核心:包含 CompactManager、CompactStrategy 和 CompactTask 三大组件,分别负责管理、策略选择和执行合并任务 触发机制:支持内联Compact(写入时触发)、定时Compact(后台调度)和手动Compact三种方式 执行流程:包括文件层级管理、策略选择、异步任务提交和结果处理 优化机制

zhangkaixuan456的博客 1065

如何用DeepSeek写年底工作总结?——从入门到精通的全流程指南

AI助手DeepSeek如何高效撰写工作总结 摘要:本文介绍如何利用DeepSeek智能AI助手高效完成工作总结写作。工作总结具有结构固定、语言规范、内容数据化三大特性,而DeepSeek的结构化生成、风格适配、数据整合和迭代优化四大核心能力与之完美匹配。文章提出"准备-搭架-填充-优化"四步工作法:1)精准输入岗位、时间范围等核心信息;2)先搭建逻辑清晰的提纲框架;3)分模块填充具体内容,突出数据与案例;4)通过风格润色和细节补充进行优化。通过合理运用多模态材料处理能力,DeepSee

通俗易懂学IT 289

Paimon的部分更新以及DeleteVector实现

本文基于Paimon 0.9源码分析了主键表的部分更新和DeleteVector实现机制。部分更新通过MergeTreeWriter的SortBufferWriteBuffer和PartialUpdateMergeFunction实现,按主键+sequenceNumber排序后合并更新字段。DeleteVector在Compaction时生成,通过"Compaction+lookup"机制标记需要删除的记录,仅支持主键表且为bucket级别。核心逻辑集中在MergeTreeWriter的

monkeyboy_tech的博客 1376

超大规模系统(千万级用户)中实现字段级权限控制

摘要:本文提出了一套分布式架构下的字段级权限优化方案,结合RBAC+ABAC混合模型与技术手段实现性能与安全的平衡。方案包括:1)权限模型优化,采用RBAC预计算基础权限与ABAC动态校验敏感字段;2)数据层优化,实现动态字段过滤与加密存储;3)多级缓存策略与预计算机制提升性能;4)分布式架构设计,通过网关校验和策略引擎集群保证扩展性。最终在千万级用户系统中实现99.9%可用性,权限校验延迟控制在50ms以内。

从技术实践立足,从项目管理方法论延伸思考 1353

【RT-DETR多模态融合改进】| 自研 多模态大核选择模块:MM_LSK,适配多模态图像信息融合

本文记录的利用改进的多模态大核选择模块(MM-LSK)优化RT-DETR,构建可见光-红外双模态目标检测网络。在遥感等大尺寸图像的可见光-红外双模态小目标检测任务中,单模态检测易受光照、云雾、背景干扰等因素影响,且小目标外观信息匮乏,无法仅基于单模态外观实现较好的识别,因此需要融合双模态互补特性与广泛的跨模态上下文信息进行辅助。

Limiiiing的博客 382

【Ubuntu datasophon1.2.1 二开之九:验证离线数据入湖】

摘要: 本文记录了在Ubuntu环境下基于DataSophon 1.2.1进行二次开发时,验证离线数据入湖(Paimon)的完整过程。重点解决了Spark 3.1.3与Paimon版本不兼容问题(升级至Spark 3.2.4)、HDFS权限配置、元数据存储切换为Hive Metastore等核心挑战。同时总结了12类典型问题及解决方案,包括Kafka依赖缺失、Derby权限错误、参数格式问题等,最终通过调整组件版本、完善配置和权限管理,成功实现离线数据入湖。关键经验:版本匹配和权限管理是数据入湖的核心痛点,

longxibo的博客 546

车规SoC深度对比:高通8397 vs 比亚迪D9000 vs 联发科CT-X1/MT8676/MT2715

芯片优势弱势最适合场景高通 8397低功耗、低延迟AI和音频处理单屏算力略低HUD + 音响座舱 + 低延迟交互D9000多屏渲染、Wi-Fi7高速通信AI算力中等高端多屏座舱 + 流媒体娱乐CT-X1极高AI算力、多模态渲染功耗较高高端沉浸式智能座舱 + 多摄像头感知MT8676算力均衡、座舱应用全面GPU稍弱全栈智能座舱、音视频多任务MT2715成本低、入门座舱可用算力低,低端显示入门智能座舱、基础信息娱乐。

weixin_43199439的博客 1772

Paimon快照详解

Paimon 快照(Snapshot)机制详解:快照作为表在特定时间点的数据状态记录,具有不可变性、版本化和增量存储特性。核心作用包括数据版本控制、时间点恢复和增量处理。通过配置快照过期参数(保留时间、数量限制)和创建参数(合并大小、并发变更数)来管理存储空间和性能。快照策略采用滑动窗口机制自动清理过期数据,同时支持合并小快照优化存储。提供多种操作方式:SQL/API创建快照、查询快照信息、读取特定版本数据,以及手动合并快照优化性能。

m0_74880098的博客 1866

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Apache Doris 4.0.1 集群部署与 Paimon 数据湖集成实战文档

高可用性 (HA):配置了nd1和nd3双 Metastore 节点,任意单点故障不影响 Doris 业务查询。性能优化 (CBO):Doris 可以从 HMS 获取表的行数、文件大小等统计信息,生成更优的 Join 执行计划。数据准确性:HMS 模式能正确识别 Paimon/Hive 的 ACID 事务状态,避免读取到未提交或已删除的脏数据。运维规范:统一通过 Metastore 管理元数据,符合数仓建设标准。

QXXDYL的博客 1497

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

StarRocks 4.0.2 (CDH 环境)与Paimon数据湖集成混合部署文档

JDK 版本报错现象:解决: StarRocks 4.0.2 强制要求JDK 17。必须在fe.conf和be.conf中显式配置。FE 启动失败 / 端口冲突现象:。原因: CDH 的 Zookeeper (zookeep) 占用了 9010。解决: 将fe.conf中的修改为19010。注意所有 FE 节点必须一致,且 helper 参数也要用新端口。YARN 端口冲突原因: StarRocks BE 默认为 8040,与 YARN NodeManager 冲突。解决: 在be.conf中将。

QXXDYL的博客 1146

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【全网首发】Apache Paimon大厂面试必备系列-基础篇

这是一个系列文章,包含基础篇、原理篇、进阶篇、实践篇等至少4+个系列。欢迎收藏、追更。本系列的文章非常「功利」,完全着眼于面试,当然读者完全可以把它当成学习完Paimon后的自我检验也是可以的。文章较长,推荐收藏。本篇文章是基础篇。基础篇是入门Paimon必须要掌握的部分。本系列内容在知识星球同步更新,知识星球内同步答疑,冲刺中大公司、高阶岗位的同学随时在知识星球提问。本文部分参考了Paimon官...

微信搜:import_bigdata,大数据领域硬核原创作者 2735

Flink+Paimon实时数据湖仓实践分享

随着 Paimon 近两年的推广普及,使用 Flink+Paimon 构建数据湖仓的实践也越来越多。在 Flink 实时数据开发中,对于依赖大量状态 state的场景,如长周期的累加指标计算、回撤长历史数据并更新等,使用实时数仓作为中间存储来代替 Flink 的内部状态 state 是非常有必要的。本文主要分享了使用 Paimon 作为实时状态存储,并在 Flink 中通过 Lookup 维表 ...

淘系技术 3665

Paimon x Spark:助力企业 Lakehouse 架构升级

摘要:本文整理自 Paimon Committer邹欣宇老师在11月15日 Apache Spark & Paimon Meetup,助力 Lakehouse 架构生产落地上的分享。文章介绍了 Paimon x Spark 的发展历程,企业搭建 Lakehouse 面临的挑战,Paimon 通过分层元数据架构支持 ACID 事务,主键表通过引入 LSM Tree 结构实现实时场景分钟级时...

weixin_45906054的博客 1608

Paimon之LSM-Tree及其分层策略

层级文件特征Key 范围特征合并触发条件L0MemTable Flush 结果文件间无序,文件内有序MemTable 满(默认 128MB)L1L0 合并产物文件间可能重叠L0 文件数达到阈值L2+深层合并产物文件间严格不重叠,且全局有序下层文件总大小达到阈值关键配置参数'num-sorted-run.stop-trigger' = '5', -- L0 文件数达到 5 触发 Minor Compaction。

weixin_43935207的博客 561

Apache Doris 集成 Iceberg 与 Paimon:基于 Docker Compose 的湖仓一体查询实战指南

本文以 [samples/datalake/iceberg_and_paimon](https://link.gitcode.com/i/1fc501b81cd973c686e1c8872a732d04) 示例为骨架,完整讲解如何用一套 Docker Compose 环境同时拉起 Apache Doris、Apache Iceberg、Apache Paimon、Flink、Spark 与 Min

gitblog_01013的博客 407
上一篇: LSM Tree 底层设计理念
下一篇: paimon中的Branch
JNWsong
博客等级 码龄9年 287粉丝 204原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值