2. Spark MLlib 模型生命周期:模型训练、保存与加载、部署、监控

在风控场景中,Spark MLlib 模型的完整生命周期涵盖从离线训练到在线推理、再到持续监控的全链路。理解每个阶段的关键操作与风险点,是进行模型风险排查的基础。本章按时间顺序拆解四个核心阶段:模型训练、模型保存与加载、模型部署、模型监控。

2.1 模型训练:Pipeline 与 Estimator

MLlib 使用 Pipeline 将特征工程与模型训练串联为一个工作流。训练阶段的核心风险包括:数据倾斜、特征穿越、参数未收敛。

关键流程: DataFrame → Transformer(特征处理)→ Estimator(算法训练)→ PipelineModel(拟合结果)
// 示例:逻辑回归 Pipeline 训练
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.feature.{VectorAssembler, StandardScaler}
import org.apache.spark.ml.{Pipeline, PipelineModel}

val assembler = new VectorAssembler()
  .setInputCols(Array("feature1", "feature2", "feature3"))
  .setOutputCol("rawFeatures")

val scaler = new StandardScaler()
  .setInputCol("rawFeatures")
  .setOutputCol("features")

val lr = new LogisticRegression()
  .setMaxIter(100)
  .setRegParam(0.01)

val pipeline = new Pipeline().setStages(Array(assembler, scaler, lr))
val model = pipeline.fit(trainingData)
阶段 核心组件 常见风险 排查方向
特征处理 Transformer(StringIndexer, VectorAssembler) 类别基数过高、空值未处理 检查 DataFrame 统计信息、空值比例
模型拟合 Estimator(LR, GBT, RandomForest) 不收敛、过拟合、梯度爆炸 查看 trainingLog、验证集 AUC/KS
交叉验证 CrossValidator / TrainValidationSplit 参数网格过大导致 OOM 监控 Executor 内存、调整并行度
Spark MLlib 模型训练 Pipeline 流程 原始 DataFrame Transformer 链 Estimator 拟合 PipelineModel 风险排查要点: • 检查 VectorAssembler 输入列是否存在 Null 或 Infinity • 验证 Estimator 的 maxIter 是否真正收敛(查看 history 对象)

2.2 模型保存与加载:序列化与版本管理

MLlib 使用 PipelineModel.save(path) 将完整模型持久化到 HDFS 或对象存储。加载时使用 PipelineModel.load(path)。此阶段的风险集中在元数据兼容性和文件完整性。

最佳实践: 保存时同时写入模型版本号、训练时间、特征列表等元数据到外部表(如 Hive),便于后续追溯。
// 模型保存
model.write.overwrite().save("hdfs://cluster/models/risk_lr_v1.0")

// 模型加载
val loadedModel = PipelineModel.load("hdfs://cluster/models/risk_lr_v1.0")

// 检查模型 UID 是否匹配
println(loadedModel.stages.last.uid)
操作 API 风险场景 排查方法
保存 write.overwrite().save() 写入中途失败导致目录不完整 检查 _SUCCESS 标记文件;对比文件数
加载 PipelineModel.load() Spark 版本不兼容(2.x vs 3.x) 检查 metadata/part-00000 中的 sparkVersion
版本管理 手动维护版本表 模型文件被误覆盖 启用 HDFS 回收站或对象存储版本控制

2.3 模型部署:批处理与实时推理

风控模型部署通常有两种模式:离线批处理(T+1 评分)和实时 API(毫秒级决策)。MLlib 原生模型适合批处理;实时场景需转换为 PMML 或 ONNX 格式,或使用 Spark 的 transform 方法在微批中执行。

常见陷阱: 实时部署时直接使用 PipelineModel.transform() 处理单条数据,会导致 Driver 端序列化开销极大。应使用 mapPartitions 或广播模型变量。
// 批处理部署:对全量用户评分
val scoreDF = loadedModel.transform(batchData)
scoreDF.select("user_id", "prediction", "probability").show()

// 实时部署优化:广播模型
val broadcastModel = spark.sparkContext.broadcast(loadedModel)
val resultRDD = inputRDD.mapPartitions { partition =>
  val model = broadcastModel.value
  partition.map { row => model.transform(row) }
}
模型部署双模式架构 离线批处理模式 Hive 全量数据 PipelineModel 批量评分结果 → Hive/ES 实时推理模式 Kafka 事件流 广播模型 实时评分 → Redis/API 批处理适合全量回溯;实时推理需关注延迟与模型序列化开销

2.4 模型监控:漂移检测与性能衰减

部署后的模型需要持续监控两个维度:数据漂移(特征分布变化)和概念漂移(标签分布变化)。MLlib 不提供内置监控,通常结合 Spark Streaming 或外部工具(如 Evidently、Whylogs)实现。

监控指标清单:
  • PSI(群体稳定性指标):衡量特征分布偏移
  • KS / AUC:区分能力是否衰减
  • 空值率 / 异常值率:数据质量变化
  • 模型评分均值:整体风险偏好是否偏移
// 使用 Spark 计算 PSI 示例
val expected = spark.table("expected_features")  // 训练集分布
val actual = spark.table("actual_features")      // 当前批次分布

val psiDF = expected.join(actual, "feature_bin")
  .withColumn("psi_component", 
    ($"actual_pct" - $"expected_pct") * log($"actual_pct" / $"expected_pct"))
  .groupBy("feature_name")
  .agg(sum("psi_component").alias("psi"))

psiDF.filter($"psi" > 0.25).show()  // 超过阈值触发告警
监控维度 常用指标 告警阈值 排查动作
数据漂移 PSI、KL 散度 PSI > 0.25 检查上游特征源、ETL 逻辑变更
概念漂移 KS、AUC 衰减率 AUC 下降 > 5% 重新训练或回滚至稳定版本
数据质量 空值率、异常值率 空值率 > 10% 排查数据管道、补全缺失字段
风险排查建议: 在模型监控阶段,优先对比当前批次与训练批次的 summary 统计量(均值、方差、分位数)。若发现某个特征均值偏移超过 3 个标准差,应立即触发告警并阻断模型自动决策。