Spark 概述与编程模型

概述,生态系统以及周边的配套

  • 本地实现
  • 线上 HDFS 实现

运行的时候

  • 交互式 shell 编写
  • IDE 编写

对spark内核进行解析,结合源码,能写基本代码

对 transformation 了解,map(),能写代码

什么是 Spark ?

Apache Spark is an open source cluster computing system that aims to make data analytics fast — both fast to run and fast to write

不仅分析快,写代码也快

以下为 the Berkeley Data Analytics Stack (BDAS)
Spark 概述与编程模型_第1张图片

Mesos 与 yarn 功效类似,有效区别
国内用 yarn 比较多,生态系统 yarn 更多一些

Mesos 的上一层是 分布式文件系统 HDFS

Tachyan 是分布式内存文件系统,并不仅支持 spark,也支持map-reduce

hadoop2.3.0 的datanode 也支持 cache(重大改进)

Spark Streaming Stream processing 是实时流处理

GraphX 是个图处理

MLlib 是个机器学习库

Shark SQL API 相当于 Hive on Spark ,相当于在 spark 上面建立一个 SQL

BlinkDB是海量数据上运行交互式SQL查询的大规模并行查询引擎,它允许用户通过传衡数据精度提升查询响应时间,可以将查询时间限制在误差范围之内

Spark 概述与编程模型_第2张图片

只需要一个站,就可以将所有都搞定了!无论是实时查询、流处理还是批处理,都可以实现

而以往的 Hadoop MapReduce来进行海量数据的分析,用 Strom 来进行实时流处理,Hive来做 SQL 处理,但维护这么多系统,必然会出现很多问题!spark 却不会出现这些问题,因为兼容好,原始设计的初衷也是这样。spark 是最有希望成为下一代分布式计算系统

回顾 Hadoop

Spark 概述与编程模型_第3张图片

  • 两个阶段,map / reduce
  • 每个 map 从 HDFS 若干个数据处理,input split 。inputfomat,将 hdfs上的数据处理为 key-value。通过inputfomat 实现。可供用户的 map 程序执行。排序后的会不断的spilt到 disk 上
  • 然后有一各分片的过程,partition过程 。map需要哪找 partiton 过程 , 可以指定分片被放在哪个 reduce 上。一个排好序的大文件
  • combine 相当于在本地已经进行 reduce 的过程了。
  • reduce 就是”要“数据,从map拿数据,数据量大放在磁盘上,数据量小,放在内存上。但由于小文件过多,全在内存,会爆。

面试必问题

Spark 概述与编程模型_第4张图片

Hadoop的数据共享?慢
为什么慢???额外的复制,序列化和磁盘IO开销

每次迭代操作写入和写出都是在 hdfs 上完成的。然而数据挖掘和机器学习 迭代次数非常多

将来 spark 从 datanode(有 cache)上取数据将非常完美了

十几G和百来G很适合 spark

Spark的快只是因为内存?

  • 内存计算
  • DAG 是把整个执行过程做成一张图,然后再进行优化

很多优化措施其实是相通的,譬如说delay scheduling
比如 A节点上正在运行程序,当 B 节点需要从 A 节点上获取资源时,那么将延迟一段时间在执行。这样可以避免以往从忙碌的A节点上复制数据,这样是很耗费时间的,因为如果等待也许只需要几秒钟呢…

Spark API

  • 支持3种语⾔言的API
  • Scala(很好)
  • Python(不错)
  • Java(不建议)

通过哪些模式运行Spark呢

有4种模式可以运⾏

  • local(多⽤用于测试)
  • Standalone
  • Mesos
  • YARN(工作时)

一切都以RDD为基础

  • A list of partitions(源代码里的注释里)一系列的分片
  • A function for computing each split
    定义一个函数计算或迭代

  • A list of dependencies on other RDDs
    一系列的依赖,RDD(a)->RDD(b)->RDD(c) ,则C 依赖 B ,B依赖A,这样就相互依赖

  • Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
    告诉它怎么去分片的,利用小的技巧,可以避免很大的shuffle,避免宽依赖,优化成窄依赖

  • Optionally, a list of preferred locations to compute each split on(e.g. block locations for an HDFS file)
    选择最优的计算机子来进行,

Spark runtime

Spark 概述与编程模型_第5张图片

用户的 driver 程序,各个 worker 从分布式系统中获取数据并计算,把结果持久化。

流程图示意

Spark 概述与编程模型_第6张图片

其中的 transformation 操作是针对 RDD 操作的,且是延迟执行的(比如 map()操作),spark 并不会真正执行,而是会在原数据下记录下即将对 A 进行 map 操作。到 action 才会执行。

RDD可以从集合直接转换⽽而来,也可以由从现存的任何Hadoop InputFormat⽽而来,亦或者HBase等等,但国内应用比较少

first demo

Spark 概述与编程模型_第7张图片

  • sc 即为 sparkcontents
  • lines 代表取了很多数据
  • .filter() 过滤,再次强调这里的 transformation 延迟
  • 有count 就是代表执行的操作

缓存策略

class StorageLevel private(!
    private var useDisk_ : Boolean,!
    private var useMemory_ : Boolean,!
    private var deserialized_ : Boolean,!
    private var replication_ : Int = 1)!

val NONE = new StorageLevel(false, false, false)!
val DISK_ONLY = new StorageLevel(true, false, false)!
val DISK_ONLY_2 = new StorageLevel(true, false, false, 2)!
val MEMORY_ONLY = new StorageLevel(false, true, true)!
val MEMORY_ONLY_2 = new StorageLevel(false, true, true, 2)!
val MEMORY_ONLY_SER = new StorageLevel(false, true, false)!
val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, 2)!
val MEMORY_AND_DISK = new StorageLevel(true, true, true)!
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, true, 2)!
val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false)!
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, 2)

其中 cache默认

 val MEMORY_ONLY = new StorageLevel(false, true, true)!

transformation & action

scala 操作和 spark 操作一样的
Spark 概述与编程模型_第8张图片

  • map 指的是对每个函数经过函数转换后的所有值,得到新的分布式数据集
  • filter是经过函数计算,返回 true
  • flatMap: 先压扁,再map
  • sample: 返回一个样本子集
  • groupByKey:在键值对数据上调用,将相同的 key 的值都组合起来,返回一个序列
  • reduceByKey:相对于groupByKey, function 会作用在具有相同 key的 value 上面,返回的是一个值
  • union :两个数据联合起来
  • join :就是一个显示
  • cogroup:会生成两个序列
  • mapValue : 会保存 partition,key 不变,只改变 value
  • sort: 用的最多还是 sortByKey 函数。 原始 API 不提供 sortByValue, 相应的解决办法就是将 key 和value 的位置相互调换,再用 sortByKey 函数

Action:

  • count: 取出多少行
  • colletc:取出一部分
  • loohup:在 map 中 look 出一个 key 一样
  • save :会将结果保存到存储系统,如 HDFS

运行几行代码

进入 spark下的 bin 目录,启动 spark-shell

cd /home/hadoop/software/spark-1.0.2-bin-hadoop2/bin
./spark-shell

Spark 概述与编程模型_第9张图片

1. 分别执行以下命令(新手)

val rdd = sc.parallelize(List(1,2,34,5,6))

这里写图片描述

val mapRdd = rdd.map(2 * _)

这里写图片描述

mapRdd.collect

这里写图片描述

val filterRdd = mapRdd.filter(_ > 5)

这里写图片描述

filterRdd.collect

这里写图片描述

2. 一步到位(老手)

val filterRdd = sc.parallelize(List(1,2,34,5,6)).map(2 * _).filter(_ > 5).collect

Spark 概述与编程模型_第10张图片

运行 wordcount 程序

  • 准备数据,首先新建文件inputWord
vim ~/inputWord

内容如下:

  • 将本地文件上传到HDFS中
hadoop fs -put  ~/inputWord /data/wordcount/
  • 可以查看上传后的文件情况,执行如下命令
hadoop fs -ls /data/wordcount
hadoop fs -text /data/wordcount/inputWord

进入 spark 的 sbin 目录下

cd /home/hadoop/software/spark-1.0.2-bin-hadoop2/sbin
./start-master.sh

显示如下:

starting org.apache.spark.deploy.master.Master, logging to /home/hadoop/software/spark-1.0.2-bin-hadoop2/sbin/../logs/spark-hadoop-org.apache.spark.deploy.master.Master-1-master.out

查看相应的 log 文件

cat logs/spark-hadoop-org.apache.spark.deploy.master.Master-1-master.out

Spark 概述与编程模型_第11张图片

可以看到输出的几条重要的信息,spark端口 7077,ui端口8080等,并且当前node通过选举,确认自己为leader,这个时候,我们可以通过 http://localhost:8080/ 来查看到当前master的总体状态

Spark 概述与编程模型_第12张图片

val rdd = sc.textFile("/data/wordcount/")
rdd.cache
rdd.count

Spark 概述与编程模型_第13张图片

Note:暂时只会从 HDFS上取数据,而不会从本地上取数据。在 HDFS 上的路径应是文件的上一层路径,不应包含文件名!切记!

val wordcount = rdd.flatMap(_.split(' ')).map((_,1)).reduceByKey(_+_)

这里写图片描述

wordcount.collect

Spark 概述与编程模型_第14张图片

期间,我们可以通过UI看到job列表和状态:
http://localhost:4040/stages/

Spark 概述与编程模型_第15张图片

val rdd1 = sc.parallelize(List(('a',1),('a',2)))
val rdd2 = sc.parallelize(List(('b',1),('b',2)))
val result = rdd1 union rdd2
result.collect

Spark 概述与编程模型_第16张图片

val rdd1 = sc.parallelize(List(('a',1),('a',2),('b',3),('b',4)))
val rdd2 = sc.parallelize(List(('a',5),('a',6),('b',7),('b',8)))
rdd1 join rdd2
res12.collect

最终出现以下结果
这里写图片描述

val rdd1 = sc.parallelize(List(('a',1),('a',2),('b',3),('b',4)))
rdd1.lookup('a')

这里写图片描述


val rdd = sc.textFile("/data/spark_wordcount")
val wordcount = rdd.flatMap(_.split(' ' )).map((_,1)).reduceByKey(_+_).map(x => (x._2,x._1)).sortByKey(false).map(x => (x._2,x._1)).saveAsTextFile("/spark_outcome/")

程序执行成功之后,在另外一个终端输入命令以查看最终的结果

hadoop fs -ls -R /spark_outcome

这里写图片描述

hadoop fs -text /spark_outcome/part-00000
hadoop fs -text /spark_outcome/part-00001

Spark 概述与编程模型_第17张图片

Lineage

Spark 概述与编程模型_第18张图片

每个子RDD都依赖前一个 RDD,一般会在中间制作个拷贝,防止最后的时刻某个 RDD 挂了

容错

val logs = sc.textFile(…).filter(_.contains(“spark”)).map(_.split(‘\t’)(1))

Spark 概述与编程模型_第19张图片

每个RDD都会记录⾃自⼰己依赖于哪个(哪些)RDD,万⼀一某个RDD的某些 partition挂了,可以通过其它RDD并⾏行计算迅速恢复出来

依赖

Spark 概述与编程模型_第20张图片

大的框称之为 RDD,而小的实心矩形为 partition

窄依赖:一个 partition 最多只能被子 RDD 的一个 partion 所使用
宽依赖:一个 partition 可以被子 RDD 的多个 partion 所使用

map,filter 会导致窄依赖,而 join 会导致宽依赖。co-partition 也可以被认为是窄依赖

在一个节点上把所有的 partition 全部搞定,宽依赖只有等所有的副partition全部传输到节点上以后才开始计算。在宽依赖中,如果某个节点失效了,那么将重新计算,计算代价相当的大

左边的 RDD 计算出的结果,会存在 map端所在的磁盘

集群配置

spark-env.sh

export JAVA_HOME=
export SPARK_MASTER_IP=
export SPARK_WORKER_CORES=   // 分配给spark的CPU数量 
export SPARK_WORKER_INSTANCES=  // 划分出来的实例,普通的一个就够了
export SPARK_WORKER_MEMORY=  // 给 spark 分配的内存
export SPARK_MASTER_PORT=   // 设置的端口
export SPARK_JAVA_OPTS="-verbose:gc -XX:-PrintGCDetails -XX:+PrintGCTimeStamps”

slaves
xx.xx.xx.2
xx.xx.xx.3
xx.xx.xx.4
xx.xx.xx.5

版本选择

  • ⾃己编译 — 可能会遇到某些问题
    网络好就可以尝试,否则就算了
  • pre-built版本
    下载相应 hadoop2.2.0 版本的 spark

interactive shell & programming in IDE

shell运行

/sbin 是存放一些启动和关闭集群的一些脚本
/bin 是存放 spark 启动关闭的程序,例如 spark-shell

MASTER=local[4] ADD_JARS=code.jar ./spark-shell

其中 local [4] 表示的是 几个本地线程

如果只是简单的启动,后面没有跟任何参数,那么默认是以 standalone 的方式启动

MASTER=spark://host:port 
指定executor内存:export SPARK_MEM=25g

这个指定的 application 能用多少内存(这个命名可能将来会被废除)

spark-shell注意

spark-shell intends to set MASTER automatically if we do not provide the option when we start the shell , but there’s a problem. The condition is “if [[ “x” != “x$SPARK_MASTER_IP” && “y” != “y $SPARK_MASTER_PORT” ]];” we sure will set SPARK_MASTER_IP explicitly, the SPARK_MASTER_PORT option, however, we probably do not set just using spark default port 7077. So if we do not set PARK_MASTER_PORT, the condition will never be true. We should just use default port if users do not set port explicitly I think.

Spark 概述与编程模型_第21张图片

IDE

  • 推荐Intellij IDEA
  • 加⼊依赖

Spark 概述与编程模型_第22张图片
有时还要把 hadoop 版本加进去

  • coding
  • 打包
  • 运⾏

Spark 1.0相关变动

  • spark-defaults.conf 默认参数
spark.master spark://server1:8888
spark.local.dir /data/tmp_spark_dir/    // shuffle 过程中的临时目录
spark.executor.memory 10g   // 设置内存
  • 注意:SPARK_MEM已被弃⽤
  • SPARK_JAVA_OPTS不建议再使⽤用
  • SPARK_SUBMIT_OPTS为替代者

Spark 概述与编程模型_第23张图片

  • spark-submit
    http://spark.apache.org/docs/latest/submitting-applications.html

这里写图片描述

Spark 概述与编程模型_第24张图片

http://spark.apache.org/docs/latest/configuration.html

  • 使⽤用spark-submit来提交任务(推荐)
  • 其它也可⾏行,如sbt run, java -jar 等等

这里写图片描述

你可能感兴趣的:(Spark 概述与编程模型)