【大数据】MapReduce的“内存增强版”——Spark
【大数据】MapReduce的“内存增强版”——Spark
- 文章脉络
- Spark架构
- Spark-core
- SparkConf 和 SparkContext
- RDD
- Spark集群
- Spark-sql
在大数据时代,数据处理和分析成为企业竞争的重要手段。Hadoop作为大数据处理的基石,其核心组件MapReduce在众多场景中发挥了巨大作用。但是随着业务数据变多业务变复杂,MapReduce在处理速度、迭代计算等方面逐渐暴露出局限性。
为此,Spark应运而生,被誉为MapReduce的“内存增强版”。Spark比较核心的几个组件是core、sql、streaming,其中streaming使用不多,因此本文着重介绍Spark-core和Spark-sql。
文章脉络
Spark是一个基于内存计算的大数据计算框架,由加州大学伯克利分校的AMPLab实验室开发。它继承了Hadoop的分布式计算思想,并在MapReduce的基础上进行了优化和改进。
Spark有以下核心优势:
1、高速计算:Spark将中间结果存储在内存中,大大减少了磁盘IO操作,提高了计算速度。
2、易用性:Spark提供了丰富的API,支持多种编程语言,如Java、Scala、Python等,简化了编程模型。
3、通用性:Spark整合了多种大数据处理框架,如SQL、Streaming、MLlib(机器学习)等,实现了多场景的一站式解决方案。
【注意】Streaming、MLlib在我的日常工作中并不会用到。流式计算一般用Flink(真·流式计算)来做,而不用Streaming(假·流式计算);机器学习或者深度学习则是有Python这边各种各样的库(sklearn、tf、torch)可以做。
4、兼容性:Spark可以与Hadoop生态系统无缝集成,充分利用Hadoop的资源管理和存储优势。
Q:为什么Spark比MapReduce快?
A:MapReduce在处理数据时,需要将中间结果写入磁盘,导致频繁的磁盘IO操作,从而影响整体执行速度。Spark使用了内存计算,可以在处理过程中将数据尽可能多地保存在内存中,这大大减少了磁盘I/O操作,而磁盘I/O是MapReduce性能的一个主要瓶颈。
Q:既然基于内存计算更快,那为什么MapReduce不基于内存做?
A:MapReduce最初被开发的时候(2004年左右),内存的价格相对较高,容量也远不如今天,设计一个基于磁盘的系统更加经济实用。并且在MR设计之初,人们对磁盘I/O和内存性能的权衡有不同的理解。尽管磁盘I/O较慢,但通过批处理和顺序读写操作,MR能够高效地利用磁盘带宽。
Spark架构
图2清晰地展示了Spark与许多大数据产品之间的关系。
【注意】Spark并不仅作为MapReduce的平替而使用,在资源调度环节可以不采用YARN,在存储上也可以不采用HDFS,它其实可以把Hadoop这一套给替换掉。
在API支持上,Spark像MapReduce一样支持了非常多的语言。
在资源调度上,Spark不仅可以使用YARN,可以使用Mesos以及自身的独立模式(Standalone Mode)。这三种资源管理器各有特点,可以根据实际应用场景和需求进行选择:
YARN(Yet Another Resource Negotiator):是Hadoop生态系统中的资源管理器,Spark on YARN模式下,Spark应用程序可以运行在YARN集群上,与其他Hadoop应用程序共享资源。
Mesos:是一个通用的集群资源管理器,它可以将不同类型的任务(如Spark、Hadoop、Marathon等)运行在同一个集群上,实现资源的细粒度管理和分配。
独立模式(Standalone Mode):Spark自带的资源管理器,它简化了Spark集群的部署和管理,适用于不需要与其他大数据框架共享资源的小型或独立Spark集群。
在存储环节,Spark除了支持HDFS,还支持很多种存储系统,比如Amazon S3、HBase甚至关系型数据库。
在SQL层面,Spark的支持性也超高,不但支持标准的SQL语法,还支持多种数据源(HDFS、Hive表、JSON、Parquet、ORC、JDBC等),而且还兼容Hive。
Spark-core
SparkConf 和 SparkContext
在Apache Spark中,SparkConf 和 SparkContext 是创建和配置Spark应用程序的两个核心组件。
SparkConf 是一个配置Spark应用程序的类。它允许用户设置各种Spark参数,这些参数可以控制应用程序的运行时行为。
【注意】SparkConf可以设置应用名称、设置运行模式等等。
SparkContext是Spark的入口点,负责与Spark集群通信,创建RDD,以及向集群提交作业。
【注意】SparkContext可以初始化Spark应用程序的运行环境、创建和操作RDD、提交作业以执行计算、提供访问集群状态的方法。
这两个类,基本相当于Spring里面的配置类、上下文的感觉,没太多学习成本。
RDD
Spark采用弹性分布式数据集(RDD)作为基本计算单元。RDD是一种分布式的、容错的、并行的数据结构,可以将数据存储在内存或磁盘中。
【注意】真正写代码的时候,并不能感知到“分布式”、“弹性”这些概念。只能接触到RDD这个类,把数据放到RDD类里面,它就是弹性分布式数据集了~
RDD有两类重要的方法,称为:
1、转换操作(Transformations)
2、行动操作(Actions)
【注意】转换操作(Transformations)是懒加载的,也就是说,如果你只写了转换操作的代码,即使运行代码也并不会真正执行,必须有行动操作才可以触发先前的转换操作。有点像TensorFlow里面预先定义计算图的感觉。
- 转换操作(Transformations):
- map(func)
:对每个元素应用一个函数。
- filter(func)
:返回满足函数条件的元素。
- flatMap(func)
:将每个元素映射到0个或多个元素,并扁平化结果。
- reduceByKey(func, [numPartitions])
:在键值对的RDD上,按键进行聚合。
- 行动操作(Actions):
- count()
:返回RDD中的元素数量。
- collect()
:将RDD的所有元素以数组的形式返回驱动程序。
- saveAsTextFile(path)
:将RDD的内容保存到文本文件中。
- foreach(func)
:对RDD中的每个元素应用一个函数。
【注意】目前我只在Java工程里面写过Spark,或者写SQL来执行Spark任务。以Java举例,假设你写了filter筛选表里大于0的数据,然后print,直接运行输出为空。必须在后面跟上行动操作,比如count,才会真正执行。
Spark集群
如图3,Apache Spark集群由多个组件组成,每个组件负责不同的功能。
Spark Driver
驱动程序是Spark应用程序的入口,负责将用户编写的应用程序转换成实际的作业执行过程。驱动会在Spark应用程序中创建SparkContext,将应用程序分解成多个任务,并将这些任务分配给集群中的执行器(Executors)。
Cluster Manager
集群管理器负责为Spark应用程序分配资源。
Executor
执行器是运行在工作节点上的进程,负责运行任务、保存数据以及向驱动程序汇报任务的进度。每个执行器都有一定数量的核心,可以并行执行多个任务。执行器还负责存储计算过程中产生的数据,以减少对磁盘的读写操作。
Worker Node
工作节点是集群中的物理或虚拟机器,每个工作节点都会被分配一定数量的执行器,执行器负责运行任务并存储数据。
DAG Scheduler
DAG调度器负责将Spark应用程序中的高层RDD转换操作转换成物理执行计划。将RDD的依赖关系转换成一个有向无环图(DAG),并将DAG划分为多个阶段(stages)。
Spark-sql
Spark SQL除了支持标准SQL、兼容Hive之外,其在API层面还抽象出了一个DataFrame类。
在Spark SQL中,DataFrame是一个分布式数据集合,它被组织成命名列的形式,类似于关系数据库中的表或Python的pandas DataFrame。DataFrame API提供了丰富的数据操作功能,而且支持Scala、Java、Python和R语言。
也就是说,DataFrame底层是由RDD实现的,但它提供了更丰富的优化和抽象。DataFrame的API比RDD更高级,因此在大多数情况下,DataFrame的性能会更好,且代码更简洁。
【注意】起码在编码层面,写RDD还是没DF优雅的。
Q:Pandas的DF与Spark的DF之间有什么区别和联系?
A:对于大规模数据集,Spark DataFrame可以利用集群的计算资源进行分布式计算,性能通常优于pandas。对于小型到中型数据集,pandas DataFrame的性能通常很好,因为它是在单个机器上运行的,没有网络通信的开销。
Spark和pandas DataFrame可以相互转换,可以在Spark中处理大规模数据集,然后在需要时将数据子集转换为pandas DataFrame进行更细致的分析。
【注意】总结:一个是分布式场景下的数据集合,一个是单机情况下的数据集合,但是它们可以互转,API也很相似。