5.2 Spark:Lineage、DAG、DataFrame 与数据倾斜
Spark 把 transformation 组织成惰性计算的 DAG,action 触发实际执行;一个 action 可能涉及多个 job。性能关键不是“数据都在内存”,而是减少扫描、Shuffle、序列化和不必要物化,并让失败分区可重算。
RDD 的三个核心属性
- partition:并行和数据局部性的单位;
- dependency/lineage:分区由哪些父分区计算而来;
- function:如何从父数据生成当前数据。
RDD 不可变。丢失分区可以沿 lineage 重算,而不必始终复制每个中间结果。
可靠 checkpoint 在数据仍可计算时,将结果写入可靠存储,完成后才能截断 lineage。它适合长依赖链或需要独立恢复点的作业;等源数据已经丢失,再调用 checkpoint 并不能补回缺失分区。RDD 的 checkpoint() 先标记意图,之后的 action 才实际物化。
cache/persist 缓存可重算结果,是否写磁盘取决于 StorageLevel;丢失缓存后仍依赖源数据和确定性 lineage。localCheckpoint 则借用 executor 的本地缓存来截断依赖,不具备可靠存储 checkpoint 的容错保证。省下的持久化成本,会在丢 executor 时回来问你要答案。
Transformation 与 Action
map、filter、select、join 等先构建计划;count、collect、写出等 action 触发执行。
重复 action 若没有 persist,可能重复计算整个 lineage。persist 也不是越多越好:缓存占内存、可能溢写磁盘,还需要驱逐和序列化。
collect() 把全部结果拉到 driver,只适合确定很小的数据。生产代码要有硬上限,不能凭开发样本判断。
窄依赖与宽依赖
map/filter 这类窄依赖可以直接从相应父分区计算子分区,多个转换可在同一 stage 中流水执行,各分区 task 仍然并行。
需要跨分区重新分发数据的宽依赖会触发 Shuffle,并形成 stage 边界。不过 join 或按 key 聚合不必每次都 Shuffle:已有兼容分区器、可复用分布,或使用广播 join 时,计划会不同。应检查实际依赖与执行计划,不能仅按算子名字判断。
优先用 reduceByKey/aggregateByKey 进行 map-side combine,而不是先 groupByKey 把所有值跨网络搬运。但自定义聚合仍需满足正确的结合语义。
DataFrame 让引擎看见结构
RDD 中的任意函数对优化器是黑盒;DataFrame 提供 schema 和表达式,使优化器能够:
- 数据源支持时的 predicate pushdown;
- column pruning;
- 常量折叠;
- join 重排与策略选择;
- 更紧凑的内存和代码生成路径。
UDF 可能阻断部分优化,优先使用内置表达式。解释执行计划时同时看逻辑计划、物理计划和运行时统计,不能只看源码的链式顺序。
Join 策略与倾斜
- broadcast join:把足够小的一侧广播到 executors,避免大表 shuffle;
- sort-merge join:双方按 key 重分区和排序,适合大数据;
- shuffle hash 等策略:适用性由引擎和统计决定。
广播前要考虑序列化传输大小、driver 构建开销,以及每个 executor 解码后完整哈希表的内存;磁盘上压缩过的文件大小不等于构建表大小。executor 数量还会放大总传输和存储成本。热点 join key 可以拆分、单独处理或使用自适应倾斜优化,但空值或默认 key 往往是数据质量问题,不应仅靠加资源掩盖。
小文件与分区数量
太多小文件增加元数据、任务调度和打开成本;太少大分区降低并行度并增加失败重算范围。
输出分区数应根据数据量、下游读取和目标文件大小设计。coalesce(1) 会把全量输出压到单个 task,通常只适合很小结果,还可能连带减少前面窄依赖阶段的并行度。想得到一个文件很容易,想让最后那个 task 早点下班就难了。
验证作业而不只看“成功”
- 输入、过滤、输出记录数;
- 主键唯一性、空值率和范围约束;
- 每分区大小与最大/中位比;
- Shuffle、spill、GC、executor loss;
- 计划是否使用期望 pushdown/join;
- 重跑是否产生同一业务结果;
- 输出发布是否原子,失败重试是否重复。
参考资料
Apache Spark, RDD.checkpoint
Apache Spark, RDD.localCheckpoint
Zaharia et al., Resilient Distributed Datasets
Apache Spark, RDD Programming Guide
Apache Spark, SQL Performance Tuning