流式数据湖Paimon探秘之旅 (十一) Changelog变更日志

第11章:Changelog变更日志

导言:实时数据流的核心

在第10章,我们讲了同一主键的多个版本如何合并 。现在需要讨论如何让下游系统感知到这些变化 。答案就是Changelog(变更日志)

Changelog的作用

ini 复制代码
原始表数据:
order_id=1: status="未支付" → "已支付" → "已发货" → "已签收"

Changelog记录:
{order_id=1, status="未支付", _change_flag=INSERT}
{order_id=1, status="已支付", _change_flag=UPDATE_AFTER}
{order_id=1, status="已发货", _change_flag=UPDATE_AFTER}
{order_id=1, status="已签收", _change_flag=UPDATE_AFTER}

下游系统(如Kafka、实时处理)可以实时感知这些变化

第一部分:Changelog的基本概念

1.1 Change Flag(变化标记)

每条Changelog记录都有一个Change Flag,表示数据的变化类型:

sql 复制代码
+I (INSERT):新增数据
-D (DELETE):删除数据
-U (UPDATE_BEFORE):更新前的镜像(用于旧值)
+U (UPDATE_AFTER):更新后的值(用于新值)

例子:
订单状态从"未支付"更新为"已支付"

Changelog:
-U: {order_id=1, status="未支付"}  ← 旧值
+U: {order_id=1, status="已支付"}  ← 新值

下游系统可以:
├─ 看到完整的前后对比
├─ 识别出是UPDATE操作
└─ 可以决定如何处理(仅保留新值、两者都保留等)

1.2 ChangelogProducer(变更日志生成器)

ChangelogProducer负责生成和维护Changelog

sql 复制代码
配置:
changelog-producer: NONE | INPUT | FULL_COMPACTION | LOOKUP

NONE:不生成Changelog
INPUT:仅从输入生成(只有INSERT/DELETE)
FULL_COMPACTION:全量压缩时生成(完整的前后镜像)
LOOKUP:使用Lookup表加速(实时生成)

第二部分:Changelog的生成模式

2.1 NONE模式

yaml 复制代码
CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY,
    status STRING,
    ...
) WITH (
    'changelog-producer' = 'NONE'
);

特点:
├─ 不生成Changelog
├─ 性能最优(减少开销)
└─ 下游看不到数据变化

使用场景:
└─ 不需要实时感知变化的场景
   如纯分析表、非实时处理

2.2 INPUT模式

yaml 复制代码
CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY,
    status STRING,
    ...
) WITH (
    'changelog-producer' = 'INPUT'
);

生成的Changelog:
只包含来自应用的INSERT和DELETE
不包含更新操作的前值

例子:
应用插入:INSERT order_id=1, status="未支付"
  → Changelog: +I {order_id=1, status="未支付"}

应用删除:DELETE order_id=1
  → Changelog: -D {order_id=1, status="未支付"}

应用更新:UPDATE status="已支付" WHERE order_id=1
  → Changelog: +I {order_id=1, status="已支付"} (新值)
           -D {order_id=1, status="未支付"} (旧值)

特点:
├─ 生成完整的前后镜像
├─ 开销中等
└─ 适合需要UPDATE前值的场景

2.3 FULL_COMPACTION模式

yaml 复制代码
CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY,
    status STRING,
    ...
) WITH (
    'changelog-producer' = 'FULL_COMPACTION'
);

生成的Changelog:
仅在Compaction完成时生成
包含完整的前后镜像

流程:
Time 1: 用户插入order_id=1, status="未支付"
  → 内部写入Level 0,暂不生成Changelog

Time 2: 用户更新status="已支付"
  → 内部写入Level 0,暂不生成Changelog

Time 3: Compaction触发(Level 0→Level 1)
  → Changelog生成!
     -D {order_id=1, status="未支付"}
     +U {order_id=1, status="已支付"}

特点:
├─ Changelog生成延迟(等待Compaction)
├─ 性能最优(批量生成)
└─ 适合可接受短延迟的场景

2.4 LOOKUP模式

yaml 复制代码
CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY,
    status STRING,
    ...
) WITH (
    'changelog-producer' = 'LOOKUP'
);

生成的Changelog:
实时生成,每次写入时立即生成

流程:
Time 1: 用户插入order_id=1, status="未支付"
  → 立即生成Changelog: +I {order_id=1, status="未支付"}

Time 2: 用户更新status="已支付"
  → Lookup旧值(从现有数据读取)
  → 立即生成Changelog:
     -U {order_id=1, status="未支付"}  (旧值来自Lookup)
     +U {order_id=1, status="已支付"}  (新值来自输入)

特点:
├─ 实时生成,无延迟
├─ 开销较大(每次Lookup)
└─ 适合实时流处理

第三部分:Changelog的消费

3.1 从Paimon读取Changelog

java 复制代码
// 创建支持Changelog的表扫描
StreamDataTableScan scan = table
    .newStreamScan()
    .withChangelogMode(ChangelogMode.ALL);  // 读取所有变化

// 扫描Changelog
DataIterator iterator = scan.plan().execute();
while (iterator.hasNext()) {
    Row row = iterator.next();
    
    // 获取变化标记
    RowKind kind = row.getKind();
    
    switch (kind) {
        case INSERT:
            System.out.println("新增:" + row);
            break;
        case UPDATE_BEFORE:
            System.out.println("更新前:" + row);
            break;
        case UPDATE_AFTER:
            System.out.println("更新后:" + row);
            break;
        case DELETE:
            System.out.println("删除:" + row);
            break;
    }
}

3.2 Flink消费Changelog

java 复制代码
StreamExecutionEnvironment env = 
    StreamExecutionEnvironment.getExecutionEnvironment();

TableEnvironment tableEnv = StreamTableEnvironment.create(env);

// 注册Paimon表
tableEnv.executeSql(
    "CREATE TABLE orders ("
    + "  order_id BIGINT,"
    + "  status STRING,"
    + "  PRIMARY KEY (order_id) NOT ENFORCED"
    + ") WITH ("
    + "  'connector' = 'paimon',"
    + "  'path' = '/path/to/paimon/orders'"
    + ")");

// 实时读取Changelog
DataStream<Row> stream = tableEnv.toChangelogStream(
    tableEnv.sqlQuery("SELECT * FROM orders"));

stream.print();

env.execute();

3.3 Kafka同步

Paimon可以将Changelog实时同步到Kafka:

yaml 复制代码
CREATE TABLE orders_kafka (
    order_id BIGINT,
    status STRING,
    ...
    PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
    'connector' = 'kafka',
    'topic' = 'orders-changelog',
    'properties.bootstrap.servers' = 'localhost:9092',
    'format' = 'avro'
);

-- 同步Changelog到Kafka
INSERT INTO orders_kafka
SELECT * FROM orders WHERE __op <> 'before';

第四部分:生产级配置

4.1 实时数据同步场景

yaml 复制代码
CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY,
    user_id BIGINT,
    amount DECIMAL,
    status STRING,
    created_at BIGINT,
    updated_at BIGINT,
    ...
) WITH (
    'changelog-producer' = 'LOOKUP',
    'changelog.num.retained.min' = '5',
    'changelog.num.retained.max' = '10'
);

-- 配置说明:
-- changelog-producer:使用LOOKUP实时生成
-- changelog.num.retained.min/max:最少保留5个,最多10个Snapshot的Changelog

下游消费:
Flink CDC Source → Paimon Table
    ↓
Changelog生成
    ↓
Kafka Sink(同步给消费方)

4.2 低延迟分析场景

yaml 复制代码
CREATE TABLE metrics (
    hour STRING PRIMARY KEY,
    page_id STRING PRIMARY KEY,
    pv BIGINT,
    uv BIGINT,
    ...
) WITH (
    'changelog-producer' = 'FULL_COMPACTION',
    'compaction.min.file-num' = '3',
    'num-sorted-run-compaction-trigger' = '3'
);

-- 配置说明:
-- 激进的Compaction触发,使得Changelog定期生成
-- 下游可以定时拉取Changelog进行分析

第五部分:Changelog的局限与最佳实践

5.1 选择合适的模式

css 复制代码
场景1:实时数据同步(CDC)
→ 使用LOOKUP
└─ 需要实时前后镜像

场景2:准实时分析(小时级)
→ 使用FULL_COMPACTION
└─ 可接受Compaction延迟

场景3:纯仓库(无下游实时处理)
→ 使用NONE
└─ 最优性能

5.2 开销管理

arduino 复制代码
LOOKUP模式开销:
├─ 每条记录都要Lookup旧值
├─ 额外的读取IO:~2倍
└─ 若表频繁更新,开销严重

FULL_COMPACTION模式开销:
├─ Changelog生成不涉及额外IO
├─ 仅在Compaction时生成
└─ 总体开销低,但有延迟

建议:
├─ 小表(<1GB)→ LOOKUP(可接受额外开销)
├─ 中表(1-100GB)→ FULL_COMPACTION(平衡方案)
└─ 大表(>100GB)→ 考虑不启用Changelog或使用INPUT

总结

Changelog的核心价值

markdown 复制代码
Paimon表
    ↓ (启用Changelog)
原始数据 + Changelog数据流
    ↓
下游系统可以:
├─ 实时感知数据变化
├─ 获取完整的前后镜像
├─ 同步到其他系统(Kafka、数据库等)
└─ 支持CDC(Change Data Capture)

配置checklist

  • 根据业务选择changelog-producer模式
  • 设置合理的changelog retention(保留时间)
  • 如果性能敏感,评估开销
  • 配置下游消费者的处理逻辑

下一章预告:第12章讲解索引与加速,包括Deletion Vector、文件索引、统计信息

相关推荐
hzcj888几秒前
汇正财经:出海数据向好,创新药热度高
大数据·人工智能
Bzc11456231 小时前
中医辨证调护:慢病视角下的血糖健康养护思路
大数据·人工智能·生活
Fluxart.ai1 小时前
2026电商AI出图质量验收标准与质检SOP完整教程
大数据·人工智能
泛普软件1 小时前
工程施工项目管理办公系统能解决哪些现场管理难题与超支问题
大数据·人工智能·软件需求
用户3610588626121 小时前
Spark 核心之广播变量、累加器原理深度剖析
大数据·spark
A15362551 小时前
WMS 仓储系统的软件有哪些?2026 主流产品分类与选型参考
大数据·人工智能
hopsky2 小时前
《HBase 权威指南》 Lars George
大数据·数据库·hbase
Elastic 中国社区官方博客2 小时前
Elasticsearch:列式索引模式 - Columnar index mode
大数据·数据库·elasticsearch·搜索引擎·全文检索
仍然.2 小时前
服务端高并发分布式结构演进之路
大数据·数据库·redis
企查查数据服务3 小时前
从席位订阅到用量计费:Agent 正在重写企业软件商业模式
大数据·人工智能