Appearance
计算与接入选型
链路分工
| 环节 | 组件 | 职责 | 不负责什么 |
|---|---|---|---|
| 变更捕获 | Flink CDC | 读 MySQL/PG 的 binlog,写 Kafka | 不做复杂清洗 |
| 批量接入 | DataX | 全量/增量抽数,写 Iceberg 或 Kafka | 不做常驻服务 |
| 缓冲 | Kafka | 削峰、解耦、可重放 | 不做长期存储 |
| 流处理 | Flink | 实时清洗、聚合、入湖 | 不做 T+1 全量重算 |
| 批处理 | Spark | 全量重算、历史回溯、T+1 报表 | 不做秒级查询 |
| 调度 | DolphinScheduler | 依赖编排、重跑、补数 | 不做计算 |
一、Kafka:为什么不能省
实时链路的三件事——削峰、解耦、可重放——都需要一个消息层:
- 业务库晚高峰的 binlog 洪峰不能直接打到湖上;
- 入湖任务升级、重启时,数据不能丢;
- 算错了要能回到某个位点重算。
部署形态
| 项 | 生产 | 3 节点测试 |
|---|---|---|
| 模式 | KRaft(不再依赖 ZK) | KRaft |
| Broker 数 | ≥3 | 3 |
| 副本因子 | 3 | 3 |
min.insync.replicas | 2 | 2 |
| 保留 | 按业务 3–7 天 | 1 天 |
| 存储 | 独立数据盘 | PVC |
落地要点
- 分区数不是越多越好:按峰值吞吐估,单分区 5–10 MB/s;分区过多会拖垮控制器和 Flink 的 checkpoint。
- Key 决定顺序:同一业务主键必须同 key,否则下游乱序。
- 别把 Kafka 当数据库:保留时间到了就删,长期存储是 Iceberg 的事。
- 监控 lag:消费者 lag 是最重要的指标,比 broker CPU 更能说明问题。
二、Doris:为什么是它
候选对比
| 维度 | Doris | StarRocks | ClickHouse | Greenplum |
|---|---|---|---|---|
| 架构形态 | MPP + 存算分离,多计算集群共享同一份对象存储数据 | MPP,存算分离版本较新 | 单表扫描极快,多表关联弱 | 传统 MPP,扩容成本高 |
| 接入协议 | 兼容 MySQL 协议,现有 BI 工具只改连接串 | 兼容 MySQL 协议 | 自有协议,BI 侧需适配 | PostgreSQL 协议 |
| 湖上查询 | 外部表经 Catalog 直读 Iceberg,热点表再同步本地副本 | 支持 | 外部表能力较弱 | 不支持湖上直读 |
| 并发与更新 | 高并发点查 + 主键表更新 | 高并发强,更新能力相近 | 点查弱,更新代价高 | 并发能力受限 |
| 运维与扩容 | 单一体架构,组件少、参数少,加节点即扩容 | 架构相近,社区迭代较快 | 合并策略与参数调优负担重 | 需专职 DBA |
| 许可 | Apache-2.0 | Apache-2.0 | Apache-2.0 | 社区版已停更 |
结论
Doris 综合最均衡:
- MySQL 协议意味着现有 BI 工具只改一个连接串,接入成本最低;
- 存算分离让"看板查询"和"重算任务"用不同计算集群,互不抢资源;
- 主键表能承接 CDC 的更新,明细核对不用回湖里查。
StarRocks 作为压测对照备选——两者同源,能力接近,最终用 Benchmark 说话,不靠感觉。
注意:Doris 里存的是热点副本,不是事实源。任何"只存在 Doris 里"的数据,都违反了第一原则。
落地要点
- 表模型:明细用 Duplicate,需要更新的用 Unique(Merge-on-Write),聚合报表用 Aggregate。
- 分区与分桶:按天分区,分桶数 ≈ BE 数 × 2–4,别拍脑袋。
- 外表:Iceberg 外表用于低频/全量查询;高频看板才同步成本地表。
- 资源组:把 ETL 写入和 BI 查询分到不同资源组,避免互相拖垮。
- 测试取舍:3 节点可以跑 3 FE + 3 BE,验证副本与选主;只想先跑通就 1 FE + 3 BE,但验证不了 FE 选主。存算分离需要共享存储与 Meta Service,测试期先用存算一体,别把两件事混在一起调。
三、Elasticsearch:只做索引
定位:OpenMetadata 的搜索后端,让人能在 UI 里搜表、搜字段、搜血缘。仅此而已。
三条红线:
- 不承担业务全文检索;
- 不承担日志检索(日志走 Loki);
- 不作为任何数据的唯一存储——删掉 ES,元数据仍在 PostgreSQL,重建索引即可。
许可提醒:Elasticsearch 是 AGPLv3 / SSPL / Elastic License 三选一。内部使用没问题;如果整套平台要交付给客户,改用 OpenSearch(Apache-2.0) 更省事。
四、Flink:实时接入与流处理
为什么是 Flink
- Flink CDC 能直接读 MySQL/PG 的 binlog,不用额外部署 Canal/Debezium 集群;
- 流批一体,实时入湖和离线修正用同一套 SQL;
- K8s Operator 成熟,TaskManager 可以按需伸缩。
链路设计
MySQL ──binlog──► Flink CDC Source ──► Kafka(原始变更) ──► Flink SQL(清洗/打宽) ──► Iceberg为什么 CDC 先写 Kafka 再入湖,而不是直接写湖?
- 任何一段失败(Flink 重启、湖写入限流)都不会丢数据,Kafka 里有原始变更可重放;
- 多个下游(实时指标、入湖、审计)可以各自消费,互不影响;
- 业务库的变更速率和湖的写入速率解耦。
落地要点
- Checkpoint 存 S3:
state.checkpoints.dir=s3://flink/checkpoints,别放本地盘。 - Exactly-once:Kafka sink 开两阶段提交;Iceberg sink 用 Flink 的 Iceberg connector,提交依赖 Iceberg 的原子快照。
- 水位线:CDC 流是 unbounded,窗口聚合必须定义 watermark,否则状态无限增长。
- 反压:看
backpressure指标,不要只看 CPU;反压通常是下游(Kafka/湖)写入跟不上。 - Savepoint:升级作业前先打 savepoint,回滚才有依据。
五、DataX:批量接入
为什么还用它:支持的数据源极多(关系库、文件、Hive、ES、MongoDB……),配置简单,跑完即退,天然无状态。
为什么不用 SeaTunnel 替代:
- SeaTunnel 的卖点是流批一体,但流处理已经由 Flink 承担,优势被抵消;
- DataX 是"提交一个 Job,跑完就结束",K8s 管起来很轻;SeaTunnel 常驻服务,多一层运维。
落地要点:
- DataX 作业打成镜像,用 K8s Job 跑,失败由调度器重试;
- 限流(
speed.byte/record)必须配,否则抽数会把业务库打满; - 全量初始化 + 增量按时间戳/自增 ID,增量字段要有索引;
- 脏数据用
errorLimit控制,别让一条脏数据卡死整个作业。
六、Spark:批处理主力
没有替代品:全量重算、历史回溯、复杂多表关联、Iceberg 维护(compaction / expire snapshots),都靠 Spark。
部署方式:
- 生产用 Spark Operator,作业以
SparkApplicationCRD 提交,镜像、依赖、资源都声明化; - POC 可以直接
spark-submit --master k8s://...,少一层 Operator。
落地要点:
- AQE 打开:
spark.sql.adaptive.enabled=true,动态合并分区、处理倾斜。 - Shuffle 落 S3:
spark.shuffle.service.enabled或 Remote Shuffle Service;本地盘 shuffle 在 K8s 上容易把节点写满。 - Iceberg 写优化:控制文件大小(128–256 MB),写前
DISTRIBUTE BY分区列,减少小文件。 - 资源队列:用 K8s 的 ResourceQuota 限制 Spark 命名空间,避免一个大作业吃光集群。
七、DolphinScheduler:调度收口
对比
| 维度 | DolphinScheduler | Airflow | 定时任务平台(cron/XXL-Job) |
|---|---|---|---|
| 编排方式 | 可视化拖拽 DAG,业务人员能改 | 以 Python 代码定义 DAG,改流程要改代码发版 | 只能按时间触发,无依赖关系 |
| 任务类型 | 内置 Spark / Flink / SQL / Shell / K8s 等 | 需自行封装 Operator | 只能跑脚本 |
| 重跑与补数 | 失败重试、单步重跑、按日历区间补数内置 | 支持,但回填需写脚本 | 无补数概念 |
| 多租户与权限 | 内置项目 / 用户 / 租户与资源队列 | 需插件或外置方案 | 无 |
| 部署形态 | 原生支持容器化与 K8s | 可容器化,但常驻组件较多 | 单机 |
| 生态 | Apache 顶级项目,国内使用广 | Apache-2.0,社区大但偏英文 | — |
更正一个常见说法:Airflow 是有 Web UI 的,它的差异不在"有没有界面",而在 DAG 用代码定义——业务改流程要改代码、发版、评审;DolphinScheduler 是可视化拖拽,运营和数仓自己能改。
结论
DolphinScheduler 在国内生态下集成成本最低:可视化编排、内置主流引擎任务类型、原生容器化、多租户。Airflow 作为备选,适合"平台团队全是 Python 工程师、一切皆代码"的团队。
落地要点
- DAG 粒度:一个业务域一个项目,一个主题域一个工作流,别把几百个任务塞一个 DAG。
- 补数策略:按日历区间补,任务必须幂等(
INSERT OVERWRITE或按分区覆盖)。 - 告警:接 Alertmanager,按级别分流;失败告警要带 DAG、任务、日志链接。
- K8s 任务:用 K8s 任务类型直接起 Pod,避免 Worker 上装一堆客户端。
结论
| 决策点 | 结论 | 备选 | 说明 |
|---|---|---|---|
| 消息 | Kafka(KRaft) | — | 实时链路必需 |
| OLAP | Doris | StarRocks | 用压测决定最终选型 |
| 检索索引 | Elasticsearch | OpenSearch | 只服务元数据平台 |
| 实时接入/计算 | Flink + Flink CDC | Debezium + Kafka Connect | CDC 直读 binlog 更省组件 |
| 批量接入 | DataX | SeaTunnel | 无状态、跑完即退 |
| 批处理 | Spark | — | 全量重算与 Iceberg 维护 |
| 调度 | DolphinScheduler | Airflow | 可视化、补数、多租户 |