大数据笔记--Spark(第一篇)

目录

一、Spark介绍

1、概述

2、来源

二、Spark的生态系统模块

三、Spark的使用模式

1、Spark单机模式安装

2、Spark集群模式安装

四、RDD介绍

1、概述

2、创建RDD两种方式

3、分区概念

五、RDD的操作

1、Transformation变化

2、Action执行

3、Controller控制


一、Spark介绍

大数据笔记--Spark(第一篇)_第1张图片

1、概述

Spark是UC Berkeley AMP lab (加州大学伯克利分校的AMP实验室)所开源的,后贡献给Apache。是一种快速、通用、可扩展的大数据分析引擎。它是不断壮大的大数据分析解决方案家族中备受关注的明星成员,为分布式数据集的处理提供了一个有效框架,并以高效的方式处理分布式数据集。Spark集批处理、实时流处理、交互式查询、机器学习与图计算于一体,避免了多种运算场景下需要部署不同集群带来的资源浪费。目前,Spark社区也成为大数据领域和Apache软件基金会最活跃的项目之一,其活跃度甚至远超曾经只能望其项背的Hadoop。

Spark是一种分布式的,快速的,通用的,可靠的,免费的计算框架。

目前市面上比较常见和流行的计算框架:

①、Hadoop MapReduce->离线批处理

②、Spark->离线批处理+实时流处理

③、Storm->实时流处理

④、Flink->实时流处理

2、来源

大数据笔记--Spark(第一篇)_第2张图片

从上图我们观察,MapReduce在执行任务的时候,底层会发生Shuffle过程,则会产生大量和多次的磁盘I/O,拉低性能。并且在Shuffle过程会针对每个分区内的数据做排序,耗费大量的CPU,拉低性能。此外,在做一个迭代性质算法的场景,比如梯度下降法,逻辑回归等的时候,需要重复用到某些中间步结果集。由于不能做到中间结果集的复用,会带来大量的重新计算代价。

Spark团队吸取了以上MapReduce的一些经验教训,做出了相关优化,比如尽量减少shuffer过程产生,减少不必要的排序以及支持缓存机制,达到中间结果集的复用

二、Spark的生态系统模块

大数据笔记--Spark(第一篇)_第3张图片

 上图是Spark的整个生态系统。可以看出Spark涵盖了大数据处理的各种应用场景:

        1、离线批处理

        2、交互式查询和数仓

        3、实时流处理

        4、算法建模和数据挖掘

即Spark可以一站式处理大数据的所有应用场景,避免部署多种不同集群带来的麻烦。

三、Spark的使用模式

常见的模式有三种:

Local 本地单机模式:一般用于测试或练习

Standalone Spark集群模式:Spark集群的资源管理由Spark自己的Master来管理的

On Yarn Saprk集群模式:Spark集群的资源管理由Yarn的ResourceManager来管理的

1、Spark单机模式安装

①、步骤

Ⅰ、安装和配置好JDK

Ⅱ、上传和解压Spark安装包        spark-2.0.1-bin-hadoop2.7.tgz

tar -xvf spark-2.0.1-bin-hadoop2.7.tgz

Ⅲ、进入Spark安装目录下的conf目录

复制spark-env.sh.template 文件为 spark-env.sh

在其中修改,增加下面内容:

SPARK_LOCAL_IP=服务器IP地址

②、启动

在bin目录下执行: sh spark-shell --master=local

启动后发现打印消息

大数据笔记--Spark(第一篇)_第4张图片

2、Spark集群模式安装

①、步骤

1)上传解压spark安装包

2)进入spark安装目录的conf目录

3)配置spark-env.sh文件

#本机ip地址
SPARK_LOCAL_IP=hadoop01
#spark的shuffle中间过程会产生一些临时文件,此项指定的是其存放目录,不配置默认是在 /tmp目录下
SPARK_LOCAL_DIRS=SPARK_LOCAL_DIRS=/home/software/spark-2.0.1-bin-hadoop2.7/tmp
export JAVA_HOME=/home/software/jdk1.8.0_131

4)在conf目录下,编辑slaves文件

 mv slaves.template slaves 重命名一下

大数据笔记--Spark(第一篇)_第5张图片

hadoop01
hadoop02
hadoop03

5)配置完后,将spark目录发送至其他节点,并更改对应的  SPARK_LOCAL_IP 配置 

scp -r spark-2.0.1-bin-hadoop2.7 hadoop02:/home/software/
scp -r spark-2.0.1-bin-hadoop2.7 hadoop03:/home/software/

6)进入hadoop02与hadoop03的spark-env.sh修改

②、启动

1)如果你想让 01 虚拟机变为master节点,则进入01 的spark安装目录的sbin目录

执行: sh start-all.sh

2)通过jps查看各机器进程,

01:Master +Worker

02:Worker

03:Worker

3)通过浏览器访问管理界面

hadoop01:8080

4)通过spark shell 连接spark集群

进入spark的bin目录

执行:sh  spark-shell.sh --master spark://hadoop01:7077

6)在集群中读取文件:

sc.textFile("/root/work/words.txt")

默认读取本机数据 这种方式需要在集群的每台机器上的对应位置上都一份该文件 浪费磁盘

7)所以应该通过hdfs存储数据

sc.textFile("hdfs://hadoop01:9000/mydata/words.txt");

8)本地打jar包在spark的bin目录下运行指令:

sh spark-submit --class cn.yang.wordcount.Driver wordcount.jar

注:可以在spark-env.sh 中配置选项 HADOOP_CONF_DIR 配置为hadoop的etc/hadoop的地址 使默认访问的是hdfs的路径

注:如果修改默认地址是hdfs地址 则如果想要访问文件系统中的文件 需要指明协议为file 例如 sc.text("file:///xxx/xx")

四、RDD介绍

1、概述

RDD弹性分布式数据集,它是Spark最核心的数据结构,特点是可以并行操作,并且是容错的。我们刚接触RDD的话,可以把它看做是一个集合类型(类似于Array或List),用于存储数据和操作数据。

RDD和普通集合的区别:

①、RDD有分区机制,可以分布式,并行的处理同一个RDD数据集,从而极大提高处理效率。分区数量由程序员自己定

②、RDD有容错机制。即数据丢失后,可以进行恢复。

大数据笔记--Spark(第一篇)_第6张图片

2、创建RDD两种方式

①、执行Transform操作(变换操作),将一个集合(Array或List)转变成为一个RDD

转变为RDD:val r1=sc.parallelize(List(1,2,3,4),2)

查看分区数量:r1.partitions.size

查看分区数据:r1.glom.collect

查看RDD整体数据:r1.collect   收集rdd中的数据组成Array返回,此方法将会把分布式存储的rdd中的数据集中到一台机器中组建Array。

在生产环境下一定要慎用这个方法,容易内存溢出。

②、读取外部存储系统的数据集,如HDFS,HBase,或任何与Hadoop有关的数据源。读取外部存储文件系统的文件,把文件读取成为一个RDD

读取Linux本地文件:val r4=sc.textFile("file:///home/1.txt",2)

读取HDFS文件:val r5=sc.textFile("hdfs://hadoop01:9000/1.txt",2)

3、分区概念

大数据笔记--Spark(第一篇)_第7张图片

在上图中, 一个RDD有item1~item25个数据,共5个分区,分别在3台机器上进行处理。、

此外,spark并没有原生的提供rdd的分区查看工具 我们可以自己来写一个

import org.apache.spark.rdd.RDD
import scala.reflect.ClassTag
object su {
  def debug[T: ClassTag](rdd: RDD[T]) = {
    rdd.mapPartitionsWithIndex((i: Int, iter: Iterator[T]) => {
      val m = scala.collection.mutable.Map[Int, List[T]]()
      var list = List[T]()
      while (iter.hasNext) {
        list = list :+ iter.next
      }
      m(i) = list
      m.iterator
    }).collect().foreach((x: Tuple2[Int, List[T]]) => {
      val i = x._1
      println(s"partition:[$i]")
      x._2.foreach { println }
    })
  }
}

五、RDD的操作

对于RDD的操作,总的来说分为三种:

1、Transformation变化

特点:都是懒操作(算子),调用后并不是马上执行,不会真正触发RDD的处理运算。比如典型的textFile方法。此外,每当调用一次变化操作(懒方法),就会产生一个新的RDD

常用的Transformation变化操作:

大数据笔记--Spark(第一篇)_第8张图片

大数据笔记--Spark(第一篇)_第9张图片

只有我们调用才执行:

Transformation

Meaning

map(func)

参数是函数,函数应用于RDD每一个元素,返回值是新的RDD

案例展示:

map 将函数应用到rdd的每个元素中

大数据笔记--Spark(第一篇)_第10张图片

flatMap(func)

扁平化map,对RDD每个元素转换,然后再扁平化处理

案例展示:

val rdd = sc.makeRDD(List("hello world","hello count","world spark"),2)
rdd.map(_.split{" "})//Array(Array(hello, world), Array(hello, count), Array(world, spark))
rdd.flatMap(_.split{" "})//Array[String] = Array(hello, world, hello, count, world, spark)
//Array[String] = Array(hello, world, hello, count, world, spark)

注:map和flatMap有何不同?

map: 对RDD每个元素转换

flatMap: 对RDD每个元素转换, 然后再扁平化(即去除集合)

所以,一般我们在读取数据源后,第一步执行的操作是flatMap

filter(func)

参数是函数,函数会过滤掉不符合条件的元素,返回值是新的RDD

案例展示:

filter 用来从rdd中过滤掉不符合条件的数据

大数据笔记--Spark(第一篇)_第11张图片

mapPartitions(func)

该函数和map函数类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器。

案例展示:

大数据笔记--Spark(第一篇)_第12张图片

大数据笔记--Spark(第一篇)_第13张图片

补充:此方法可以用于某些场景的调优,比如将数据存储数据库,

如果用map方法来存,有一条数据就会建立和销毁一次连接,性能较低
所以此时可以用mapPartitions代替map

mapPartitionsWithIndex

(func)

函数作用同mapPartitions,不过提供了两个参数,第一个参数为分区的索引。

案例展示:

大数据笔记--Spark(第一篇)_第14张图片

union(other Dataset)

返回一个新数据集,该数据集包含源数据集中的元素和参数的并集

union 并集 -- 也可以用++实现

案例展示:

大数据笔记--Spark(第一篇)_第15张图片

intersection

(other Dataset)

返回一个新的RDD,该RDD包含源数据集中的元素与参数的交集

案例展示:

大数据笔记--Spark(第一篇)_第16张图片

subtract

返回差集

案例展示:

distinct([numTasks])

返回包含源数据集的不同元素的新数据集。

没有参数,将RDD里的元素进行去重操作

案例展示:

大数据笔记--Spark(第一篇)_第17张图片

groupByKey([numTasks])

当对(K, V)对的数据集调用时,返回(K, V)对的数据集。

注意:如果你分组是为了对每个键执行聚合(比如求和或平均),那么使用reduceByKey或aggregateByKey将产生更好的性能。

注意:默认情况下,输出的并行级别取决于父RDD的分区数量。你可以传递一个可选的numTasks参数来设置不同数量的任务。

案例展示:

注:groupByKey对于数据格式是有要求的,即操作的元素必须是一个二元tuple

大数据笔记--Spark(第一篇)_第18张图片

reduceByKey(func,[numTasks])

这个方法就是在groupByKey的基础上传入一个函数来处理数据

案例展示:

var rdd = sc.makeRDD( List( ("hello",1),("spark",1),("hello",1),("world",1) ) )

rdd.reduceByKey(_+_);

注:reduceByKey操作的数据格式必须是一个二元tuple

aggregateByKey

(zeroValue)(seqOP,comOP,[numTasks])

当对(K, V)对的数据集调用时,返回一个(K, U)对的数据集,其中每个键的值使用给定的组合函数和中性的“零”值进行聚合。允许与输入值类型不同的聚合值类型,同时避免不必要的分配。与groupByKey类似,reduce任务的数量可以通过第二个可选参数进行配置。

案例展示:

aggregateByKey(zeroValue)(func1,func2)

  • zeroValue表示初始值,初始值会参与func1的计算
  • 在分区内,按key分组,把每组的值进行fun1的计算
  • 再将每个分区每组的计算结果按fun2进行计算

大数据笔记--Spark(第一篇)_第19张图片

sortByKey

([ascending],[numTasks])

当在K实现了Ordered的(K, V)对数据集上调用时,返回一个(K, V)对数据集,按键的升序或降序排序。

案例展示:

大数据笔记--Spark(第一篇)_第20张图片

join

(otherDataset,[numTasks])

当调用类型为(K, V)和(K, W)的数据集时,返回一个(K, (V, W))对的数据集,每个键有所有对的元素。通过leftOuterJoin、rightOuterjoin和fullOuterJoin支持外部连接。

案例展示:

大数据笔记--Spark(第一篇)_第21张图片

cartesian(otherDataset)

参数是RDD,求两个RDD的笛卡儿积

案例展示:

大数据笔记--Spark(第一篇)_第22张图片

coalesce(numPartitions)

coalesce(n,true/false) 扩大或缩小分区

案例展示:

val rdd = sc.makeRDD(List(1,2,3,4,5),2)

rdd.coalesce(3,true);//如果是扩大分区 需要传入一个true 表示要重新shuffle

rdd.coalesce(2);//如果是缩小分区 默认就是false 不需要明确的传入

repartition(numPartitions) repartition(n) 等价于上面的coalesce

2、Action执行

特点:操作会真正触发执行

Action

Meaning

reduce(func)

使用函数func(它接受两个参数并返回一个)聚合数据集的元素。这个函数应该是交换的和结合的,这样才能正确地并行计算。

并行整合所有RDD数据,例如求和操作

collect()

返回RDD所有元素,将rdd分布式存储在集群中不同分区的数据 获取到一起组成一个数组返回

要注意 这个方法将会把所有数据收集到一个机器内,容易造成内存的溢出 在生产环境下千万慎用

大数据笔记--Spark(第一篇)_第23张图片

count()

统计RDD里元素个数

案例展示:

val rdd = sc.makeRDD(List(1,2,3,4,5),2)

rdd.count

first()

返回数据集的第一个元素(类似于take(1))。

take(n)

返回包含数据集的前n个元素的数组。

案例展示:

take 获取前几个数据

val rdd = sc.makeRDD(List(52,31,22,43,14,35))

rdd.take(2)

takeOrdered(n, [ordering])

使用自然顺序或自定义比较器返回RDD的前n个元素。

案例展示:

takeOrdered(n) 先将rdd中的数据进行升序排序 然后取前n个

val rdd = sc.makeRDD(List(52,31,22,43,14,35))

rdd.takeOrdered(3)

top(n)

top(n) 先将rdd中的数据进行降序排序 然后取前n个

val rdd = sc.makeRDD(List(52,31,22,43,14,35))

rdd.top(3)

saveAsTextFile(path)

将数据集的元素作为文本文件(或一组文本文件)写入本地文件系统、HDFS或任何其他hadoop支持的文件系统中的给定目录中。Spark会对每个元素调用toString,将其转换为文件中的一行文本。

案例展示:

saveAsTextFile 按照文本方式保存分区数据

val rdd = sc.makeRDD(List(1,2,3,4,5),2);

rdd.saveAsTextFile("/root/work/aaa")

大数据笔记--Spark(第一篇)_第24张图片

countByKey()

仅在(K, V)类型的rdd上可用。返回(K, Int)对的哈希图,包含每个键的计数。

foreach(func)

对数据集的每个元素运行函数func。这通常用于一些副作用,如更新Accumulator或与外部存储系统交互。

注意:在foreach()之外修改Accumulators以外的变量可能会导致未定义的行为。

3、Controller控制

对性能效率和容错方面的支持。persist , cache, checkpoint

后面在RDD的持久化会详细讲解

import org.apache.spark.storage._
val rdd1=sc.makeRDD(1 to 5)
rdd1.cache  //cache只有一种默认的缓存级别,即MEMORY_ONLY
rdd1.persist(StorageLevel.MEMORY_ONLY)
 

你可能感兴趣的:(大数据08-Spark,spark,scala)