2. Spark核心概念速览:RDD、DataFrame、Dataset、SparkSession、DAG调度、宽窄依赖

在深入贷后预警实时计算之前,必须建立对Spark核心抽象的统一认知。本章以“速览”方式梳理六大核心概念,后续章节将在此基础上展开具体实现。

2.1 三大数据抽象:RDD、DataFrame、Dataset

Spark提供了三种主要的数据抽象,分别面向不同的使用场景和性能需求。理解它们的演进关系与适用边界,是正确选择API的前提。

特性 RDD (Resilient Distributed Dataset) DataFrame Dataset
引入版本 Spark 1.0 Spark 1.3 Spark 1.6
数据表示 Java/Scala对象,无Schema Row对象,带Schema(列名+类型) 强类型JVM对象,带Schema
类型安全 编译时安全 运行时检查 编译时安全
性能优化 依赖开发者手动优化 Catalyst优化器 + Tungsten执行 Catalyst优化器 + Tungsten执行
适用场景 底层转换、非结构化数据 SQL分析、数据集成、快速开发 需要类型安全 + 性能的复杂ETL
贷后预警场景 自定义分区逻辑、原始日志解析 预警规则SQL、指标聚合 预警策略实体建模
选型建议:在贷后预警实时计算中,优先使用DataFrame进行SQL化规则计算;当需要封装预警策略为强类型对象(如WarningRule、RiskEvent)时,使用Dataset;仅在需要自定义分区器或处理非结构化日志时回退到RDD。

2.2 SparkSession:统一入口

SparkSession是Spark 2.0引入的统一编程入口,替代了旧的SparkContext、SQLContext、HiveContext。在贷后预警应用中,所有操作都从SparkSession开始。

// 创建SparkSession(贷后预警实时任务典型配置)
val spark = SparkSession.builder()
  .appName("PostLoanWarningRealTime")
  .config("spark.sql.shuffle.partitions", "8")   // 控制并行度
  .config("spark.streaming.backpressure.enabled", "true") // 背压
  .getOrCreate()

// 读取Kafka数据流(DataFrame API)
val kafkaDF = spark.readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "node1:9092,node2:9092")
  .option("subscribe", "post_loan_events")
  .load()
关键点:SparkSession内部封装了SparkContext(负责集群通信与资源调度)、SQLContext(负责SQL解析与优化)以及StreamingContext(负责流式处理上下文)。在结构化流(Structured Streaming)中,无需显式创建StreamingContext,SparkSession即可管理流作业。

2.3 DAG调度与宽窄依赖

DAG(有向无环图)调度是Spark的核心执行机制。理解DAG如何划分Stage、宽窄依赖如何影响数据Shuffle,是调优实时计算性能的基础。

2.3.1 宽依赖 vs 窄依赖

对比维度 窄依赖 (Narrow Dependency) 宽依赖 (Wide Dependency)
父RDD分区与子RDD分区关系 一个父分区最多被子分区使用一次 一个父分区被子分区多次使用(多对多)
是否触发Shuffle 否,数据在同一个节点流水线执行 是,需要跨节点重新分区
典型算子 map、filter、union、mapPartitions groupByKey、reduceByKey、join(非广播)、repartition
容错恢复代价 低,只需重新计算丢失分区的父分区 高,需要重新计算所有父分区
贷后预警影响 适合过滤、转换等预处理 预警规则中的分组聚合、跨客户关联查询

2.3.2 DAG调度流程

Spark DAG调度器将用户代码转换为物理执行计划,核心步骤为:

  1. 构建逻辑DAG:根据RDD/DataFrame的依赖关系生成有向无环图。
  2. 划分Stage:从DAG末端反向遍历,遇到宽依赖(Shuffle)时切分Stage。
  3. 提交Task:每个Stage内部生成多个Task,由TaskScheduler分发到Executor执行。
  4. 流水线执行:同一Stage内的窄依赖算子在一个Task内连续执行,避免中间结果落盘。
DAG调度与Stage划分示例 RDD A (HDFS) RDD B (map) RDD C (filter) RDD D (groupByKey) RDD E (map) RDD F (save) Shuffle Stage 0(窄依赖流水线) Stage 1 Stage 2 说明: • 窄依赖(绿色节点):map、filter等算子在同一Stage内流水线执行,无需Shuffle。 • 宽依赖(红色节点):groupByKey触发Shuffle,DAG调度器在此处切分Stage。

2.4 核心概念在贷后预警中的映射

将上述概念映射到贷后预警实时计算场景,可以更直观地理解每个抽象的实际作用:

  • SparkSession:负责连接Kafka数据源、定义预警规则UDF、启动流式计算。
  • DataFrame:承载Kafka中的JSON事件,使用SQL表达“逾期天数 > 30 且 客户等级为高风险”等规则。
  • Dataset<WarningRule>:将预警规则解析为强类型对象,利用Encoder提升序列化性能。
  • DAG调度:将“读取→解析→过滤→聚合→输出”转换为Stage,Shuffle发生在按客户ID分组聚合时。
  • 宽窄依赖:窄依赖用于事件过滤、字段转换;宽依赖用于跨分区统计(如计算客户历史逾期次数)。
常见误区:不要认为RDD已被淘汰。在贷后预警中,当需要自定义数据分区策略(如按客户ID哈希分区到指定Executor)或处理二进制协议数据时,RDD仍然是唯一选择。DataFrame/Dataset在底层最终也会编译为RDD操作。

2.5 概念关系总览

Spark核心概念关系总览 SparkSession RDD DataFrame Dataset DAG调度 宽依赖 / 窄依赖 • SparkSession是统一入口,可创建RDD/DataFrame/Dataset,并提交DAG作业。 • 宽窄依赖是DAG划分Stage的依据,直接影响实时计算的并行度和Shuffle开销。

2.6 本章小结

  • RDD是底层抽象,提供细粒度控制;DataFrame是结构化数据首选,享受Catalyst优化;Dataset兼顾类型安全与性能。
  • SparkSession统一了所有上下文,是贷后预警应用的唯一入口。
  • DAG调度将作业划分为Stage,宽依赖触发Shuffle并切分Stage,窄依赖支持流水线执行。
  • 在贷后预警实时计算中,合理利用窄依赖减少Shuffle,优先使用DataFrame API编写预警规则,是保证低延迟的关键。