软件工程学习日志2025.11.11

今日学习了spark。

大数据领域,Spark已成为不可或缺的快速、通用分布式计算系统,掌握其核心原理是每位数据工程师的必备技能。

一、Spark核心架构概述

Spark采用典型的Master-Slave(主从)架构模型,整个集群由以下几个核心组件构成:

Driver(驱动节点) 是Spark应用的“大脑”,运行应用程序的main函数并创建SparkContext,负责作业的调度和任务的协调。它通过DAGScheduler将作业分解为Stage,再由TaskScheduler将任务分发给Executor执行。

Cluster Manager(集群资源管理器) 负责整个集群的资源分配和调度。Spark支持多种集群管理模式:Standalone(Spark自带)、YARN和Mesos等,这使得Spark可以灵活部署在不同的环境中。

Executor(执行器) 是运行在工作节点(Worker Node)上的进程,负责执行具体的Task任务。每个Executor拥有自己的内存资源,通过多线程方式并行处理任务,Executor中还有一个BlockManager存储模块,能够有效减少IO开销。

Spark应用的执行流程可以概括为:Application -> Job -> Stage -> Task的层次化分解与执行。这种架构使得Spark能够高效地处理分布式计算任务。

二、Spark的核心优势与特点

Spark相较于早期的大数据处理框架(如Hadoop MapReduce)具有显著优势:

运行速度快:Spark拥有DAG执行引擎,支持在内存中对数据进行迭代计算。官方数据显示,从磁盘读取数据时,Spark比Hadoop快10倍以上;从内存读取时,速度可高达100倍。

一站式解决方案:Spark提供了统一的技术栈,支持SQL查询、流处理、机器学习、图计算等多种计算场景,大大降低了学习和开发成本。

容错性高:Spark引进了弹性分布式数据集RDD的抽象,通过血统(Lineage)机制和Checkpoint机制实现高效容错。

多语言支持:Spark支持Java、Scala、Python和R等多种编程语言,为开发者提供了灵活的选择。

三、弹性分布式数据集RDD详解

RDD的基本概念与特性

RDD是Spark中最基本的数据抽象,它代表一个不可变、可分区、元素可并行计算的分布式集合。RDD具有五大特性:

  1. 分区列表:RDD中的数据存在于一个分区列表中,每个分区就是一个数据集片段。
  2. 计算函数:每个分区都有应用于该分区的计算函数。
  3. 依赖关系:一个RDD依赖于其他RDD,这是容错机制的基础。
  4. 分区器:针对键值对RDD,可以指定分区策略(如哈希分区)。
  5. 数据本地性:优先将计算任务调度到离数据最近的节点。

RDD的操作类型

RDD支持两种类型的操作:转换(Transformation) 和动作(Action)。

转换操作是惰性的,它们只是定义新的RDD而不立即执行计算(如map、filter、reduceByKey等)。只有在遇到动作操作(如collect、count、save等)时,Spark才会触发实际的计算过程。

这种惰性执行机制让Spark能够优化整个计算流程,避免不必要的中间结果存储。

四、Spark的容错机制

Spark的容错能力主要建立在RDD的血统(Lineage)机制上。每个RDD都记录了自己是如何从其他RDD转换而来的,即它的“血统”。当某个RDD的分区数据丢失时,Spark可以根据这些信息重新计算该分区,而不需要备份整个数据集。

宽依赖与窄依赖

RDD之间的依赖关系分为两种类型,它们直接影响容错的效率:

• 窄依赖:父RDD的每个分区最多被一个子RDD的分区使用。这种情况下,分区数据丢失时只需重新计算对应的父分区即可,效率较高。

• 宽依赖:父RDD的一个分区可能被多个子RDD的分区使用。这类依赖通常涉及shuffle操作,当数据丢失时需要重新计算多个分区,开销较大。

Stage划分与容错

Spark根据RDD之间的宽依赖关系将作业划分为多个Stage。每个Stage包含一系列具有窄依赖关系的转换操作,Stage之间则是宽依赖关系。这种划分不仅优化了任务执行流程,也降低了容错的成本。

Checkpoint机制

对于血统链过长的RDD,Spark提供了检查点(Checkpoint)机制,将RDD数据持久化到可靠存储系统(如HDFS)中。这可以切断漫长的血统链,减少故障恢复时的计算量。

五、Spark性能优化策略

数据分区与并行化

合理设置分区数是优化Spark性能的关键。在shuffle密集型操作(如join)前使用repartition()增强并行性,在写入前使用coalesce()减少分区数,可以防止小文件问题。

在join或聚合前重新分区以增强并行性

df_repartitioned = df.repartition(200, "id")

在写入前合并以减少输出文件

aggregated_coalesced = aggregated.coalesce(10)

缓存与持久化策略

对于需要多次使用的RDD或DataFrame,合理的缓存策略可以避免重复计算:

内存缓存(默认)

df.cache()

使用自定义存储级别(如内存和磁盘)

df.persist(StorageLevel.MEMORY_AND_DISK)

选择合适的持久化级别(如MEMORY_ONLY、MEMORY_AND_DISK等)对性能有重要影响。

数据倾斜处理

数据倾斜是Spark作业的常见性能瓶颈,可以通过“加盐”技术解决:

加盐处理解决数据倾斜

from pyspark.sql.functions import rand
df = df.withColumn("salt", (rand() * 10).cast("int"))
result = df.groupBy("key", "salt").agg(...)

广播变量与谓词下推

使用广播变量处理小表join大表的情况,可以避免shuffle操作:
from pyspark.sql.functions import broadcast
result = large_df.join(broadcast(small_df), "key")

谓词下推技术则能在数据读取阶段就过滤掉不相关的数据,减少IO开销。

六、核心概念辨析

宽依赖 vs 窄依赖

• 窄依赖:父RDD的每个分区最多被一个子RDD的分区使用(如map、filter、union操作)

• 宽依赖:父RDD的一个分区可能被多个子RDD的分区使用(如groupByKey、reduceByKey操作)

理解这一区别对优化Spark作业性能至关重要。

转换操作 vs 动作操作

• 转换操作:懒执行,只定义计算逻辑而不立即执行(如map、filter)

• 动作操作:触发实际计算,返回结果给Driver或写入外部存储(如collect、count)

不同部署模式的比较

Spark支持多种部署模式,各有适用场景:
• 本地模式:适合开发和调试

• Standalone模式:Spark自带的集群模式,简单易用

• YARN模式:与Hadoop生态集成紧密,资源管理能力强

posted @ 2025-11-11 20:17  仙人兵马俑  阅读(13)  评论(0)    收藏  举报