软件工程学习日志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具有五大特性:
- 分区列表:RDD中的数据存在于一个分区列表中,每个分区就是一个数据集片段。
- 计算函数:每个分区都有应用于该分区的计算函数。
- 依赖关系:一个RDD依赖于其他RDD,这是容错机制的基础。
- 分区器:针对键值对RDD,可以指定分区策略(如哈希分区)。
- 数据本地性:优先将计算任务调度到离数据最近的节点。
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生态集成紧密,资源管理能力强

浙公网安备 33010602011771号