一、两代项目中的性能问题如何变化
第一版主要面对:
- 一个表一个 Source 导致任务和 Checkpoint 过多;
- 全部表共用一个 Source 导致积压和背压;
- Postgres 单条写入吞吐不足;
- 低频数据无法及时 Flush;
- 连接池过多或回收不及时。
第二版加入 Kafka 后,又增加:
- Topic Partition 规划;
- Producer 批量与事务;
- Consumer Lag;
- Kafka Source 和保序算子并行度;
- 多目标 Sink 独立容量;
- 消息保留和重放成本。
二、建立端到端容量模型
text
源库 CDC 产生速率
↓
Source 表组与并行度
↓
Kafka Producer / Partition
↓
Kafka Consumer / Key 分布
↓
顺序处理与路由
↓
JDBC Batch / 连接 / 事务
↓
Postgres / Doris 实际写入能力
任何一段到达上限,调高其他段都不会提升整体吞吐。
三、Source 分组
第一版已经证明,表分组不能走两个极端。第二版应继续演进为按权重分组:
text
表数量
历史数据量
每秒变更量
单条记录大小
业务优先级
是否存在热点主键
建议启动时输出每组实际表清单和 UID,运行中记录每个 Source 的输入速率与反压。
四、Kafka Partition 与并行度
| 配置 | 受什么限制 |
|---|---|
| Producer 并行度 | Source 数量、事务 ID、Broker 能力 |
| Topic Partition | 峰值吞吐、Key 分布、保序要求 |
| Kafka Source 并行度 | Partition 数量 |
| SQLServer 保序并行度 | Key 数量和状态大小 |
| JDBC Sink 并行度 | 目标库连接、锁和事务能力 |
Partition 越多,吞吐上限通常越高,但状态、文件句柄、网络连接和运维复杂度也会增加。
五、Batch 与 Flush Interval
| 调整 | 收益 | 风险 |
|---|---|---|
| 增大 Batch | 减少 JDBC 往返,提高吞吐 | 事务更大、延迟和重放范围增加 |
| 减小 Batch | 降低单批延迟 | 小事务增多,数据库压力上升 |
| 增大 Interval | 更容易攒满批次 | 低流量数据延迟变高 |
| 减小 Interval | 低流量更快落库 | Flush 更频繁 |
第一版当前使用固定批量和时间阈值;第二版把这些参数放入每个 Sink 配置,更适合按业务系统分别压测。
六、Checkpoint 也是性能参数
Checkpoint 会带来 Source 状态持久化、网络 Barrier 和 JDBC 强制 Flush。
需要同时观察:
text
Checkpoint duration
Checkpoint alignment time
Checkpoint failure count
JDBC flush duration
Kafka consumer lag
backpressure
state size
间隔过短会让低批量 Flush 频繁发生;间隔过长则扩大故障恢复后的重放范围。合理值只能由状态规模、HDFS 性能和恢复目标共同决定。
七、Doris 不应永远停留在 JDBC
JDBC 适合复用公共 Sink 抽象、快速打通链路。吞吐继续增长时,可评估 Doris Stream Load。
切换写入方式不能只比较速度,还要重新设计:
- 批次 Label 与幂等;
- Upsert / Delete 语义;
- Checkpoint 前提交确认;
- 失败重试和部分成功;
- 错误行定位。
八、启动摘要
每次 Job 启动应打印脱敏摘要:
text
system / mode / source type
source groups / table count
topic / partitions / transactional prefix
consumer groups / startup modes
enabled sinks / target names
checkpoint storage / interval
operator parallelism
batch size / flush interval
route count / metadata count
这能让"配置有没有生效"从猜测变成证据。
九、运行指标
| 维度 | 指标 |
|---|---|
| 时效 | 端到端延迟、Kafka Lag、最长未落库时间 |
| 吞吐 | Source 输入、Kafka 写入、Sink 成功记录 |
| 稳定性 | Checkpoint 成功率、重启次数、Flush 失败 |
| 状态 | Checkpoint 大小、保序 State 数量、Buffer 记录数 |
| 数据质量 | 缺映射、缺主键、跳过记录、冲突、源目标对账差异 |
Job Running 只能证明进程存在,不能证明数据正确。
十、DLQ 与补偿重放
无法解析、无法路由或单条写入失败的数据,需要进入死信 Topic 或错误表,至少保留:
text
system
topic / partition / offset
source database/schema/table
operation
event time
failure stage
reason
original payload or reference
DLQ 之后必须有受控重放工具,支持按时间、Offset、表和业务 Key 缩小范围。重放前再次验证目标端幂等。
十一、数据质量闭环
建议建立分层对账:
text
源库 CDC 变更量
↕
Kafka Topic 输入量
↕
各 Consumer Group 输出量
↕
目标端实际影响行数
对账不一定要求每秒严格一致,但应能在可接受窗口内解释差异:积压、重试、过滤、无效路由还是实际丢失。
十二、推荐演进路线
阶段 1:链路可用
- Source、Kafka、目标 Sink 打通;
- 目标端有业务主键;
- Checkpoint 可以稳定完成。
阶段 2:链路可靠
- 稳定 UID;
- SQLServer 顺序状态;
- JDBC 事务与 Checkpoint Flush;
- 元数据 Fail Fast;
- 故障注入测试。
阶段 3:链路可运营
- 启动摘要;
- Lag、Flush、Checkpoint 指标;
- 告警、DLQ、补偿重放;
- 源端与目标端数据质量对账。
阶段 4:平台化
- 配置版本与审计;
- 环境资源 Profile;
- 自动生成提交命令;
- Savepoint 发布与回滚;
- 目标端原生高吞吐写入。
十三、系列结语
两代项目连起来看,架构演进不是从"落后"到"先进",而是问题规模发生了变化:
text
第一版:用最短链路解决 SQLServer → Postgres 实时 ODS
第二版:用 Kafka 与公共抽象解决多源、多目标和独立演进
真正值得复用的是方法:先明确边界,准确描述一致性,用配置承接业务变化,用公共抽象固定可靠性,再用指标证明链路长期正确。