一、常用Actoin算子 (reduce 、collect 、count 、take 、saveAsTextFile 、 countByKey 、foreach )

collect:从集群中将所有的计算结果获取到本地内存,然后展示

take:从集群中将一部分的计算结果获取到本地内存,然后展示

rdd.collect

rdd.take(n)

二、内存管理

1、RDD内存持久化

Spark非常重要的一个功能特性就是可以将RDD持久化在内存中。

当对RDD执行持久化操作时, 每个节点都会将自己操作的RDD中的partition持久化到内存中, 并且在之后对该RDD的反复使用中, 直接使用内存中缓存的partition数据。

这样的话, 对于针对一个RDD反复执行多个操作的场景, 就只要对RDD计算一次即可, 后面 直接使用该RDD, 而不需要反复计算多次该RDD。

巧妙使用RDD持久化, 甚至在某些场景下, 可以将Spark应用程序的性能提升10倍。 对于迭代式算法和快速交互式应用来说, RDD持久化, 是非常重要的。

2、RDD持久化原理
          要持久化一个RDD, 只要调用其cache()或者persist()方法即可。
          在该RDD第一次被计算出来时, 就会直接缓存在每个节点中,而且Spark的持久化机制还是自 动容错的。 如果持久化的RDD中的任何partition丢失了, 那么Spark会自动通过其源RDD, 使
用transformation操作重新计算该partition。

         cache()和persist()的区别在于:
                cache()是persist()的一种简化方式, cache()的底层就是调用的persist()的无参版本, 同时就是调用 persist(MEMORY_ONLY), 将数据持久化到内存中。 如果需要从内存中清除缓存,

那么可以使用 unpersist()方法。 
         Spark自己也会在shuffle操作时, 进行数据的持久化,比如写入磁盘, 主要是为了在节点失败时, 避免需要重新计算整个过程。

3、RDD持久化策略

RDD持久化是可以手动选择不同的策略的。
             比如可以将RDD持久化在内存中、 持久化到磁盘上、 使用序列化的方式持久化, 多持久化的数据进 行多路复用。 只要在调用persist()时传入对应的StorageLevel即可。


              以序列化方式优点:节省内存  缺点:读取时有一个反序列化,会加大CPU的开销


                   2代表副本数

4、如何选择RDD持久化策略
             Spark提供的多种持久化级别, 主要是为了在CPU和内存消耗之间进行取舍。
             下面是一些通用的持久化级别的选择建议:

优先使用MEMORY_ONLY, 如果可以缓存所有数据的话, 那么就使用这种策略。 因为纯内 存速度最快, 而且没有序列化, 不需要消耗CPU进行反序列化操作。

如果MEMORY_ONLY策略, 无法存储的下所有数据的话, 那么使用MEMORY_ONLY_SER, 将数据进行序列化进行存储, 此操作会消耗CPU进行反序列化。

如果需要进行快速的失败恢复, 那么就选择带后缀为_2的策略, 进行数据的备份, 这样在 失败时, 就不需要重新计算了。

能不使用DISK相关的策略, 就不用使用, 有的时候从磁盘读取数据, 还不如重新计算一次。

三、共享变量

1、共享变量

Spark一个非常重要的特性就是共享变量。

默认情况下, 如果在一个算子的函数中使用到了某个外部的变量, 那么这个 变量的值会被拷贝到每个task中。

此时每个task只能操作自己的那份变量副本。 如果多个task想要共享某个变 量, 那么这种方式是做不到的。

Spark为此提供了两种共享变量:

一种是Broadcast Variable( 广播变量)               另一种是Accumulator( 累加器)
            Broadcast Variable会将使用到的变量, 仅仅为每个节点拷贝一份, 更大的 用处是优化性能, 减少网络传输以及内存消耗。

Accumulator则可以让多个task共同操作一份变量, 主要可以进行累加操作。

2、Broadcast Variable广播变量

Spark提供的Broadcast Variable, 是只读的, 并且在每个节点上只会有一份副本, 而不 会为每个task都拷贝一份副本。

因此其最大作用, 就是减少变量到各个节点的网络传输消耗, 以及在各个节点上的内存 消耗。 此外, spark自己内部也使用了高效的广播算法来减少网络消耗。

通过调用SparkContext的broadcast()方法, 来针对某个变量创建广播变量, 然后在算子 的函数内使用广播变量时, 每个节点只会拷贝一份副本了 。

每个节点可以使用广播变量的value()方法获取值。 记住, 广播变量是只读的。

val factor = 3
               val factorBroadcast = sc.broadcast(factor)
               val arr = Array(1, 2, 3, 4, 5)
               val rdd = sc.parallelize(arr)
               val multipleRdd = rdd.map(num => num * factorBroadcast.value())
               multipleRdd.foreach(num => println(num))

3、Accumulator 累加器

Spark提供的Accumulator, 主要用于多个节点对一个变量进行共享性的操作。

Accumulator只提供了累加的功能, 但是却给我们提供了多个task对一个变量并 行操作的功能。

task只能对Accumulator进行累加操作, 不能读取它的值, 只有Driver程序可以 读取Accumulator的值。

val sumAccumulator = sc.accumulator(0)
             val arr = Array(1, 2, 3, 4, 5)
             val rdd = sc.parallelize(arr)
             rdd.foreach(num => sumAccumulator += num)
             println(sumAccumulator.value)

四、容错机制

1、容错机制

分布式数据集的容错性有两种方式: 数据检查点和记录数据的更新。

数据检查点(Check Point), 即将某个时机的中间数据写到存储(通常是HDFS)中。

面向大规模数据分析, 数据检查点操作成本很高, 需要通过数据中心的网络连接在机器之间 复制庞大的数据集, 而网络带宽往往比内存带宽低得多, 同时还需要消耗更多的存储资源。

Spark选择记录更新的方式。

RDD是一个有向无环图(DAG), 每一个RDD都会记住创建该数据集需要哪些操作, 跟踪记 录RDD的继承关系, 这个关系在Spark中称为LineAge(血统)。
        由于创建RDD的操作是相对粗粒度的变换, 比如map、 filter、 join等, 即单一的操作应用于 许多数据元素, 而不需要存储真正的数据, 比通过网络复制数据更高效。

当一个RDD的某个分区丢失时, RDD有足够的信息记录其如何通过其他RDD进行计算的, 只需要通过其他RDD重新计算即可。

RDD 血统的依赖关系分为两种: 宽依赖、 窄依赖。

根据父RDD分区是对应一个还是多个子RDD分区来判断。

窄依赖, 一个父RDD分区对应一个子RDD分区;

宽依赖, 一个父RDD分区对应多个子RDD分区;

对于窄依赖, 只需通过重新计算丢失的那一块数据来恢复, 容错成本

对于宽依赖, 当容错重算分区时, 因为父分区数据只有一部分是需要重算子分区的, 其余数 据重算就造成了冗余计算。

所以, 不同的应用有时候也需要在适当的时机设置数据检查点。 由于RDD的只读特性使得  它比常用的共享内存更容易做检查点, 具体可以使用doCheckPoint方法。

检查点( 本质是通过将RDD写入Disk做检查点) 是为了通过lineage做容错的辅助, lineage 过长会造成容错成本过高, 这样就不如在中间阶段做检查点容错, 如果之后有节点出现问题

而丢失分区, 从做检查点的RDD开始重做Lineage, 就会减少开销。

(血统是系统生成的,checkpoint是辅助血统的,需要手动添加)

(A-B-C-D如果把c缓存到内存当中,ABC的依赖关系依然存在,如果把D放到HDFS上,则ABC的依赖关系就没有了)

案例:移动互联网数据分析: (1)对APP字段访问次数进行统计,并进行排序 (2)统计移动互联网上日活跃用户(DAU)和月活跃用户(MAU)
                                       (3)统计在不同应用中的上下行流量

package SparkCore.day1

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD /**
* Created by tg on 3/23/17.
*/
object MobileDemo {
def main(args: Array[String]): Unit = {
upDownAmount
// mauCount
// dauCount
// appCount
}
//返回创建的初始RDD
def creatFirstRDD:RDD[Array[String]]={
val conf=new SparkConf().setAppName("MobileDemo")
.setMaster("local")
val sc=new SparkContext(conf)
//创建初始RDD
val lines=sc.textFile("file:///home/tg/datas/mobile")
.map(x=>x.split(","))
lines
}
/**
* 对APP字段访问次数进行统计,并进行排序
*/
def appCount: Unit ={
val lines=creatFirstRDD
lines.filter(x=>x.length==7 && x(3)!=null)
.map(x=>(x(3).trim,1))
.reduceByKey(_+_)
.sortBy(_._2,false)
.foreach(x=>{
println(x._1+"这款APP访问的次数是:"+x._2)
}) } /**
* 统计日活跃用户的数量
* imei是移动设备的唯一标识
* imei+time,可以确定日活跃用户,但是要注意数据去重
*/
def dauCount: Unit ={
val lines=creatFirstRDD
lines.filter(x=>x.length==7 && x(2)!=null && x(4)!=null)
.map(x=>{
val imei=x(2).trim
val time=x(4).trim
imei+":"+time //IMEI:Time
}).distinct() //进行数据去重
.map(x=>{
val time=x.split(":")(1).trim
(time,1) //形成键值对(Time,1)
}).reduceByKey(_+_)
.foreach(item=>{
println(item._1+"活跃用户的数量:"+item._2)
})
} /**
* 统计月活跃用户
*/
def mauCount: Unit ={
val lines=creatFirstRDD
lines.filter(x=>x.length==7 && x(2)!=null && x(4)!=null)
.map(x=>{
val imei=x(2).trim
val time=x(4).trim
//把时间截取到月份
val month=time.substring(0,time.lastIndexOf("-"))
imei+":"+month
}).distinct()
.map(x=>{
val month=x.split(":")(1).trim
(month,1)
}).reduceByKey(_+_)
.foreach(x=>{
println(x._1+"活跃用户数量:"+x._2)
})
} /**
* 统计在不同应用中的上下行总流量
*/
def upDownAmount: Unit ={
val lines=creatFirstRDD
lines.filter(x=>x.length==7 && x(3)!=null&&x(5)!=null&&x(6)!=null)
.map(x=>{
val app=x(3).trim //APP
val up=x(5).trim.toInt //上行流量,注意转换成Int
val down=x(6).trim.toInt //下行流量
(app,(up,down))
}).reduceByKey((x,y)=>{
/**
* x._1+y._1将相近的两个上行流量相加
* x._2+y._2将相近的两个下行流量相加
*/
(x._1+y._1,x._2+y._2)
}).foreach(x=>{
println(x._1+"这款应用的上下行流量总和分别是:")
println("上行流量总和:"+x._2._1)
println("下行流量总和:"+x._2._2)
})
}
}

  

补充:

1、大数据开发的核心理念:

(高)并发操作、 数据不动,计算动

2、HA高可靠:通过两个namenode,其中一个处于active状态。对外提供服务,另一个处于standby状态,对外不提供服务。当处于active的状态的namenode发生故障时,处于standby状态的namenode会切换为active状态并且对外提供服务,从而保证集群的正常运行。

faderation联盟:

hadoop集群在启动时,namenode需要将全部的元数据信息都加载到内存中,从而保证hadoop集群的正常启动。如果namenode中的元数据信息体量太大,内存容量又太小,那么会造成元数据信息无法全部都加载到内存中,这时hadoop集群就无法正常启动了。

为了解决这个问题,提出了faderation联盟,让原先的一个namenode变成了多个namenode,同时对外提供可服务,并且每个namenode保存元数据的一部分。在hadoop集群启动时,每个namenode将各自保存的那一部分元数据信息加载到内存中,保证hadoop集群的正常启动,这样也减轻namenode所在节点内存的压力。

但是faderationn联盟也是有缺陷的,当其中一个namenode发生故障会造成元数据信息的丢失,所以faderation无法从根本上解决单点故障。

常用Actoin算子 与 内存管理 、共享变量、内存机制的更多相关文章

  1. Linux内存管理3---分页机制

    1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...

  2. JVM内存管理及GC机制

    一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...

  3. SAP专家培训之Netweaver ABAP内存管理和内存调优最佳实践

    培训者:SAP成都研究院开发人员Jerry Wang 1. Understanding Memory Objects in ABAP Note1: DATA itab WITH HEADER LINE ...

  4. memcached的内存管理与删除机制

    memcached的内存管理与删除机制 简介 注意:Memcache最大的value也只能是1M的空间,超过1M的数据无法保存(修改memcache源代码).   注意:内存碎片化永远都存在,只是哪一 ...

  5. MC的内存管理和删除机制

    先看一下,什么叫做内存的碎片化: 如果用c语言直接 malloc,free 来向操作系统申请和释放内存时, 在不断的申请和释放过程中,形成了一些很小的内存片断,无法再利用. 这种空闲,但无法利用内存的 ...

  6. Android 之 内存管理-查看内存泄露(三)

    概述 在android的开发中,要时刻主要内存的分配和垃圾回收,因为系统为每一个dalvik虚拟机分配的内存是有限的,在google的G1中,分配的最大堆大小只有16M,后来的机器一般都为24M,实在 ...

  7. JVM自动内存管理-Java内存区域与内存溢出异常

    摘要: JVM内存的划分,导致内存溢出异常的可能区域. 1. JVM运行时内存区域 JVM在执行Java程序的过程中会把它所管理的内存划分为以下几个区域: 1.1 程序计数器 程序计数器是一块较小的内 ...

  8. memcached整理の内存管理及删除机制

    内存的碎片化 如果用C语言直接malloc,free来向操作系统申请和释放内存时,在不断申请和释放的过程中,形成了一些很小的内存片段,无法再利用.这种空闲但无法利用内存的现象称为内存的碎片化. sla ...

  9. memcached 的内存管理与删除机制

    1:内存的碎片化 如果用 c 语言直接 malloc,free 来向操作系统申请和释放内存时, 在不断的申请和释放过程中,形成了一些很小的内存片断,无法再利用. 这种空闲,但无法利用内存的现象,--- ...

随机推荐

  1. Python爬虫与反爬虫(7)

    [Python基础知识]Python爬虫与反爬虫(7) 很久没有补爬虫了,相信在白蚁二周年庆的活动大厅比赛中遇到了关于反爬虫的问题吧 这节我会做个基本分享. 从功能上来讲,爬虫一般分为数据采集,处理, ...

  2. [转]RobotFrameWork+APPIUM实现对安卓APK的自动化测试----第一篇【安装】

    前言:关于RobotFrameWork+APPIUM实现对安卓APK的自动化测试的文章都是取自于乐于分享知识于网络的好心人们,所以我也希望我的知识可以分享给大家. 首先我们先罗列一下我们要安装的软件 ...

  3. .NET工程师 技能清单

    第一次写博客,先说自己对自己的职业定位.NET全栈跨语言工程师 .首先说明自己是微软的狂热粉丝,几乎所有技术都在.NET下进行. 接下来对微软目前的.NET上的技术进行进一步了解,列出一个清单或者说是 ...

  4. 城市规模越大,工资、GDP、犯罪率越高:4.5星|《规模》

    规模 信息浓度非常高的一本书.篇幅也不小,纸书有568页,致谢与注释只占7%. 全书讲各种复杂的东西中存在的普遍规律:哺乳动物体重每增加一倍,心率降低25%:城市人口每增加一倍,加油站只增加85%:城 ...

  5. cinder的组件

    跟nova相似,cinder也有很多组件,每个组件负责各自的业务,然后共同协作完成volume的管理.组件之间的通信方式与nova个组件之间的通信方式相同,都是通过消息队列进行通信. cinder-a ...

  6. java之接口开发-初级篇-socket通信

    socket通信实现util包类实现 public class SocketThread extends Thread { public void run() { while (true) { // ...

  7. 改进意见的答复及bug重现

    各组对本组的互评链接如下 Thunder:http://www.cnblogs.com/vector121/p/7905300.html 王者荣耀交流协会:http://www.cnblogs.com ...

  8. 软工1816 · Alpha冲刺(7/10)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 学会了POSTMAN的使用,对后端已经完成的接口进行了收发消息正确性的验证 推 ...

  9. GIT团队实战

    项目要求 组长博客 遇到的困难及解决办法 组员1(组长):王彬 遇到的困难  在团队任务分工的时候没有充分照顾到所有人,导致队员们的工作量不均. 现场编程时间不够 解决办法 在此对组员们表示抱歉,由于 ...

  10. 线段树---成段更新hdu1698 Just a Hook

    hdu1698 Just a Hook 题意:O(-1) 思路:O(-1) 线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息) 题意:给一组棍子染色,不同 ...