spark原理介绍和实践

Spark简单介绍

Spark是一个基于内存的快速、通用、可扩展的大数据分析计算引擎,由Scala开发。Java,scala,python,R和SQL都可以访问SparkAPI。

背景:
Matei Zaharia开发,作为加州大学伯克利分校博士论文的一部分,spark第一个版本于2012年发布。2013年Spark代码库被捐赠给Apacha Software Foundation,并成为其旗舰项目。

功能:
允许用户读取,转换,聚合数据,可以轻松训练和部署复杂的统计模型,或者打包成为要部署在集群上的库。或通过notebook交互式执行快速的分析。

包含:SparkCore,SparkSQL,SparkStreaming,Spark MLib,Spark GraphX
在这里插入图片描述
在这里插入图片描述
spark原理相关的内容可参考spark原理介绍和scala打包介绍

用于大数据处理的集群计算框架。与Hadoop紧密集成,可以在yarn上运行,并支持Hadoop文件格式及其hdfs。
spark最突出的表现是将作业间产生的大规模工作数据集存储在内存中。

优点:擅长迭代算法和交互式分析,拥有丰富的API集。

spark运行架构

在这里插入图片描述

核心组件:
  • driver
    负责托管sparkcontext并为作业调度任务
    在这里插入图片描述

  • executor
    专属于应用,在应用运行期间运行并执行该应用的任务
    在这里插入图片描述
    在这里插入图片描述

spark自身资源调度–Master 和 Worker

Master 和 Worker,Master 是一个进程,主要负责资源的调度和分配,并进行集群的监控等职责,类似于 Yarn 环境中的 RM, 而Worker 也是进程,一个 Worker 运行在集群中的一台服务器上,由 Master 分配资源对数据进行并行的处理和计算,类似于 Yarn 环境中 NM。

ApplicationMaster

Hadoop 用户向 YARN 集群提交应用程序时,提交程序中应该包含ApplicationMaster,用于向资源调度器申请执行任务的资源容器 Container,运行用户自己的程序任务 job,监控整个任务的执行,跟踪整个任务的状态,处理任务失败等异常情况。简单点就是,ResourceManager(资源)和 Driver(计算)之间的解耦合靠的就是ApplicationMaster。

提交流程

spark:
1.作业提交
2.DAG构建
3.任务调度
4.任务执行

基于yarn(Spark 应用程序提交到 Yarn 环境中执行的时候,一般会有两种部署执行的方式:Client和 Cluster。主要区别在于:Driver 程序的运行节点位置。)在这里插入图片描述

Spark核心编程

Spark 计算框架为了能够进行高并发和高吞吐的数据处理,封装了三大数据结构,用于处理不同的应用场景。三大数据结构分别是:
➢ RDD : 弹性分布式数据集
➢ 累加器:分布式共享只写变量
➢ 广播变量:分布式共享只读变量

1.RDD
1.1设计背景

许多迭代式算法(比如机器学习、图算法等)和交互式数据挖掘工具,共同之处是,不同计算阶段之间会重用中间结果

目前的MapReduce框架都是把中间结果写入到稳定存储(比如磁盘)中,带来了大量的数据复制、磁盘IO和序列化开销提供了一个抽象的数据架构,不必担心底层数据的分布式特性,只需将具体的应用逻辑表达为一系列转换处理,不同RDD之间的转换操作形成依赖关系,可以实现管道化,避免中间数据存储

1.2概念

Spark 中最基本的数据处理模型。代码中是一个抽象类,它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。

• 一个RDD就是一个分布式对象集合,本质上是一个只读的分区记录集合,每个RDD可分成多个分区,每个分区就是一个数据集片段,并且一个RDD的不同分区可以被保存到集群中不同的节点上,从而可以在集群中的不同节点上进行并行计算

• RDD提供了一种高度受限的共享内存模型,即RDD是只读的记录分区的集合,不能直接修改,只能基于稳定的物理存储中的数据集创建RDD,或者通过在其他RDD上执行确定的转换操作(如map、join和group by)而创建得到新的RDD

•RDD提供了一组丰富的操作以支持常见的数据运算,分为“动作”(Action)和“转换”(Transformation)两种类型

•RDD提供的转换接口都非常简单,都是类似map、filter、groupBy、join等粗粒度的数据转换操作,而不是针对某个数据项的细粒度修改(不适合网页爬虫)

•表面上RDD的功能很受限、不够强大,实际上RDD已经被实践证明可以高效地表达许多框架的编程模型(比如MapReduce、SQL、Pregel)

•Spark用Scala语言实现了RDD的API,程序员可以通过调用API实现对RDD的各种操作

1.3RDD运行原理

在这里插入图片描述

1.4RDD特性

在这里插入图片描述

1.5RDD依赖关系(Shuffle操作、窄依赖和宽依赖)

在这里插入图片描述
在这里插入图片描述

1.6阶段划分

在这里插入图片描述
Spark根据DAG图中的RDD依赖关系,把一个作业分成多个阶段。对于宽依赖和窄依赖而言,窄依赖对于作业的优化很有利。只有窄依赖可以实现流水线优化,宽依赖包含Shuffle过程,无法实现流水线方式处理。Spark通过分析各个RDD的依赖关系生成了DAG,再通过分析各个RDD中的分区之间的依赖关系来决定如何划分Stage,具体划分方法是:
•在DAG中进行反向解析,遇到宽依赖就断开
•遇到窄依赖就把当前的RDD加入到Stage中 •将窄依赖尽量划分在同一个Stage中,可以实现流水线计算

1.7RDD运行过程总结

在这里插入图片描述

1.8基础编程
1.8.1创建RDD

两种方式:读取外部数据集,在驱动程序中对一个集合进行并行化

  • 从外部存储(文件)创建 RDD
    由外部存储系统的数据集创建 RDD 包括:本地的文件系统,所有 Hadoop 支持的数据集,比如 HDFS、HBase 等。
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("spark")
val sparkContext = new SparkContext(sparkConf)
val fileRDD: RDD[String] = sparkContext.textFile("input")
fileRDD.collect().foreach(println)
sparkContext.stop()
  • 从集合(内存)中创建 RDD
    Spark 主要提供了两个方法:parallelize 和 makeRDD(从底层代码实现来讲,makeRDD 方法其实就是 parallelize 方法)
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("spark")
val sparkContext = new SparkContext(sparkConf)
val rdd1 = sparkContext.parallelize(
 List(1,2,3,4)
)
val rdd2 = sparkContext.makeRDD(
 List(1,2,3,4)
)
rdd1.collect().foreach(println)
rdd2.collect().foreach(println)
sparkContext.stop()
  • 从其他 RDD 创建
  • 直接创建 RDD(new)

2.累加器

累加器用来把 Executor 端变量信息聚合到 Driver 端。在 Driver 程序中定义的变量,在Executor 端的每个 Task 都会得到这个变量的一份新的副本,每个 task 更新这些副本的值后,传回 Driver 端进行 merge。

3.广播变量

广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个 Spark 操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,广播变量用起来都很顺手。在多个并行操作中使用同一个变量,但是 Spark 会为每个任务分别发送

实践

下载spark
集群启动spark-shell --master local[2]
单机启动 spark-shell

linux scala实践相关

sbt设置

sbt是一款Spark用来对scala编写程序进行打包的工具,Spark 中没有自带 sbt,
curl https://bintray.com/sbt/rpm/rpm > bintray-sbt-rpm.repo
mv bintray-sbt-rpm.repo /etc/yum.repos.d/
yum install sbt
检验 sbt 是否可用
sbt sbt-version

#!/bin/bash 
SBT_OPTS="-Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M" 
java $SBT_OPTS -jar `dirname $0`/sbt-launch.jar "$@"

在./sparkapp 中新建文件 simple.sbt(vim ./sparkapp/simple.sbt),添
加内容如下,声明该独立应用程序的信息以及与 Spark 的依赖关系:
name := “Simple Project”
version := “1.0”
scalaVersion := “2.12.10”
libraryDependencies += “org.apache.spark” %% “spark-core” % “3.0.0”

sbt编译打包
在这里插入图片描述

在这里插入图片描述

编译打包

sbt打包:/usr/bin/sbt package
在这里插入图片描述
生成的 jar 包的位置为 /usr/local/spark/sparkapp/simple-project_2.12-1.0.jar
创建sparkapp2,文件与sparkapp内容一致,并新建pom.xml

<project>
 <groupId>cn.edu.xmu</groupId>
 <artifactId>simple-project</artifactId>
 <modelVersion>4.0.0</modelVersion>
 <name>Simple Project</name>
 <packaging>jar</packaging>
 <version>1.0</version>
 <repositories>
 <repository>
 <id>jboss</id>
 <name>JBoss Repository</name>
 <url>http://repository.jboss.com/maven2/</url>
 </repository>
 </repositories>
 <dependencies>
 <dependency> <!-- Spark dependency -->
 <groupId>org.apache.spark</groupId>
 <artifactId>spark-core_2.11</artifactId>
 <version>2.1.0</version>
 </dependency>
 </dependencies>
 <build>
 <sourceDirectory>src/main/scala</sourceDirectory>
 <plugins>
 <plugin>
 <groupId>org.scala-tools</groupId>
 <artifactId>maven-scala-plugin</artifactId>
 <executions>
 <execution>
 <goals>
 <goal>compile</goal>
 </goals>
 </execution>
 </executions>
 <configuration>
 <scalaVersion>2.11.8</scalaVersion>
 <args>
 <arg>-target:jvm-1.5</arg>
 </args>
 </configuration>
</plugin>
</plugins>
</build>
</project>

mvn编译打包 /usr/bin/mvn package
生成的应用程序JAR包的位置为“sparkapp2/target/simple-project-1.0.jar”。

提交应用
/usr/local/spark/spark-3.0.2-bin-without-hadoop/bin/spark-submit --class "SimpleApp" /usr/local/spark/sparkapp/target/scala-2.12/simple-project_2.12-1.0.jar

可以通过spark-submit提交应用程序,该命令的格式如下:

./bin/spark-submit 
 --class <main-class> //需要运行的程序的主类,应用程序的入口点
 --master <master-url> //Master URL,下面会有具体解释
 --deploy-mode <deploy-mode> //部署模式
 ... # other options //其他参数
 <application-jar> //应用程序JAR包
 [application-arguments] //传递给主类的主方法的参数

Spark的运行模式取决于传递给SparkContext的Master URL的值。
Master URL可以是以下任一种形式:

  • local 使用一个Worker线程本地化运行SPARK(完全不并行)
  • local[*] 使用逻辑CPU个数数量的线程来本地化运行Spark
  • local[K] 使用K个Worker线程本地化运行Spark(理想情况下,K应该根
    据运行机器的CPU核数设定)
  • spark://HOST:PORT 连接到指定的Spark standalone master。默认端
    口是7077.
  • yarn-client 以客户端模式连接YARN集群。集群的位置可以在
    HADOOP_CONF_DIR 环境变量中找到。
  • yarn-cluster 以集群模式连接YARN集群。集群的位置可以在
    HADOOP_CONF_DIR 环境变量中找到。
  • mesos://HOST:PORT 连接到指定的Mesos集群。默认接口是5050。
    (Spark 主要是计算框架,而不是资源调度框架,所以本身提供的资源调度并不是它的强项)
    提交应用
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \
./examples/jars/spark-examples_2.12-3.0.0.jar \
10

例子:

import org.apache.spark.SparkContent._
import org.apache.spark.{SparkConf, SparkContent}
Object MaxTemperature {
def main(args:Array[Strings]){
	val conf = new SparkConf().setAppName('max temperature')
	val sc = new SparkConf(conf)

	sc.textFile(args(0))
	.map(_.split('\t'))
	.filter(rec => (rec(1) != '9999' &&rec(2).matches('[01459]')
	.map(rec => (rec(0).toInt, rec(1).toInt))
	.reduceByKey((a,b) => Math.max(a,b))
	.saveAsTextFile('output')
	}

}

执行:
spark-submit --class 类名 --master指定作业应该在哪运行

spark-submit --class MaxTemperature --master local\
spark-examples.jar input/sample.txt output
spark-submit --class MaxTemperature --master local\
***/***/MaxTemperature.py input/sample.txt output

windows scala相关

上手

1.配置环境,scala,maven
创建test.scala

object Test {

    def main(args: Array[String]): Unit = {

        println("Hello Spark")

    }
}

在这里插入图片描述

实战-word count

思路:
在这里插入图片描述
windows:
hadoop:
安装和配置参考:https://www.cnblogs.com/wuxun1997/p/6847950.htmll
成功
在这里插入图片描述

spark:下载安装包:https://www.apache.org/dyn/closer.lua/spark/spark-3.1.1/spark-3.1.1-bin-hadoop2.7.tgz,解压安装包,配置环境变量
成功:

实现:
1.建立连接
2.执行业务操作
3.关闭连接
报错:可参考window failed to locate the winutils binary in the hadoop binary path 。。。
scala代码如下:


object Spark01_WordCount {

    def main(args: Array[String]): Unit = {

        // Application
        // Spark框架
        // TODO 建立和Spark框架的连接
        // JDBC : Connection
        //val sparConf = new SparkConf().setMaster("local").setAppName("WordCount")
        val sparConf = new SparkConf().setMaster("local").setAppName("WordCount")
        val sc = new SparkContext(sparConf)

        // TODO 执行业务操作

        // 1. 读取文件,获取一行一行的数据
        //    hello world
        val lines: RDD[String] = sc.textFile("datas")

        // 2. 将一行数据进行拆分,形成一个一个的单词(分词)
        //    扁平化:将整体拆分成个体的操作
        //   "hello world" => hello, world, hello, world
        val words: RDD[String] = lines.flatMap(_.split(" "))

        // 3. 将数据根据单词进行分组,便于统计
        //    (hello, hello, hello), (world, world)
        val wordGroup: RDD[(String, Iterable[String])] = words.groupBy(word=>word)

        // 4. 对分组后的数据进行转换
        //    (hello, hello, hello), (world, world)
        //    (hello, 3), (world, 2)
        val wordToCount = wordGroup.map {
            case ( word, list ) => {
                (word, list.size)
            }
        }

        // 5. 将转换结果采集到控制台打印出来
        val array: Array[(String, Int)] = wordToCount.collect()
        array.foreach(println)

        // TODO 关闭连接
        sc.stop()

    }
}

结果:
在这里插入图片描述
进阶
在这里插入图片描述

 def main(args: Array[String]): Unit = {

        // Application
        // Spark框架
        // TODO 建立和Spark框架的连接
        // JDBC : Connection
        val sparConf = new SparkConf().setMaster("local").setAppName("WordCount")
        val sc = new SparkContext(sparConf)

        // TODO 执行业务操作

        // 1. 读取文件,获取一行一行的数据
        //    hello world
        val lines: RDD[String] = sc.textFile("datas")

        // 2. 将一行数据进行拆分,形成一个一个的单词(分词)
        //    扁平化:将整体拆分成个体的操作
        //   "hello world" => hello, world, hello, world
        val words: RDD[String] = lines.flatMap(_.split(" "))

        // 3. 将单词进行结构的转换,方便统计
        // word => (word, 1)
        val wordToOne = words.map(word=>(word,1))

        // 4. 将转换后的数据进行分组聚合
        // 相同key的value进行聚合操作
        // (word, 1) => (word, sum)
        val wordToSum: RDD[(String, Int)] = wordToOne.reduceByKey(_+_)

        // 5. 将转换结果采集到控制台打印出来
        val array: Array[(String, Int)] = wordToSum.collect()
        array.foreach(println)

        // TODO 关闭连接
        sc.stop()

    }

其他一些API

dataframe

dataframe像RDD一样,是分布在集群的节点中不变的数据集合,与RDD不同的是,在DataFrame中,数据是以命名列的方式组织的。
目的在使大型数据集处理更容易,允许开发人员对数据结构进行形式化,允许更高级的抽象。主要要点使,Spark引擎一开始就构建了一个逻辑执行计划,而且执行生成的代码使基于成本优化程序确定的物理计划。与Java,Scala相比,python中的RDD非常慢,而DataFrame的引入则使性能在各种语言都保持稳定。

dataset

允许用户轻松表达域对象的转换,同事还提供了具有强大性能和优点的SparkSQL引擎。

Catalyst优化器

Spark SQL支持SQL查询和DataFrame API。Spark SQL的核心是Catalyst优化器。优化器是基于函数式编程结构,并且意在实现两个目的:简化向Spark SQL的添加新的优化技术和特性的条件,并允许外部开发人员扩展优化器
在这里插入图片描述
参考:
Spark编程基础课件
尚硅谷Spark教程(Spark3.0重磅发布)代码和课件
pyspark实战指南

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值