Flink-Hudi技术实践:Upsert场景开发实践

一、背景介绍

之前写了一篇Flink实时场景下Hudi-Insert开发实践的文章,主要讲述纯插入操作场景下的技术原理与配置实践。然而,Upsert能力才是Hudi实现数据湖准实时数据更新的一大利器,Hudi凭借其Upsert(Update+Insert)能力,高效处理数据的插入、更新与删除操作,并保证基于主键的数据唯一性和一致性。今天聚焦在Hudi-Upsert操作场景,介绍Upsert模式的的技术原理、适用场景、关键参数与最佳实践,提供一套可落地的开发实践参考。

二、Hudi-Upsert技术特性与适用场景

1.Hudi-Upsert技术特性

Hudi的upsert模式是 Hudi-Flink 写入的核心模式,其核心逻辑为:将流式数据的插入、更新、删除操作统一写入 Hudi MOR 表,基于 主键(分区表需结合分区字段)的索引机制,自动将写入行为标记为update(主键已存在)或insert(主键不存在),保障表中数据的唯一性与一致性;同时支持基于precombine.field字段解决同主键数据冲突,基于hoodie.is_deleted字段实现物理删除。

  • 增量写入:Flink 将 CDC 流数据写入 Hudi MOR 表的增量日志文件(Log File),保证秒级低延迟写入。
  • 主键去重与冲突解决:基于「主键 + 分区字段」判断数据唯一性,若存在同主键数据,通过precombine.field指定的时间 / 版本字段排序,自动保留最新记录。
  • 物理删除支持:通过hoodie.is_deleted字段标记删除记录,实现数据的物理删除(而非逻辑标记)。
  • Compaction 合并:定期将 Log 文件合并到 Parquet 基础数据文件,生成新版本的基础文件,解决 Log 文件堆积问题,平衡读写性能。

2.Hudi-Upsert应用场景

基于Upsert模式的技术特性,其典型应用场景包括:

  • 数据库变更流捕获(CDC)

从MySQL Binlog或Flink CDC流中获取的数据,包含大量INSERT、UPDATE、DELETE操作。使用Upsert模式写入Hudi MOR表,可确保Hudi表中始终保留每条记录的最新状态,且不会出现重复数据。这正是构建实时ODS层的核心方案。

  • 实时数据同步与ETL

在数仓分层建设中,ODS层到DWD层的处理往往需要保留数据的变更历史。开启changelog.enabled参数后,Hudi MOR表可保留消息的所有变更(I/-U/U/D),下游Flink作业可进行全链路的增量计算。

  • 数据湖上的近实时查询

对于需要兼顾写入实时性与查询性能的场景,MOR表的Upsert模式提供了理想的平衡------写入时仅追加Log文件,查询时通过Compaction合并成Parquet,实现分钟级数据可见。

三、Hudi-Upsert参数配置指南

|------------------------------------------------------------|
| 'connector' = 'hudi' |
| 'table.type' = 'MERGE_ON_READ' |
| 'path' = '' |
| 'write.operation' = 'upsert' |
| 'hoodie.datasource.write.recordkey.field' = '' |
| 'hoodie.datasource.write.partitionpath.field' = '' |
| 'metadata.enabled' = 'false' |
| 'hive_sync.enable' = 'true' |
| 'hive_sync.db' = '' |
| 'hive_sync.table' = '' |
| 'hive_sync.mode' = 'hms' |
| 'hive_sync.metastore.uris' = '' |
| 'hive_sync.table.strategy' = 'RT' |
| 'hoodie.datasource.write.hive_style_partitioning' = 'true' |
| 'index.type' = 'BUCKET' |
| 'hoodie.bucket.index.num.buckets' = '' |
| 'write.precombine' = 'true' |
| 'precombine.field' = '' |
| 'write.rate.limit' = '' |

其他自定义参数可参阅Hudi官网(https://hudi.apache.org/docs/1.0.2/configurations)。

2.Compaction介绍

Compaction 是 Hudi MOR 表的独有核心机制,其核心逻辑是:定期将 MOR 表中的增量日志文件(Log File)合并到对应的Parquet 基础数据文件,生成新版本的基础数据文件,解决 Log 文件过多导致的查询性能下降问题,平衡写入延迟与查询性能。

Compaction 分为两个独立阶段:

  • 计划生成:由 Flink 写入任务实时生成合并计划(必须配置compaction.schedule.enabled='true');
  • 计划执行:分为在线合并(Flink 任务内异步执行)和离线合并(独立 Spark 任务执行)两种方式,二选一。

其中Compaction核心参数说明如下:

参数名 含义 默认值 详细说明
compaction.async.enabled 是否启用异步合并(MOR 表专属) true 设为true在线合并模式false离线合并模式
compaction.schedule.enabled 是否启用生成合并计划(MOR 表专属) true 在线 / 离线合并均需设置为true,由 Flink 任务实时生成合并计划
compaction.trigger.strategy 合并触发策略 num_or_time 支持按 commit 次数(num_commits)或时间(time)触发合并
compaction.delta_commits 多少次 delta commit 生成合并计划 5 离线合并需与 checkpoint 间隔配合,至少 20-30 分钟生成一次计划,推荐配置 10-15
compaction.delta_seconds 多少秒触发 compaction 3600 离线合并需与 checkpoint 间隔配合,至少 20-30 分钟生成一次计划
compaction.max_memory 合并可用内存(MB,超出则溢写) 100 直接影响 log 文件合并效率,推荐不低于 300MB;数据量越大,需增大该值提升合并效率
write.task.max.size 单个 write task 最大内存(MB) 1024 单桶 1GB 的 Parquet 文件合并耗时约 5min,该值与compaction.max_memory共同决定合并性能

根据内部实践,内存设置一般存在以下关系:compaction.max_memory < write.task.max.size < taskmanager堆内存(约taskmanager总内存40%)。

3.在线/离线Compaction实践

为保障Hudi表数据查询性能,我们以20min内完成Compaction为目标,在内部展开多场景压测验证(数据大小、字段数、TPS、资源规格等),最后制定了一个Compaction策略选型的参考原则:

  • checkpoint 间隔 120s
  • 单条数据大小 0.2kb
  • 表字段数 60
  • parquet 文件大小推荐 0.3g~1g,最大不超过 2g
存量数据量 在线合并适用 TPS 离线合并适用 TPS
0-1000w ≤4000 >4000
1000w-2000w ≤3000 >3000
≥2000w或 TPS>4000 不推荐 推荐
  • 存量数据量≤1000w(在线合并)
TPS 区间 TM 资源 合并和写入配置
0-1000 4c12g 'compaction.max_memory'='300', ``'write.task.max.size'='1200',``'write.rate.limit'='1200'
1000-2500 6c18g 'compaction.max_memory'='500', ``'write.task.max.size'='1800',``'write.rate.limit'='3000'
2500-4000 8c24g 'compaction.max_memory'='500', ``'write.task.max.size'='1800',``'write.rate.limit'='6000'
  • 存量数据量 1000w-2000w(在线合并)
TPS 区间 TM 资源 合并和写入配置
0-1000 4c12g 'compaction.max_memory'='300', ``'write.task.max.size'='1200',``'write.rate.limit'='1200'
1000-2000 6c18g 'compaction.max_memory'='500', ``'write.task.max.size'='1800',``'write.rate.limit'='3000'
2000-3000 8c24g 'compaction.max_memory'='500', ``'write.task.max.size'='1800',``'write.rate.limit'='5000'
  • 存量数据量>2000w或TPS>4000(离线合并)
TPS 区间 TM 资源 合并和写入配置
0-5000 4c12g 'compaction.max_memory'='100', ``'write.task.max.size'='1200',``'write.rate.limit'='7000'
5000-8000 6c18g 'compaction.max_memory'='100', ``'write.task.max.size'='1900',``'write.rate.limit'='10000'
8000-12000 8c24g 'compaction.max_memory'='100', ``'write.task.max.size'='1900',``'write.rate.limit'='13000'

四、总结展望

本文围绕Flink写入Hudi MOR表的Upsert模式,系统介绍了其技术原理、应用场景以及核心的Compaction配置实践。技术没有银弹,通过深入理解原理、结合场景精准调优,我们能够最大化发挥Flink-Hudi-Upsert组合的潜力,为实时数据湖建设提供坚实支撑。

对比维度 Flink-Hudi Upsert-MOR Flink-Hudi Insert-MOR 核心选型结论
写入核心逻辑 主键匹配,支持增 / 改 / 删,自动去重、保留最新版本 纯追加写入,无主键匹配、无去重,允许主键重复 有更新 / 删除 / 保最新 → Upsert;纯日志追加 → Insert
索引依赖 必须维护主键索引(Bucket/Bloom),索引开销高 不依赖主键索引,无索引查询 & 写入开销 高吞吐日志场景优先 Insert,节省索引资源
冲突处理 依赖precombine.field自动覆盖旧数据,解决乱序 不处理冲突,多条同主键数据全部留存 需要数据收敛→Upsert;需要全链路溯源→Insert
删除能力 原生支持物理 / 逻辑删除 CDC 数据 不支持删除标记,删除数据会变成新增记录 CDC 业务、订单状态变更必选 Upsert
后台治理机制 依赖Compaction合并日志,解决增量更新堆积 依赖Clustering聚类,解决小文件碎片 合并目的不同:Upsart 收敛数据,Insert 规整文件
性能开销 写入延迟中等,高 TPS 下易受 Compaction 抢占资源 写入延迟极低,峰值吞吐远高于 Upsert 亿级日志埋点、IoT 时序数据首选 Insert
适用数据体量 中低~高 TPS,存量大、频繁更新的业务数据 超高 TPS,不可变、仅追加的流水数据 60 字段:Upsert 建议≤4000TPS,Insert 可上万 TPS
运维复杂度 需区分在线 / 离线 Compaction,关注数据一致性 只需治理小文件 Clustering,逻辑简单 轻量化运维、快速上线优先 Insert
典型业务场景 MySQL CDC 入湖、实时维表、订单交易、用户画像 APP 埋点、行为日志、系统监控、IoT 设备数据 业界标准选型,严格匹配业务数据特征
相关推荐
人工智能培训2 小时前
样本效率与安全探索的矛盾解析及平衡路径
大数据·人工智能·深度学习·算法·机器学习·知识图谱·故障诊断
第二只羽毛2 小时前
C++ 高并发内存池4
java·大数据·linux·c++·算法
2601_949221032 小时前
2026数字会议系统榜单发布,保伦股份入选十大品牌
大数据
Apache Flink2 小时前
Apache Flink Agents 0.2.1 发布公告
大数据·flink·apache
首席数智官2 小时前
AI CRM 2.0时代:SaaS厂商的生死局
大数据·人工智能·物联网
珠海西格电力3 小时前
零碳园区能源互联技术路径适配方案的成本效益分析
大数据·人工智能·架构·智慧城市·能源
尽兴-3 小时前
Elasticsearch 高可用集群架构:Master 选举、Shard 分配与容灾设计
大数据·elasticsearch·架构·集群·节点·可视化工具·分片
Elastic 中国社区官方博客3 小时前
从 Elasticsearch runtime fields 到 ES|QL:将传统工具适配到当前技术
大数据·数据库·sql·elasticsearch·搜索引擎·全文检索
万琛3 小时前
【Flink_CEP】MySQL 动态规则 + Kafka 实时流 + Flink CEP 后缀收集的实战方案
mysql·flink·kafka