python里面的spark为什么是最火的计算引擎

1、Spark简介

        了解PySpark之前首先要介绍Spark。Spark,英文原义为火花或者星火,但这里并非此意,或者说它就没有明确的含义。实际上"名不副实"这件事在大数据生态圈各个组件中是很常见的,例如Hive(蜂巢),从名字中很难理解它为什么会是一个数仓,难道仅仅是因为都可用于存储?

       当然,讨论spark名字的含义并无意义,我们需要知道的是Spark是大数据生态圈中的一个分布式快速计算引擎,这其中包含了三层含义:分布式、快速、计算引擎。分布式意味着它支持多节点并行计算和备份;而快速则是相对Hadoop中的MapReduce计算框架而言,官网号称速度差距是100倍;计算引擎则描述了Spark在大数据生态中定位:计算。

存储和计算是大数据中的两大核心功能。

       大数据框架,一般离不开Java,Spark也不例外。不过Spark并非是用Java来写的,而是用Scala语言。但考虑Scala语言建立在Java基础之上,实际上Scala是可以直接调用Java的包的,所以从这点来讲Spark归根结底还是要依赖Java,自然环境依赖也需要JDK。也正是基于这些原因,Spark的主要开发语言就是Java和Scala。然后随着数据科学的日益火爆,Python和R语言也日益流行起来,所以Spark目前支持这4种语言。当Spark遇到Python就变成了PySpark,这也是我们今天介绍的主角。

Spark目前最新版本是3.0,于今年6月16日正式发布release版。

2、 PySpark安装

      一般而言,进行大数据开发或算法分析需要依赖Linux环境和分布式集群,但PySpark支持local模式,即在本地单机运行。所以,如果为了在个人PC上练习PySpark语法功能或者调试代码时,是完全可以在自己电脑上搭建spark环境的,更重要的windows系统也是可以的!

 

      实际上,安装PySpark非常简单,仅需像安装其他第三方Python包一样执行相应pip命令即可,期间pip会自动检测并补全相应的工具依赖,如py4j,numpy和pandas等。这里py4j实际上是python for java的意思,是Python和java之间互调的接口,所以除了pip命令安装PySpark之外还需配置系统的jdk环境,一般仍然是安装经典的JDK8版本,并检查是否将java配置到系统环境变量。相应的检验方法是在cmd窗口中键入java -version,当命令可以执行并显示正确的版本时,说明系统已完成java环境搭建。这是为PySpark运行提供了基础。

 

 

所以总结一下,安装pyspark环境仅需执行两个步骤:

  • 安装JDK8,并检查系统配备java环境变量

  • Pip命令安装pyspark包

顺利完成以上两个步骤后,在jupyter中执行如下简单代码,检验下PySpark环境是否正确搭建。

from pyspark import SparkContext
sc = SparkContext()
rdd = sc.parallelize([1, 2])
rdd.getNumPartitions()
# 输出4

 

3、 PySpark主要功能介绍

Spark作为分布式计算引擎,主要提供了4大核心组件,它们之间的关系如下图所示,其中GraphX在PySpark中暂不支持。

 

      RDD(Resilient Distributed DataSet,弹性分布式数据集)是Spark中的核心数据结构(Spark core),是完成分布式任务调度的关键,从名字缩写中可以看出其有3大特性:弹性,意味着大小可变、分区数量可变;分布式,表示支持多节点并行处理;数据集,说明这是一个特殊的数据结构。

 

进一步的,Spark中的其他组件依赖于RDD,例如:

  • SQL组件中的核心数据结构是DataFrame,而DataFrame是对rdd的进一步封装。值得一提的是这里的DataFrame实际上和Pandas或者R语言的data.frame其实是很为相近的,语法、功能、接口都有很多共同之处,但实际上这里的DataFrame支持的接口要少的多,一定程度上功能相对受限;

  • Streaming组件中的核心数据结构是Dstream,即离散流(discrete stream),本质就是一个一个的rdd;

  • PySpark中目前存在两个机器学习组件ML和MLlib,前者是推荐的机器学习库,支持的学习算法更多,基于SQL中DataFrame数据结构,而后者则是基于原生的RDD数据结构,包含的学习算法也较少

     十年前我们只有Hadoop,大家首先通过HDFS实现海量数据的共享存储,然后使用MapReduce以批处理的方式处理这些海量数据,这一切看起来似乎十分完美。

     但众口难调啊,有人觉得MapReduce的编程模型太难使用了,为什么不能使用SQL来分析数据呢?我们数据库领域已经有非常成熟的数据仓库模型了,为何不实现一个大数据技术的数据仓库呢?于是Hive类的框架便诞生了,人们开始使用Hive类的框架来构建大数据技术的数据仓库,使用SQL查询数据。

    接着人们又开始诟病MapReduce的执行效率太慢,因为它本质上是面向批处理场景的,难以支撑一些实时性要求很高的场景,我们需要一种能够支撑流计算的架构,于是Storm类的框架诞生了。人们开始使用Storm这类框架处理流计算场景。  接着伴随垃圾邮件分析、商品推荐、金融风控这类应用场景需求的出现,又迫使我们需要在大数据场景下具备机器学习的能力,于是乎Mahout类的框架出现了,人们使用它们来进行大数据下的机器学习。

     随着越来越多来自应用领域的细分需求,人们从最初Hadoop的HDFS和MapReduce开始,一步步地构造出了各种细分领域的技术框架。有专攻处理批处理场景的,有专攻数据仓库场景的,有处理流计算场景的,也有专职机器学习的。

      在我看来这有点像在给Hadoop打补丁,因为Hadoop在设计之初根本没有考虑过这么多的场景,它只是为了支撑离线批处理。但是需求摆在这里,为了实现目标只得另起炉灶通过设计一个全新的系统满足需求。这种现状造成了很多问题。

 

  • 重复工作:不同的系统之间都需要解决一些相同的共性问题,比如分布式执行和容错性。例如MapReduce、SQL查询引擎和机器学习系统都会涉及聚合操作。

  • 组合:不同系统之间的组合使用非常“昂贵”,因为不同系统之间无法有效的功效数。为了组合使用我们需要将数据在不同的系统之间频繁的导出导入,数据用来移动的时间可能都会超过计算的时间。

  • 维护成本:虽然这些系统从每个个体的角度来看都十分优秀,但是它们都是在不同时期由不同的团队设计实现的,其设计思路和实现方式也各不相同。这导致平台在部署运维这些系统的时候十分痛苦,因为它们差异太大了。

  • 学习成本:系统之间巨大的差异性对于开发人员来讲更是如此,这些技术框架拥有不同的逻辑对象、专业术语、API和编程模型,每种框架都需要重新学习一遍才能使用。

      Spark意识到了这个问题,作为一个后起之秀它拥有天然的优势。Spark诞生于2012年,那个时候Hadoop生态已经经过了6个年头的发展,其生态格局已经成型。Spark已经能够看清大数据有哪些细分领域,同时MapReduce、Hive、Storm等开源组件也已经发展多年,Spark也能够了解到它们的长处和不足。

      于是Spark横空出世,成为目前开源社区最为火爆的一款分布式内存计算引擎。Spark使用DAG(有向无环图)模型作为其执行模型,并且主要使用内存计算的方式进行任务计算。

      Spark基于一套统一的数据模型(RDD)和编程模型(Trans-foration /Action)之上,构建出了Spark SQL、Spark Streaming、Spark MLibs等多个分支,其功能涵盖了大数据的多个领域,如图2-14所示。

 

▲图2-14 Spark涵盖的领域

 

Spark通过统一的数据模型和编程模型,构造出了SQL查询、流计算、机器学习和图计算等多个分支库。

       RDD是弹性分布式数据集(Resilient Distributed Datasets)的缩写,它是MapReduce模型的扩展和延伸。Spark之所以能够同时支撑大数据的多个领域,在很大程度上是依靠了RDD的能力。

      虽然批处理、流计算、图计算和机器学习这些计算场景之间初看起来风马牛不相及,但是它们都存在一个共同的需求,那就是在并行计算阶段能够高效的共享数据。

       RDD的设计者们洞穿了这一现象,于是通过高效的数据共享概念和类似MapReduce的操作设计了RDD,使得它能模拟迭代式算法、关系查询、MapReduce和流式处理等多种编程模型。

       同时它也是一个可容错的、可并行的数据结构,可以让用户指定将数据存储到磁盘和内存中,并能控制数据的分区。同时它还提供了一些高效的编程接口操作数据集。

Spark将RDD的操作分为两类:转换(transformation)与行动(action)。

       转换操作是一种惰性操作,它只会定义新的RDD,而不会立即执行。而行动操作则是立即执行计算,它要么返回结果给Driver进程,或是将结果输出到外部存储。常见转换操作如map、flatMap、filter等,常见行动操作如count、collect等。

       当用户对一个RDD执行了行动操作之后,调度器会根据RDD的依赖关系生成一个DAG(有向无环图)图来执行程序。DAG由若干个stage组成,每个stage内都包含多个连续的窄依赖。而各个stage之间则是宽依赖。如图2-15所示,实线方框代表的是RDD。方框内的矩形代表分区,若分区已在内存中保存则用黑色表示。

 

▲图2-15 Spark任务拆分示意

      RDD作为数据结构,本质上是一个只读的分区记录集合。一个RDD可以包含多个分区,每个分区是一个数据片段。

     RDD可以相互依赖。如果父RDD的每个分区最多被一个子RDD的分区使用,则称之为窄依赖;若多个子RDD分区依赖一个父RDD的分区,则称之为宽依赖。不同的操作依据其特性,可能会产生不同的依赖。例如map操作会产生窄依赖,而join操作则产生宽依赖。

     Spark之所以将依赖分为两种,基于两点原因。首先,窄依赖支持在同单个集群上以管道的形式式执,例如在执行了map后,紧接着执行filter。相反,宽依赖需要所有的父RDD数据都可用并通过shuffle动作才可继续执行。

      其次,窄依赖的失败恢复更加高效,因为它只需要重新计算丢失的父分区,并且这些计算可以并行的在不同节点同时进行。与此相反,在宽依赖的继承关系中,单个失败的节点可能导致一个RDD的所有先祖RDD中的一些分区丢失,导致计算的重新执行。如图2-16所示,说明了窄依赖与宽依赖之间的区别。

 

▲图2-16 SparkRDD宽依赖和窄依赖示意

      传统分布式系统的容错方案有据复制和恢复日志两种方案。对于以数据为中心的系统而言,这两种方式都非常昂贵,因为它需要跨集群网络复制大量数据,而网络带宽的速度远远低于内存访问的速度。

     RDD天生是支持容错的。首先,它自身是一个不变的数据集,其次,Spark使用DAG作为其执行模型,所以它能够通过RDD的依赖特性记住一系列操作生成一张DAG图。因此当执行的任务失败时,Spark只需根据DAG图进行重新计算即可实现容错机制。由于无须采用复制的方式支持容错,Spark很好地降低了跨网络的数据传输成本。

     Spark的应用以一组独立进程的形式运行在一个集群之上,由主程序中的SparkContext对象进行协调(也被称为driver程序)。Spark目前支持三种集群运行方式。

具体来说,Spark既可以通过standlone模式独立运行,也可以运行在Mesos或者YARN之上。

       如图2-17所示,一旦SparkContext连接到集群,Spark首先会从集群的节点中获得一些executor进程,这些进程会用来执行我们程序中的计算和存储逻辑,接着它会通过jar包的形式分发我们的程序代码到各个executor进程。最后,SparkContext会分派任务到各executor进程进行执行。

 

▲图2-17 Spark任务进程示意

 

      每个应用都拥有自己的executor进程,这些进程会在整个应用生命周期内持续运行并以多线程的方式执行具体的任务。这种设计的好处是将各个应用之间的资源消耗进行了隔离,每个应用都运行在它们各自的JVM中。但是这也意味着不同应用之间的SparkContext无法共享数据,除非借助扩展的存储媒介。

      Spark对底层集群管理不可知。只要能够获取到executor进行,并且这些进程之间可以通信,它就能比较容易的运行在其他通用集群资源调度框架之上,如Mesos和YARN。

    Spark借助其RDD的出色设计,做到了横跨多个领域的支撑。这意味着我们在一套程序逻辑之中可以集成多种操作。

例如使用SQL查询过滤数据,然后进行机器学习或是通过SQL的方式操作流数据。在提升便利的同时也降低了开发人员的学习曲线,基于Spark,只需要学习一套编程模型即可处理多个领域。

所以将Spark作为平台的一站式计算解决方案是再合适不过了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值