跳至主要内容

Apache Spark 架构:数据从业者指南

了解 Apache Spark 如何在规模上处理数据——从基础组件到驱动现代大数据工作流的高级特性。
Patrick Brus
Patrick Brus

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续继续即表示您接受我们的 使用条款,我们的 隐私政策 ,并且您的数据存储在美国。

您是否曾尝试调试一个突然失败的 Spark 任务,却发现自己完全迷失在 Spark 的“兔子洞”里? 

我最初使用 Apache Spark 时,以为只要写几步 PySpark 转换,Spark 就会“神奇地”在集群上横向扩展。我错了。Spark 的性能完全取决于您是否理解幕后发生了什么。

本指南适合任何不想把 Spark 当作黑盒的人。我们将从主从模型与执行流程,到内存管理与容错机制,逐步解析 Spark 的架构设计。 

如果您想构建快速、具备容错能力且高效的大数据应用,那就来对地方了!

Apache Spark 的基础架构

在您写下第一行 PySpark 代码之前,Spark 已经为您做了一些架构层面的决策。Spark 之所以快,不仅因为内存计算,更因为它建立在可扩展且能应对现实世界混乱场景的主从架构之上,比如节点崩溃hes, Java Virtual Machine (JVM) 问题,以及不稳定的数据量。

让我们拆解 Spark 的核心架构,并看看它为何在现代大数据工作流中依然强大且常用。

主从范式

Spark 的核心是主从 模型。可以这样理解:

  • Driver(主节点):这是 Spark 的大脑。它运行您的 main() 函数,创建 Spark 上下文,处理 DAG 调度,并指挥集群执行。
  • Executor(工作节点):这是“肌肉”。它们执行任务、在内存中保留数据,并向 driver 汇报。

这种设置让您专注于定义转换,而由 Spark 决定在 executors 上如何并行运行它们。 

我喜欢这套设计的一个原因是它与部署方式无关。同一段代码可在本机、Kubernetes 或 Mesos 上运行,无需改动。这使得本地开发测试更简单,随后即可无缝扩展到集群而无需重写代码。

Spark 的 driver‑worker 分离还有一个强大的好处:提升故障隔离。如果某个工作节点在执行任务时宕机,Spark 可以把该任务重新分配给其他工作节点,而不会导致应用崩溃。

核心组件

让我们拆解 driver 和各节点内部发生了什么。 

Diagram showing the Spark architecture

Spark 架构。作者自绘。

Spark 上下文

当您调用 SparkContext() 或使用 SparkSession.builder.getOrCreate() 时,您就打开了通往 Spark 内部“魔法”的大门。

Spark 上下文会:

  • 连接到集群管理器
  • 分配 executors
  • 跟踪作业状态与执行计划

Spark 会在幕后构建一个有向无环图(DAG)来表示转换。该 DAG 会被拆分为阶段和任务,并行执行。

DAG 调度器负责确定哪些任务可以一起运行,任务调度器则把它们分配给 executors。同时,块管理器(Block manager)确保数据按需缓存、shuffle 或重载。 

这种分层设计让 Spark 弹性极强,您可以分别微调内存、存储与计算。

如果您在做 Spark 转换或特征工程,可以查看PySpark 特征工程课程,看看这套架构如何实际运作。

Executor 运行时

Executor 是实际完成工作的地方。

每个 executor 会运行:

  • 一个或多个任务(多线程)
  • 一块用于缓存数据与输出 shuffle 的内存
  • 各自独立的 JVM 实例

您可以配置每个 executor 获得多少内存、使用多少核心、内存不足时是否应写入磁盘。 

但要小心:内存分配不足会频繁触发内存溢出错误;而分配过多又会浪费资源。监控与调优在这里至关重要。

执行工作流:从代码到集群

写 PySpark 代码看起来很简单。您过滤一个 DataFrame、做个连接、再聚合一下,然后运行。但在这套干净的 API 背后,Spark 正悄悄启动一个执行引擎,把工作分发到多台节点上。 

让我们走一遍幕后发生的流程。

从逻辑计划到物理计划

多数 Spark 用户起初并不了解:当您编写 PySpark 代码时,并不会立刻执行。您是在构建计划,而 Spark 的 Catalyst 优化器会接手该计划,将其转化为高效的执行策略。

它分四个阶段工作:

  1. 解析:Spark 解析列名、数据类型与表引用,确保一切有效。
  2. 逻辑优化:应用谓词下推与常量折叠等规则;优化过滤并合并投影。
  3. 物理规划:基于数据规模、分区等因素评估多种执行策略并选出最优方案。
  4. 代码生成:最终通过全阶段代码生成(whole-stage codegen)产出 JVM 字节码。 

Image showing a diagram of Spark’s Catalyst Optimizer

Spark 的 Catalyst 优化器。图源 Databricks。

因此,那串 .select()、.join()、.groupBy() 并不是逐行执行,而是先被分析、优化,再编译成可在集群上高速运行的代码。

如果想快速查阅常用 PySpark 命令,可以看看这份PySpark 速查表。

DAG 调度器与阶段创建

计划确定后,DAG 调度器开始接管。

它会根据 shuffle 边界把作业拆分为阶段,决定哪些需要顺序执行,哪些可以并行执行。

主要有两类阶段:

  • ShuffleMapStage:涉及 shuffle,通常由 groupBy() 或 join() 等宽依赖转换引起。随后数据会被分区并在网络中传输。该阶段用于为 ResultStage 计算所需数据。
  • ResultStage:这些阶段产生输出,比如写入磁盘或将结果返回给 driver。

我学到的一个关键点是尽量减少 shuffle。shuffle 必须在阶段结束前完成,且代价昂贵。您需要了解它们在 DAG 中的出现位置,并思考是否能进一步优化代码以减少 shuffle 次数。 

任务执行生命周期

当 DAG 调度器创建好所有阶段后,它们就可以在不同的 executors 上执行了。 

任务执行的生命周期大致如下:

  1. 任务序列化:driver 将任务指令序列化并发送到 executors。
  2. shuffle 写阶段:Spark 将分区后的输出写入本地磁盘。
  3. 拉取阶段:下一阶段的 executors 会从集群中的其他节点获取相关的 shuffle 文件。
  4. 反序列化与执行:executors 对数据反序列化,运行您的逻辑,并可能进行缓存或写出结果。
  5. 垃圾回收:JVM 自动回收不再被 Spark 应用使用的内存。这一步对防止内存泄漏、确保应用稳定运行至关重要。

基于我的经验给个小提示:如果某个 Spark 作业之前运行正常、如今却卡住,常见原因是垃圾回收或 shuffle 拉取延迟。务必检查您的代码,并确保理解 Spark 架构,从而有效优化这些问题。

内存管理架构

Spark 的内存管理非常复杂,如果没弄明白,可能会让您在调试上耗费大量时间。 

因此我们来看看 Spark 在底层是如何管理内存的,以便您心中有数,避免为慢代码或内存溢出问题而长时间调试。

统一内存模型

在 Spark 1.6 之前,内存被严格划分为执行(用于 shuffle 和 join)与存储(用于缓存)。Spark 1.6 引入了统一内存模型,改变了这一点。 

在统一内存模型中,内存大致分为三个关键池:

  • 保留内存:少量内存用于 Spark 内部与系统。 
  • Spark 内存:用于存放执行数据与缓存,且是动态共享的。如果作业在 shuffle 上需要更多内存、缓存上需要更少(或反之),Spark 会做出自适应。
  • 用户内存:用于存放用户自定义的数据结构,以支持在 Spark 应用中执行用户代码。

Spark 内存池进一步划分为两部分:

  1. 执行器内存:在处理任务的各个阶段用于存放临时数据(如 shuffle、join、聚合等)。 
  2. 存储内存池:用于缓存数据与存储内部数据结构。 

这种弹性让 Spark 能更灵活地应对不可预测的数据量。 

但这也意味着在您不了解内部状况时,控制力会有所下降。比如,如果您对一个大型 DataFrame 调用 cache(),同时在同一阶段还进行昂贵的聚合,Spark 可能会为了给 shuffle 腾地方而驱逐已缓存的数据。

堆外与列式存储

在 Spark 的堆外与列式存储中,Tungsten 引擎发挥了作用。 

Tungsten 引入了多项优化,大幅提升了 Spark 性能:

  • 堆外内存管理:Spark 可将部分数据存放在 JVM 堆外,降低垃圾回收开销,让内存管理更可预测。
  • 二进制格式存储:数据以紧凑、利于缓存的二进制形式存储,提升 CPU 利用率并启用向量化执行。
  • 感知缓存的算法:Spark 能更有效利用 CPU 缓存,避免不必要的 RAM 或磁盘读取。

如果您在使用 DataFrame,这些优化已经在幕后为您工作了。这也是我鼓励大家使用 DataFrame 与 SQL API 而不是原生 RDD 的原因之一。无需额外调优,就能充分受益于 Catalyst 与 Tungsten。

如果您在做数据清洗流程,可在用 PySpark 清洗数据课程中看到这些优化的实际应用。

容错机制

如果您从事分布式系统,就有一个铁律:它们会失败。节点会崩溃,网络会出错,executor 会内存不足并退出。

但 Spark 天生为这些问题而建,确保您的作业依然能成功完成。 

让我们深入了解 Spark 如何在出现不稳定性时,仍能保证作业成功。

RDD 血统追踪

RDD(弹性分布式数据集)是 Spark 的基础数据结构,“弹性”绝非空谈。 

Spark 使用血统(lineage)来确保在节点故障、数据丢失时可以重算每个 RDD。 

因此当某个节点失败时,Spark 会基于血统图重算丢失的数据。 

实际工作原理如下: 

  • 窄依赖(如 map() 或 filter()):Spark 只需重算丢失的分区。
  • 宽依赖(如 groupBy() 或 join()):Spark 可能需要跨多个分区拉取数据,因为可能涉及多个阶段的输出。 

血统使您无需手动处理故障。然而,如果血统图过长(包含上百个转换),重算代价会变大。这时就需要用到检查点(checkpointing)。

检查点与预写日志

在复杂工作流或流式作业中,Spark 不能只依赖血统,这就是检查点发挥作用的地方。

您可以调用 rdd.checkpoint() 将当前 RDD 状态持久化到可靠存储(如 HDFS)。 

随后 Spark 会截断血统。如发生错误,它会直接加载数据而非重算。

在结构化流处理中,Spark 还使用预写日志(WAL)来确保数据在传输中不丢失。 

其稳定性体现在: 

  • 可靠接收器:在处理前将输入数据写入日志。
  • Executor 心跳:定期上报以确认 executors 存活且健康。
  • 检查点目录:对流式作业,保存偏移量、元数据与输出状态,以便断点续跑。

对批处理作业,检查点是可选的;对流式管道,则是必需的。 

想象一下:一个运行了 10 小时后失败的 Spark 作业,借助检查点和 WAL,您可以从中断处继续执行。 

高级架构特性

到现在,您已经看到了 Spark 如何处理作业,以及它的内存与容错机制。

本节我们将探讨一些高级架构升级,使 Spark 更具动态性、更实时、更具适应性。

自适应查询执行(AQE)

AQE 于 Spark 3.0 引入,通过在运行时基于收集到的统计信息动态调整执行计划来提升查询性能。

AQE 的特性包括:

  • 动态切换连接策略:如果广播连接内存放不下,AQE 会切换为排序合并连接(sort-merge join)。
  • 合并 shuffle 分区:将过小的 shuffle 分区合并为更大的分区,降低开销。
  • 处理数据倾斜:AQE 可拆分倾斜分区,平衡执行时间。

这一特性能带来颠覆性提升,使原本需要大量手动调优与反复试错的作业,能够在运行时自适应优化。

只需通过配置显式启用(spark.sql.adaptive.enabled = true)。如果您运行的是 Spark 3.0 及以上版本,没有不启用的理由。

结构化流架构

结构化流将 Spark 引擎扩展到实时领域,而无需您学习全新的 API。

在幕后,它依然采用微批处理,但会处理:

  • 偏移量管理:Spark 精确跟踪从数据源(Kafka、socket、文件等)读取了哪些数据。配置正确时可提供强有力的“恰好一次”保证。
  • 水位线:在基于时间的聚合中,Spark 使用水位线决定“过晚数据”的丢弃时机,这对事件时间处理至关重要。
  • 状态存储:进行窗口聚合或流式连接时,Spark 会在微批之间维护状态。该状态存储于磁盘,并通过检查点避免数据丢失。

强大之处在于:流处理的体验像批处理。您写个 groupBy() 或 filter(),其余交给 Spark 处理,让流式分析无需专门的工具链也能上手。

安全架构

如果您在生产环境运行 Spark,尤其是在金融、医疗或类似领域,您需要了解 Spark 如何处理认证、加密与审计。

下面我们深入看看这些主题,以及 Spark 的实现方式。

认证与加密

Spark 拥有许多安全特性,需要您先行启用。但启用后,Spark 能为安全通信与认证提供一套可靠工具: 

  • 认证(SASL):Spark 使用简单认证与安全层(SASL)来验证,只有授权的用户与服务才能提交作业或连接集群。
  • 传输加密(AES-GCM,SSL/TLS):Spark 通过 AES-GCM(带认证的加密)或 TLS 加密节点间通信,防止作业数据被窃听,尤其适用于多租户或云环境。
  • Kerberos 集成:在 Hadoop/YARN 环境下,Spark 可与 Kerberos 集成实现安全的用户认证,从而与企业身份与访问管理系统打通。
  • UI 访问控制:Spark Web UI 可能泄露敏感信息(如日志、输入路径、SQL 查询),请设置 spark.acls.enable=true 以及 spark.ui.view.acls 和 spark.ui.view.acls.groups 进行限制。

您可以在 Spark 的官方文档中查看全部安全特性。请务必检查并启用所需功能,以保护您的 Spark 应用。

审计与合规

记录“谁在何时做了什么”同样关键。 

Spark 支持: 

  • 事件日志:启用后(spark.eventLog.enabled=true),Spark 会将每个作业、阶段与任务事件记录到磁盘。您可用它们回放作业历史或满足审计要求。
  • 基于角色的访问控制(RBAC):Spark 本身不提供 RBAC,但如果您通过 Databricks、EMR 或 OpenShift 等平台使用 Spark,通常可在基础设施层获得 RBAC。Spark 将以定义的身份提交作业,从而控制对数据与计算资源的访问。
  • 数据源侧的脱敏与访问控制:Spark 可从多种源读取(Parquet、Delta Lake、Hive 等),访问控制应在这些源头强制执行。

性能优化模式

Spark 很强大也很快,如果知道该在哪些方面下手,还能更快。 

有若干方向可以尝试优化,从而充分发挥 Spark 的能力。我们分别展开。

Shuffle 优化

如果说 Spark 有弱点,那就是 shuffle。当数据需要在分区间移动时(通常在 groupByKey()、distinct() 或 join() 等宽转换之后)就会发生 shuffle。

而一旦 shuffle 出问题,可能会出现巨量磁盘 I/O、冗长的垃圾回收暂停,或某些倾斜任务迟迟无法完成。 

改进 shuffle 的方法包括:

  • 优先使用 reduceByKey() 而非 groupByKey():reduceByKey() 会在本地聚合后再进行 shuffle;groupByKey() 则会把所有数据都发往网络。
  • 聪明地重新分区:使用 .repartition(n) 提升并行度,或用 .coalesce(n) 降低并行度。不要完全依赖 Spark 的默认分区。
  • 明智地使用广播连接:如果一侧数据集足够小,可以广播到所有工作节点。通过 spark.sql.autoBroadcastJoinThreshold 控制大小阈值。
  • 避免 collect():尽量避免把数据拉回 driver,这会严重影响性能。

内存配置指南

调优 Spark 内存颇具门道,但可参考下列清单简化流程:

  • 分配足够内存:为 Spark 集群至少分配 6 GB 内存,并根据具体需求调整。
  • 考虑 Spark 内存占比:默认 60% 是 Spark 的内存比例。如果您的应用高度依赖 DataFrame/Dataset 操作,或需要更多用户内存,可适当提高。 
  • 为每个 executor 选择合适核心数:一般 3-5 个较优。太少会导致资源未充分利用,太多会引发任务争用。
  • 启用动态分配(如受支持):Spark 可根据负载按需扩缩 executors。 
spark.dynamicAllocation.enabled=true
spark.dynamicAllocation.minExecutors=2
spark.dynamicAllocation.maxExecutors=20
  • 调整存储占比:如果需要更多缓存,可增大 spark.memory.storageFraction 值。
  • 监控与剖析内存使用:利用 Spark UI 或 VisualVM 等工具跟踪内存消耗并定位瓶颈。

调整内存配置的收益可能非常可观。我曾仅通过调整内存配置(不改一行代码),就把 30 分钟的作业缩短到 8 分钟。

集群规模估算公式

多数团队在这一点上会犯错:凭感觉而非估算来决定集群大小。 

您可以借助以下公式做得更好: 

  1. 确定分区数量: 
    • 根据数据总量与期望的分区大小计算所需分区数。 
    • 通行建议是每 128 MB 至 256 MB 未压缩数据对应一个分区。
    • 公式:分区数 = 向上取整(数据总量 ÷ 分区大小)。
  2. 计算总核心数: 
    • 核心数应足以并行处理全部分区。
    • 公式:总核心数 = 向上取整(分区数 ÷ 每核心并行分区数)。
  3. 确定每个 executor 的内存: 
    • 基于核心数、分区大小与开销计算每个 executor 所需内存。
    • 公式:每个 executor 内存 = 基础内存 ×(1 + 开销百分比)。
  4. 计算 executor 数量: 
    • 根据总核心数与每个 executor 的核心数确定 executor 数量。
    • 公式:executor 数量 = 向上取整(总核心数 ÷ 每个 executor 核心数)。
  5. 计算总内存: 
    • 基于 executor 数量与每个 executor 内存计算集群总内存。
    • 公式:总内存 = executor 数量 × 每个 executor 内存。

例如: 

  • 输入:500GB 数据,分区大小约 128MB
  • 分区数:约 4,000 个分区
  • 核心数:4,000 分区 / 每核心 4 个分区 = 1,000
  • 每个 executor 内存:假设 8 GB,开销 20%。8 GB * 1.20 = 9.6 GB
  • executor 数量:1,000 核心 / 每个 executor 4 核心 = 250
  • 总内存:250 个 executor * 9.6GB = 2,400 GB

但请记住:这只是估算。可作为起点,随后通过剖析进一步优化。

新兴架构趋势

Spark 已有十年历史,但依然非常“新潮”。得益于云原生平台、GPU 加速与更紧密的机器学习集成,它的演进从未如此迅速。

如果您还在用三年前的方式使用 Spark,很可能在性能与新特性上损失不小。

让我们看看其中一些最新进展。

Photon 引擎(Databricks)

如果您使用 Databricks,大概率已经接触并听说过 Photon。

如果您想了解更多 Databricks,推荐Databricks 入门课程。

Photon 是 Databricks Lakehouse 平台上的新一代引擎,以更低成本提供极速查询性能。它兼容 Spark API,因此无需改动 Spark 代码即可受益。 

它能显著加速您的 SQL 与 PySpark 代码。

Photon 包含以下特性: 

  • 向量化执行:Photon 以列式批处理数据,利用 SIMD(单指令多数据)CPU 指令同时对多个值执行操作。传统 Spark 以行式执行为主,并在内存分配与垃圾回收上严重依赖 JVM。
  • C++ 运行时(无 JVM 开销):没有 Java 垃圾回收这一大作业瓶颈;内存由 C++ 精细管理。
  • 更优的查询优化:Photon 深度集成 Spark 的 Catalyst 优化器,并在执行时加入自身优化(如运行时过滤、自适应代码路径、连接与聚合优化)。 
  • 硬件加速:支持现代硬件(如 NVIDIA GPU、Intel CPU 的 AVX-512 指令集、AWS 的 Graviton(ARM)处理器)。 

无服务器 Spark

无服务器非常棒,因为这意味着您无需管理集群、无需预置资源,且只为 Spark 实际运行的时间付费。 

面向 Spark 的无服务器已在 Databricks Serverless、AWS Glue 与 GCP Dataproc Serverless 等服务中落地。

其优势在于:

  • 自动伸缩:平台会根据作业的实际需求扩缩算力,您无需再“拍脑袋”估算节点数。
  • 成本效益:按用量计费,不再为闲置服务器买单。 
  • 简化运维:无需处理集群搭建、配置或维护,这些都由平台代劳。
  • 高性能:由于配置与环境已为您优化,执行可能更快。

无服务器 Spark 适合交互式分析、临时性作业或不可预测的负载。

但需注意:长时间、稳定运行的流水线,在固定集群上可能更便宜。务必同时衡量成本与延迟。

MLflow 集成

随着行业演进,数据工程与人工智能的界限日益模糊。正如 Azurelib Academy 的 CEO & 创始人 Deepak Goyal 在 DataFramed 播客中所探讨的

数据工程将在即将到来的 AI 转型中发挥至关重要且基础性的作用。

Deepak Goyal, CEO & Founder at Azurelib Academy

如果您在规模化地做机器学习并希望将模型投入生产,单靠 Spark 远远不够。您需要MLOps 原则,例如实验追踪、模型版本管理与可复现性。这正是 MLflow 的用武之地。 

MLflow 现已与 Spark 集成,为您的流水线带来完整的 MLOps 堆栈。

您可以: 

  • 追踪实验:使用 mlflow.log_param() 与 mlflow.log_metric() 记录 Spark ML 作业的参数、指标与制品。
  • 版本化模型:将 pyspark.ml 或 sklearn 训练的模型直接保存到 MLflow 的模型注册表。
  • 服务化模型:使用 MLflow 的模型服务将训练好的模型部署为 REST 端点。

您无需更换工具。继续用 Spark 进行训练、特征工程与评分,同时用 MLflow 处理 MLOps 相关任务。

结语

如果不了解 Spark,它就像一个巨大的黑盒。您写几行 PySpark 代码,点下运行,然后祈祷一切顺利。 

有时这对我很奏效,有时却让我陷入漫长的调试,试图搞清哪里出了问题。 

直到我开始探究幕后,事情才逐渐清晰。但要真正弄明白,也花了我不少时间。

如果让我重新开始,我会重点关注以下几点: 

  • 了解 Spark 如何将您的代码拆分为作业、阶段与任务。
  • 理解内存机制。
  • 留意 shuffle。
  • 从小处着手,在本地模式运行,多动手实践。

这正是我们在本文中所学习的。

如果您想继续进阶,以下是我推荐的一些入门友好型资源:

<p>通过这些课程进一步学习 Spark!</p>

如何为我的 Spark 部署选择合适的集群管理器?

Spark 支持多种集群管理器(YARN、Mesos、Kubernetes 与 standalone)。选择取决于现有基础设施、资源共享需求与运维经验:YARN 与 Hadoop 集群集成度高,Kubernetes 提供容器化的可移植性,而 Mesos 在多租户隔离方面表现出色。

什么是外部 shuffle 服务,它如何改进性能?

外部 shuffle 服务将 shuffle 文件的提供与 executor 生命周期解耦,从而实现动态分配,并减少 executor 被回收时的数据丢失。即便 executor 关闭,它也能保持 shuffle 文件可用,从而加速阶段重试并在高负载下节省磁盘 I/O。

广播连接的内部原理是什么,何时应当使用?

对于广播连接,Spark 会将一个小的查找表发送到每个 executor,以避免完整的数据 shuffle。当连接一侧的大小低于 spark.sql.autoBroadcastJoinThreshold(默认 10 MB)时应使用,因为它能显著减少网络 I/O,并在键分布倾斜时加速连接。

在 Spark 中调优 JVM 垃圾回收的最佳实践是什么?

通过 Spark UI 或 VisualVM 等工具监控 GC 暂停时间,并优先选择 G1GC 收集器以获得更低暂停。为 executor 预留足够的开销内存(spark.executor.memoryOverhead),并调优 -XX:InitiatingHeapOccupancyPercent 以更早触发 GC,避免长时间的“停顿世界”事件。

如何利用 GPU 加速来提升 Spark 作业速度?

使用 NVIDIA RAPIDS Accelerator for Apache Spark,可透明地将 SQL 与 DataFrame 操作卸载到 GPU。它可插入 Spark 的执行引擎,用 GPU 加速算子替换 CPU 算子,在适配工作负载下可实现最高 10× 的处理加速。

Spark 中静态与动态资源分配有何区别?

静态分配在作业全程固定 executor 数量,具备可预测性,但可能导致资源空闲。动态分配则根据待处理任务与工作负载请求或释放 executor,提升共享环境下波动性作业的集群利用率。

在 S3 等云存储上应如何配置 Spark 以获得最佳性能?

启用 S3 传输加速,调优 spark.hadoop.fs.s3a.connection.maximum,并使用一致性视图(S3A v2)来应对最终一致性。在写入前合并小文件,并考虑使用 S3A 提交器以降低列举操作开销、提升写入吞吐。

如何通过 Kerberos 与 TLS 保护 Spark 通信安全?

为 RPC 启用 TLS(spark.ssl.enabled),并配置 SASL/Kerberos(spark.authenticate and spark.kerberos.keytab)以强制双向认证。将凭证存放在安全、HDFS 可访问的 keytab 中,并通过 ACL 设置限制 Spark UI 访问,防止未授权数据暴露。

什么是 Pandas UDF,它何时比常规 UDF 更高效?

Pandas UDF(向量化 UDF)使用 Apache Arrow 在 JVM 与 Python 之间批量交换数据,大幅降低序列化开销。相比逐行 UDF,它们在处理大型列式批次时对复杂数值运算更高效,适用于 PySpark。

相较于 V1,DataSource V2 API 为自定义数据源带来了哪些优势?

DataSource V2 提供更清晰、模块化的接口,原生支持谓词下推、分区裁剪与流式数据源。它能实现更细粒度的读/写控制,并与 Spark 的 Catalyst 优化器更好集成,从而为定制连接器带来更高性能与更易维护性。

Patrick Brus

作者

Patrick Brus

我是一名云工程师,拥有坚实的电气工程、机器学习和编程基础。我的职业生涯始于计算机视觉领域,专注于图像分类,随后转向 MLOps 和 DataOps。我擅长构建 MLOps 平台、支持数据科学家,并交付基于 Kubernetes 的解决方案,以优化机器学习工作流。

主题