spark
UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行计算框架。
1、Spark Streaming:支持高吞吐量、支持容错的实时流数据处理
2、Spark SQL, Data frames: 结构化数据查询
3、MLLib:Spark 生态系统里用来解决大数据机器学习问题的模块
4、GraphX是构建于Spark上的图计算模型
Spark的运行模式
单机上以本地模式local运行、或以伪分布式模式运行
分布式的方式运行在Cluster集群中时,底层的资源调度可以使用Mesos 或者Yarn,也可以使用Spark自带的Standalone模式。
另外一种分法:master有local(调试方便)、yarn-client(普遍)、yarn-cluster、spark、mesos模式
Spark Standalone:需要部署Spark到相关节点,包括Master和Worker
Yarn-Cluster:Driver和Executor都运行在Yarn集群中
Yarn-Client:Driver运行在本地,Executor运行在Yarn集群中基本概念
(1) Application:用户编写的Spark应用程序,其中包含Driver功能的代码和分布在集群中多个节点上运行的Executor代码。
(2) Driver:运行Application的main()函数并且创建SparkContext,创建SparkContext的目的是为了准备Spark应用程序的运行环境。
SparkContext负责和ClusterManager通信,进行资源的申请、任务的分配和监控等。
当Executor部分运行完毕后,Driver同时负责将SparkContext关闭。通常用SparkContext代表Driver。
(3)Executor: 某个Application运行在Worker节点上的一个进程,该进程负责运行某些Task,并且负责将数据存在内存或者磁盘上。
每个Application都有各自独立的一批Executor。
(4)Cluster Manager:指的是在集群上获取资源的外部服务,目前有:
Standalone:Spark原生的资源管理,由Master负责资源的分配
Apache Mesos:与Hadoop MapReduce兼容性良好的一种资源调度框架;
Hadoop Yarn:主要是指的Yarn中的ResourceManager;
(5)Worker:集群中任何可以运行Application代码的节点
在Standalone模式中指的就是通过slave文件配置的Worker节点,在Spark on Yarn模式中指的就是NodeManager节点。
(6)Job:包含多个Task组成的并行计算,往往由Spark Action触发产生。一个Application中可能会产生多个Job。
(7)Stage:Job被拆分很多组Task,作为一个TaskSet,其名称为Stage。
Stage的划分和调度由下面的DAGScheduler负责。
Stage有非最终的Stage即Shuffle Map Stage和最终的Stage即Result Stage两种。
Stage的边界就是发生Shuffle的地方。
(8)Task:被送到某个Executor上的工作单元,是运行Application的基本单位。
多个Task组成一个Stage,而Task的调度及管理等由下面的TaskScheduler负责。
一个Job被拆分成若干个Stage,每个Stage执行一些计算,产生一些中间结果。
它们的目的是最终生成这个Job的计算结果。
而每个Stage是一个task set,包含若干个task。Task是Spark中最小的工作单元,在一个executor上完成一个特定的事情。
(9)RDD:Spark的基本计算单元,可以通过一系列算子进行操作(主要有Transformation 延迟执行 和Action操作)。
它表示已被分区、被序列化的、不可变的、有容错机制的并且能够被并行操作的数据集合。
A list of partitions
A function for computing each split
A list of dependencies on other RDDs
其存储级别可以是内存,也可以是磁盘,可通过spark.storage.StorageLevel属性配置。
1、直接从集合转化 sc.parallelize(List(1,2,3,4,5,6,7,8,9,10))
2、从各种(分布式)文件系统来 sc.textFile(“README.md”) sc.textFile(“hdfs://xxx”)
3、从现存的任何Hadoop InputFormat而来 sc.hadoopFile(keyClass, valClass, inputFormat,conf)
(10)共享变量:在Spark Application运行时,可能需要共享一些变量,提供Task或Driver等使用。
Spark提供了两种共享变量,一种是可以缓存到各个节点的广播变量,一种是只支持加法操作、可以实现求和的累加变量。
(11)宽依赖:ShuffleDependency,依赖需要计算好所有父RDD对应分区的数据,然后在节点之间进行Shuffle。
指父RDD的每个分区都可能被多个子RDD分区所使用,子RDD分区通常对应所有的父RDD分区(O(n),与数据规模有关)
(12)窄依赖:RDD其分区最多被子RDD中的一个分区依赖。此种情况只有Map任务,是不需要发生Shuffle过程的。窄依赖又分为1:1和N:1两种。
(13)DAGScheduler:根据Job构建基于Stage的DAG,并提交Stage给TaskScheduler。其划分Stage的依据是根据RDD之间的依赖关系。
1、为每个Job分割stage,同时会决定最佳路径,并且DAG Sheduler会记录哪个RDD或者stage的输出被物化,从而来找到一个最优调度方案。
2、将TaskSet传给TaskScheduler3、重新提交那些输出lost的stage
(14)TaskScheduler:将Taskset提交给Worker(集群)运行,每个Executor运行什么Task就是在此处分配的。
1、提交tasks到集群并执行,假如出错就重试。
2、假如shuffle输出lost就报告fetch failed错误 3、遇到straggle task需要放到别的node上重试spark的2个优点:
内存计算(Job中间输出和结果可以保存在内存中,从而不再需要读写HDFS)
DAGSpark Streaming的核心思想是把流式处理转化为“微批处理”,即以"时间"为单位切分数据流,每个切片内的数据对应一个RDD,
最小抽象单位是Discretized Stream,常用操作foreachRDD
代码例子 object NetworkWordCount {
def main(args: Array[String]) {
StreamingExamples.setStreamingLogLevels()
val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
val ssc = new StreamingContext(conf, Seconds(1))
val lines = ssc.socketTextStream("localhost", 9999)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.print()
ssc.start()
ssc.awaitTermination() transformation 返回值还是一个RDD
窄依赖:
map List("dog", "salmon", "salmon", "rat", "elephant").map(_.length)
flatMap List(1, 2, 3), 2).flatMap(x => List(x, x, x)) = Array(1, 1, 1, 2, 2, 2, 3, 3, 3)
mapPartitions 对rdd中的每个分区的迭代器进行操作 while(x.hasNext){ 操作运算x.next()...
mapPartitionsWithIndex
filter (1 to 10).filter(_ % 2 == 0)
union 将两个RDD进行合并,不去重 等价操作符++ (sc.parallelize(datas1) ++ sc.parallelize(datas2)).foreach(println)
intersection 取交集 sc.parallelize(datas1).intersection(sc.parallelize(datas2)).foreach(println);
distinct 去重复 datas.distinct().foreach(println)
repartition 就是coalesce函数第二个参数为true的实现
coalesce 将RDD进行重分区,使用HashPartitioner。且该RDD的分区个数等于numPartitions个数。如果shuffle设置为true,则会进行shuffle。
partitions
cartesian 笛卡尔积
sample data.sample(withReplacement = false, 0.5, System.currentTimeMillis)
groupwith
crossProduct
mapvalues
sort
宽依赖: 常见于K-V style RDD
groupByKey [(3,dog),(4,lion)] [(3,cat)]..... => (4,[lion])(6,[spider])(3,[dog, cat])(5,[tiger, eagle])
reduceByKey List("dog", "tiger", "lion", "cat", "panther", "eagle").map(x => (x.length, x).educeByKey(_ + _) = Array((4,lion), (3,dogcat), (7,panther), (5,tigereagle))
cogroup 对多个RDD中的KV元素,每个RDD中相同key中的元素分别聚合成一个集合。与reduceByKey不同的是针对两个RDD中相同的key的元素进行合并。
sortByKey List((3, 3), (2, 2), (1, 4), (2, 3))).sortByKey(true)
aggregateByKey
sortBy sortBy(_._1) sortBy(_._2)...
其他
join 可能是宽依赖也可能是窄依赖,其区别是,当要对RDD进行join操作时,如果RDD进行过重分区则为窄依赖,否则为宽依赖。
(List((1, "苹果"), (2, "梨"), (3, "香蕉"), (4, "石榴"))).join(sc.parallelize(List((1, 7), (2, 3), (3, 8), (4, 3), (5, 9))))
= (4,(石榴,3)) (1,(苹果,7)) (3,(香蕉,8)) (2,(梨,3))
left outer join 左外连接,左边表中的值无论是否在b中存在时,都输出;右边表中的值,只有在左边表中存在时才输出。
right outer join 和 left outer join 相反。
举例:rdd={(1,2),(3,4),(3,6)} other={(3,9)}
join 对两个RDD进行内连接 rdd.join(other) {(3,(4,9)),(3,(6,9))}
rightOuterJoin 对两个RDD进行连接操作,右外连接rdd.rightOuterJoin(other) {(3,(4,9)),(3,(6,9))}
leftOuterJoin 对两个RDD进行连接操作,左外连接rdd.rightOuterJoin(other) {(1,(2,None)),(3,(4,9)),(3,(6,9))}
action 返回值是一个值,
reduce reduce(_ + _) 求和 满足结合律 交换律
count 计数
countByKey 仅适用于(K, V)类型,对key计数,返回(K, Int)
take 取前若干位
first 即take(1)
takeSample
saveasfile
saveAsTextFile
saveassequence
lookup
collect 转数组
foreach collect是从远程拉取到本地,经过网络传输,foreach是在远程集群上遍历 如果是在本地的话,差别不大
foreachPartition 这里function的传入参数是一个partition对应数据的iterator
spark工作流程
Spark的Application在运行的时候,首先在Driver程序中会创建sparkContext作为调度的总入口,
在其初始化过程中会分别创建DAGScheduler进行Stage调度 TaskScheduler进行Task调度两个模块。
DAGScheduler模块是基于Stage的调度模块,它为每个Spark Job计算具有依赖关系的多个Stage任务阶段,
然后将每个Stage划分为具体的一组任务(通常会考虑数据的本地性等)以TaskSet 的形式提交给底层的TaskScheduler模块来具体执行。
TaskScheduler负责具体启动任务,监控和汇报任务运行情况。而任务运行所需要的资源需要向Cluster Manager申请。
目前,用spark-submit工具来提交Spark Application,其基本提交格式为:spark-submit [options] <app jar file> [app options] 在其附加参数中可以指定Driver和Executor相关的配置信息。
获取rdd的方法
1、从共享的文件系统获取,(如:HDFS、HBase) var rdd = sc.textFile("hdfs:///qgzang/1.txt")
2、通过已存在的RDD转换
3、将已存在scala集合(只要是Seq对象)并行化 ,通过调用SparkContext的parallelize方法实现 var rdd = sc.parallelize(1 to 10)
wordcount例子:sc.textFile("README.md").flatMap(_.split(' ')).map((_,1)).reduceByKey(_+_) 其他方法是使用countByValue 和AggregateByKeyspark优化
1.减少shuffle
2.内存管理优化
3.配置项优化
4.数据序列化,数据结构优化
代码调优
1、复用相同RDD数据,避免重复创建多份RDD数据。
2、persist(StorageLevel.MEMORY_AND_DISK_SER RDD持久化操作调用cache()和persist(), cache相当于persist(StorageLevel.MEMORY)
3、尽量避免使用shuffle类算子(不是不使用) reduceByKey、join、distinct、repartition、groupByKey,cartesian ….
4、对于非巨型的大变量,使用广播变量Broadcast机制。好处:(1)每个excutor只存放份数据,而不是1个task一份(2)减小task序列化时间
场景:lookup表, mapside join
常规做法:
val rdd_A=…
val rdd_B=…
val rdd_C = rdd_A.join(rdd_B)
优化做法:
val rdd_A=…
val rdd_B=… .collect()
val rdd_B_Brd = sc.broadcast(rdd_B)
val rdd_C = rdd_A.map(x=> {
val key=x._1
val value1 = x._2
val value2 = rdd_B_Brd.value.getOrElse
(key, (value1, value2) )
})
5、使用高性能的RDD算子。
(1)使用reduceByKey/aggregateByKey替代groupByKey
(2)使用mapPartitions替代普通map(优化点,但小心OOM)
(3)使用foreachPartitions替代foreach(尤其是将结果数据输出到数据库时强烈建议使用)
(4)变化太多可能会产生很多小任务,使用coalesce(TRUE, n)代替repartition
6、使用Kryo优化序列化性能。spark默认的序列化机制是JAVA的ObjectOutputStream 兼容性好。但又大又慢
7、数据结构,尽量少使用Java对象。尽量使用字符串代替对象,使用原始类型(Int,long)替代字符串,使用数组替代集合类型,这样尽可能地减少内存占用,从而降低GC频率,提升性能。
只是尽量但也得兼顾代码可读性
8、计算并发度优化 管理操纵RDD、Partition数控制task计算的并行度 调优shuffle的并发度
9、其他。(1)无效数据处理能先过滤就先过滤,即filter前置。
(2)能减小数据处理的数据记录冗余则尽量减小。
比如: (key1,key2,value1,value2))需要基于key
((key1,key2),(key1,key2,value1,value2))
好的写法:((key1,key2),(value1,value2)
(3)有用本地运行则不用shuffle
如:A.map().reduceByKey().map().reduceByKey()
A.map().reduceByekey()
参数调优
1.driver-memory (1g-4g)
--防止spark应用OOM
2.num-executors
--控制节点并发
3.executor-memory (2-6G)
4.executor-cores (2-4个)
--决定task执行时长
5.spark.default.parallelism(默认同RDD分区数同)
--决定shuffle并发数
6.spark.yarn.executor.memoryOverhead
7. spark.kryoserializer.buffer.max (默认64M)环境调优
1、优化jar分发性能,防止jar重复上传。 如:
spark-submit hdfs://nameservice1/work/wis_2/wis.jar
spark-submit wis.jar //运行时会上传jar包到hdfs
2、数据本地化 HDFS和Mongodb
3、dir目录配置spark.local.dir(多目录,ssd) spark生态圈
HDFS
Hadoop分布式文件系统(Hadoop Distributed File System HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。
HDFS是一个高度容错性的系统,适合部署在廉价的机器上。
三个部分:
客户端(访问hdfs的入口)
nameserver(可理解为主控和文件索引类似linux的inode)一般有个secondary备份
datanode(存放实际数据的存server)
第一个block副本放在和client所在的node里(如果client不在集群范围内,则这第一个node是随机选取,当然系统会尝试不选择哪些太满或者太忙的node);
第二个副本放置在与第一个节点不同的机架中的node中(随机选择);
第三个副本和第二个在同一个机架,随机放在不同的node中。
优点: 1)处理超大文件 2)流式的访问数据
缺点: 1)不适合低延迟数据访问 2)无法高效存储大量小文件 3)不支持多用户写入及任意修改文件
Sc.textFile(path: String, minPartitions: Int = defaultMinPartitions)
Sc.objectFile[T](path: String, minPartitions: Int = defaultMinPartitions)
Rdd.saveAsTextFile(path: String): Unit
Rdd. saveAsObjectFile(path: String): Unit
RDD save到Hdfs后,RDD的每个分区都会对应于一个HDFS文件。如果一个RDD数据小,但分区多,则最好对RDD调整分区后,再保存。
RDD. Coalesce(N)
Coalesce用法注意:
1、如果将1000个分区转换成100个分区,这个过程不会发生shuffle,相反如果10个分区转换成100个分区将会发生shuffle。
2、也不能将N值设置太小,例如合并成一个分区,在数据量较大时会OOMKafka
Kafka是一个消息系统,原本开发自LinkedIn,用作LinkedIn的活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础。
Broker:Kafka集群包含一个或多个服务器,这种服务器被称为broker
Topic:每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic,被分成多个partition,每个partition是个fifo队列
Partition:物理上的概念,每个Topic包含一个或多个Partition.
Producer:负责发布消息到broker,负责确定topic,负责确定partition,异步发送
producer的ack的3种模式:
0:这意味着生产者producer不等待来自broker同步完成的确认就继续发送下一条(批)消息。此选项提供最低的延迟但最弱的耐久性保证,因为其没有任何确认机制。
1:这意味着producer在leader已成功收到数据并得到确认后,再发送下一条消息。此模式leader的确认后就返回,而不管partion的follower是否已经完成。
-1:这意味着producer在follower副本确认接收到数据后才算一次发送完成。 此选项提供最好的耐久性,保证至少一个同步副本保持存活。
Consumer:消息消费者,向Kafka broker读取消息的客户端。
Consumer Group:每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。
spark stream读取kafka数据,2个方式(1)利用接收器(receiver)和kafaka的高层API实现。(2)直接用kafka底层的API来实现。(生产上常用)
sparkle和sparkling sparkle和sparkling的区别
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
下一篇:数据挖掘的发展前景 数据挖掘未来

提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章