1. 课程导入

欢迎进入《Spark与Iceberg金融批处理工程实战》。在动手写第一行作业代码之前,我们需要先建立一张“全局地图”:金融批处理到底难在哪里,Spark与Iceberg各自解决什么问题,它们组合起来为什么能成为当前金融数据平台的主流方案,以及这30章课程将如何一步步把你从“会写Spark”带到“能交付生产级金融批处理链路”。本章不涉及复杂代码,但它是后续所有章节的认知地基。

一、金融批处理场景的四个硬特点

金融行业的数据处理与互联网推荐、日志分析有本质差异,理解这些差异才能理解技术选型。可以归纳为四点:

  • 强一致性优先于极致吞吐。账务、清算、对账类任务一旦出现重复计算或漏算,后果是资金差错,而不是“推荐不准”。因此批处理必须支持幂等重跑、精确一次语义和可追溯的血缘。
  • 数据规模大且分区特征明显。日终跑批常按“业务日期+机构+产品”分区,单日增量可达数亿行,但历史数据需要长期保留并支持回溯,典型场景是T+1全量快照与增量合并并存。
  • Schema演进频繁且必须可控。监管报送口径调整、新增字段、字段类型收敛几乎每月发生。传统Hive表改Schema代价高,容易引发下游任务集体失败。
  • 时间窗口刚性。日终批处理必须在凌晨固定时间前完成,超时会影响开门营业。因此性能优化、资源隔离和失败快速恢复是工程刚需。
金融批处理的核心矛盾可以概括为:在刚性时间窗口内,对大规模、持续演进、要求强一致的数据完成可重跑的计算。Spark解决“算得快、算得稳”,Iceberg解决“存得准、改得动、查得清”。

二、Spark与Iceberg的技术栈定位

很多初学者会把Spark和Iceberg混为一谈,实际上它们处于数据栈的不同层。Spark是计算引擎,负责分布式执行、内存计算、SQL解析与任务调度;Iceberg是表格式层,位于计算引擎与存储(HDFS/S3/OSS)之间,负责元数据、快照、分区演进和ACID语义。二者是协作关系,不是替代关系。

在金融批处理链路中,典型分工如下:

层次 组件 核心职责 金融场景关注点
计算层 Spark SQL / DataFrame / Structured Streaming 分布式计算、SQL解析、Shuffle、任务调度 批任务稳定性、资源隔离、失败重试
表格式层 Apache Iceberg 快照、Manifest、ACID、Schema/分区演进 幂等重跑、时间旅行、口径回溯
存储层 HDFS / S3 / OSS 对象与文件持久化 成本、生命周期、跨集群访问
调度层 Airflow / DolphinScheduler 依赖编排、补数、告警 日终窗口、SLA监控

理解这张分层表非常关键:后续课程中遇到的“小文件过多”“快照膨胀”“分区裁剪失效”等问题,往往需要先判断它属于计算层还是表格式层,才能对症下药。

金融批处理分层协作:计算层 × 表格式层 × 存储层 调度层 Airflow / DolphinScheduler:依赖编排、补数、SLA告警 日终窗口 计算层:Apache Spark Spark SQL · DataFrame · Shuffle · 任务重试 · 资源隔离 解决:算得快、算得稳、可重跑 表格式层:Apache Iceberg Snapshot · Manifest · ACID · Schema/分区演进 · 时间旅行 解决:存得准、改得动、查得清 存储层:HDFS / S3 / OSS(成本 · 生命周期 · 跨集群)

三、一个典型金融批处理案例:日终账户余额快照

为了把抽象概念落地,我们看一个贯穿课程的简化案例。某银行需要在每日凌晨2点前产出“账户日终余额快照表”,供次日对账、监管报送和风控使用。原始数据来自上游交易流水表,按小时增量写入。

传统Hive方案的做法是:每天用INSERT OVERWRITE重写整个分区,或者用INSERT INTO追加。前者在数据量大时耗时不可控,后者在任务重跑时会产生重复数据。引入Iceberg后,流程变为:

  1. 读取当日增量交易流水,按账户聚合出余额变动。
  2. 与历史快照做MERGE INTO,实现“有则更新、无则插入”。
  3. Iceberg在提交时生成新快照,旧快照保留,支持按业务日期回溯。
  4. 若任务失败,直接重跑同一逻辑,MERGE保证幂等,不会重复累加。
-- 示意:Iceberg MERGE 实现幂等日终快照
MERGE INTO fin.dwd_account_balance t
USING (
  SELECT account_id, biz_date, SUM(amount) AS delta
  FROM fin.ods_txn_flow
  WHERE biz_date = DATE '2025-03-01'
  GROUP BY account_id, biz_date
) s
ON t.account_id = s.account_id AND t.biz_date = s.biz_date
WHEN MATCHED THEN UPDATE SET t.balance = t.balance + s.delta
WHEN NOT MATCHED THEN INSERT (account_id, biz_date, balance)
VALUES (s.account_id, s.biz_date, s.delta);
注意:上面代码中的UPDATE SET t.balance = t.balance + s.delta在真实生产中需要结合“幂等键”设计,否则重跑仍可能重复累加。后续第12章会专门讲解幂等重跑模式,这里先建立“MERGE不等于自动幂等”的意识。

四、常见误区与学习复盘

在正式进入后续章节前,先澄清三个高频误区,避免走弯路:

  • 误区一:用了Iceberg就自动解决所有一致性问题。Iceberg提供的是表级ACID和快照隔离,但业务逻辑的幂等性仍需开发者设计。计算逻辑写错,表格式救不了你。
  • 误区二:Spark调优就是调大Executor内存。金融批处理的瓶颈常在Shuffle、数据倾斜和小文件,盲目加内存可能加剧GC。需要按“定位瓶颈—验证假设—小步调整”的方法论推进。
  • 误区三:Schema演进可以随意做。Iceberg支持加列、改类型,但下游消费方是否兼容、历史数据如何回填,仍需治理。演进必须配合元数据管理和影响面评估。

本课程的整体框架遵循“认知—基础—进阶—实战—治理”的路径:前4章建立场景与技术栈认知;第5至12章讲解Spark批处理核心能力与Iceberg表操作;第13至20章深入性能优化、分区演进、快照管理与幂等设计;第21至27章通过账户余额、对账、监管报送等真实场景做端到端实战;最后3章聚焦数据质量、血缘治理与生产运维。每一章都围绕“金融批处理可交付”这一目标展开,而不是孤立地讲API。