2. Spark 基础入门:发展史、Hadoop 对比、核心组件与运行架构

在催收触达场景中,每天需要处理数千万条通话记录、短信回执、IVR 按键流和还款行为日志。传统单机或简单批处理框架难以在 30 分钟内完成全量数据的清洗、聚合与模型评分。Spark 凭借其内存计算和统一引擎,成为催收数据中台的首选计算框架。本节从发展史、与 Hadoop 的对比、核心组件和运行架构四个维度,帮你建立 Spark 的全局认知。

2.1 Spark 发展史:从实验室到大数据标配

Spark 诞生于加州大学伯克利分校 AMPLab,最初是为了解决 MapReduce 在迭代计算和交互式查询上的性能瓶颈。以下是关键里程碑:

时间版本 / 事件核心意义
2009Spark 0.5 原型AMPLab 启动项目,基于内存的分布式计算框架
2010开源发布采用 Berkeley Software Distribution 许可,社区开始关注
2013Apache 孵化器加入 Apache 软件基金会,进入标准化治理
2014Spark 1.0引入 Spark SQL、MLlib、Streaming 和 GraphX,形成统一平台
2016Spark 2.0Dataset/DataFrame 成为一等公民,Tungsten 和 Catalyst 优化引擎
2020+Spark 3.x自适应查询执行、动态分区裁剪、GPU 加速支持
催收场景启示: Spark 2.0 之后的 DataFrame API 和 Catalyst 优化器,让催收分析师可以用 SQL 直接处理千亿级通话记录,无需编写复杂的 MapReduce 代码。

2.2 Spark 与 Hadoop 对比:不只是快

很多人认为 Spark 是 Hadoop 的替代品,实际上两者在架构哲学上有本质区别。催收业务中,Hadoop 适合海量历史归档的批量存储,Spark 则擅长需要快速迭代的实时特征计算。

对比维度Hadoop MapReduceApache Spark
计算模式磁盘迭代,每个 stage 写 HDFS内存 DAG,尽量在内存中完成计算
中间结果必须落盘,IO 开销大优先内存缓存,支持 checkpoint
延迟分钟级(任务启动 + 磁盘读写)秒级到分钟级(内存计算 + 快速调度)
编程接口仅 Map 和 Reduce 两个阶段RDD、DataFrame、Dataset、SQL、MLlib
迭代计算每次迭代重新读取数据,效率低内存中反复使用,适合机器学习训练
流处理不支持原生流Structured Streaming,微批 + 连续处理
容错机制任务级别重试 + 数据副本RDD Lineage 血统 + Checkpoint
典型催收场景历史通话详单归档、合规审计日志存储实时逾期评分、催收策略动态计算、通话特征提取
选型建议: 催收数据平台通常采用 Hadoop HDFS 做底层存储,Spark 做计算引擎。HDFS 存放原始通话录音索引和还款流水,Spark 负责每日触达策略的批量评分和实时催收队列刷新。

2.3 Spark 核心组件:统一生态的四大支柱

Spark 不是一个单一的计算引擎,而是一个包含 SQL、流、机器学习和图计算的统一平台。催收业务中,这四个组件覆盖了从数据清洗到模型部署的全链路。

Spark 统一生态核心组件 Spark Core(RDD / 调度 / 内存管理) Spark SQL 结构化查询 / DataFrame Spark Streaming 微批 / 连续流处理 MLlib 机器学习算法库 GraphX 图计算 / 关系分析 催收全链路组件映射 • Spark SQL:读取 Hive 催收宽表,过滤逾期天数 > 30 的客户,生成触达名单 • Spark Streaming:实时消费 Kafka 通话状态流,更新催收队列优先级 • MLlib:训练逾期概率预测模型,输出每个客户的触达策略评分 • GraphX:分析担保圈、共债关系,识别高风险关联客户
常见误区: 催收团队常把 Spark 当作“快一点的 Hive”来用,只使用 Spark SQL。实际上,在实时触达评分和共债图分析场景中,Streaming 和 GraphX 能带来 5-10 倍的效率提升。建议在架构设计阶段就规划好组件分工。

2.4 Spark 运行架构:Driver、Executor 与集群管理器

理解 Spark 的运行架构,是调优催收任务性能的前提。一个 Spark 应用在集群中如何分配资源、如何并行执行,直接决定了每日触达任务能否在业务 SLA 内完成。

2.4.1 核心角色

角色职责催收场景类比
Driver运行 main() 方法,创建 SparkContext,解析 DAG,调度 Task 到 Executor催收策略调度中心:拆解任务、分配工单
Executor在 Worker 节点上运行 Task,缓存数据,返回结果给 Driver催收坐席:执行具体的触达动作(外呼、短信)
Cluster Manager管理集群资源,分配 Executor 所需的 CPU 和内存催收人力排班系统:决定每个时段安排多少坐席
TaskExecutor 上最小的执行单元,对应一个分区上的计算逻辑单个催收工单:对一个客户执行一次触达

2.4.2 任务提交流程

  1. 提交应用: 使用 spark-submit 将打包好的催收任务 JAR 或 Python 脚本提交到集群。
  2. 启动 Driver: Cluster Manager 分配一台机器运行 Driver 进程,Driver 创建 SparkContext。
  3. 申请资源: SparkContext 向 Cluster Manager 申请 Executor 资源(CPU 核数、内存大小)。
  4. 启动 Executor: Cluster Manager 在 Worker 节点上启动 Executor 进程,并向 Driver 注册。
  5. 分发任务: Driver 将用户代码(如 DataFrame 转换)转换成 DAG,再拆分为 Stage 和 Task,分发到 Executor 执行。
  6. 结果汇聚: Executor 执行 Task 并将结果写回 HDFS 或直接返回 Driver,Driver 更新催收结果表。
Spark 运行架构:任务提交流程 Cluster Manager Driver SparkContext / DAGScheduler Executor 1 Task 1 | Task 2 | 缓存 Executor 2 Task 3 | Task 4 | 缓存 HDFS / Kafka 催收结果表 Driver 负责调度,Executor 负责计算和数据缓存;催收任务中 Executor 数量决定并行度

2.4.3 催收任务调优要点

  • 并行度设置: spark.sql.shuffle.partitions 建议设置为 Executor 总核数的 2-3 倍。催收宽表 JOIN 操作多,分区数不足会导致内存溢出。
  • 内存分配: Executor 内存中,spark.memory.fraction 默认 0.6,剩余留给用户代码。催收特征计算常涉及大字典广播,需适当调大 spark.memory.offHeap.size。
  • 数据本地性: 尽量让 Task 在数据所在的节点上执行,减少网络传输。催收数据通常存储在 HDFS 上,合理设置 spark.locality.wait 避免任务等待。
  • 广播变量: 催收策略配置表(如催收等级映射、节假日规则)通常较小,使用 broadcast 代替普通 JOIN,可减少 Shuffle 数据量 50% 以上。
实战案例: 某催收平台每日处理 2000 万条通话记录,初始使用默认配置,任务运行 45 分钟。通过将 Executor 数量从 10 调整为 20,并设置 spark.sql.shuffle.partitions=60,任务缩短至 18 分钟,满足 20 分钟 SLA 要求。

2.5 本章小结