yarn与zoomkeeper有什么样的关系?
Yarn的核心功能在于资源调度与管理,而ZooKeeper的核心功能在于分布式系统中的一致性服务。
Yarn:
Yarn是一个分布式资源调度器组件。这个组件的主要作用是在每次接收到请求后,会查看当下的各个子节点的状况,统筹出运算资源的调度方案来保证任务可以顺利执行。通常来说,Yarn所调度的资源常常包括磁盘空间的资源,内存的资源和通讯带宽的资源等。Yarn是Hadoop V2.0开始引入的一个组件,这个组件可以说是针对Hadoop1.0系统所爆露出的计算资源使用不合理等设计上的问题进行的修正和补充。
Zookeeper:
ZooKeeper是一个分布式的一致性服务组件。分布式系统最大的困难之处在于如何保证系统内各个节点服务器所操作或处理的数据是一致的,或者各自的配置信息是相同的,而ZooKeeper的价值就在于实现了基于分布式的统一化配置管理,命名服务,状态同步等
通俗理解:
Zookeeper和Yarn是一起工作的,它们一起管理资源。
举例说明:在一个分布式系统上。现在有个事要办。我们要找这个系统办这个事,就要通知yarn。打个比方,yarn的master node看看这个系统里有很多node,看看谁有空,谁有能力(cpu、内存、等)来干这个事。然后把任务分配给合适的node来办这个事。
这个时候系统面临一个危险。那就是在分布式系统中,failure成为常态。
yarn master node管理着很多个node,管理着它们哪一个出问题了。危险在于master自己坏了怎么办。
常见的分布式系统出问题的解决办法是我们总保持有一个待命的,到需要的时候顶上。yarn里的Resource Manager也有待命的。当一个Resource Manager坏了,或者需要升级更新,另一个Resource Manager要接手。这时候麻烦来了,新的Resource Manager怎么知道哪个任务已经完成,哪个还没有,用户想执行的任务到什么状态了,一个任务所必须的先决条件任务是否已经完成。
这个情形中,Yarn自己成了Single point of failure。 新启动的Resource Manager成了这个分布式系统的另外一个大脑。两个大脑管理同一套资源,就可能有不一致的地方。
要解决这个问题,我们就要保存Yarn自身的各种状态,比如都收到了哪些任务,各个任务都执行到了什么状态,收到了哪些安全许可。这些东西保存在Resource Manager State Store里。 Resource Manager State . Store自己怎么管理呢。好几种办法,存在内存,存在文件,或者另外一个更容易的办法就是Zookeeper了。
Zookeeper控制着什么时候,谁可以读写这个Resource Manager State Store.
Zookeeper自己也是个cluster,它也是Fault Tolerance(容错)的,我们就省去了自己管理这个资源的各种麻烦。
Zookeeper保存着它所管理的系统的各种状态,可以保证任何时候都只有一个版本的系统状态。即便是Yarn的Master坏了,重启了,正在升级,也不会出现冲突。所以说起来,Yarn和Zookeeper的功能是不一样的,对于一套完整的系统,两者都需要使用。
Yarn的三大组件
容器:
封装了一定数量的CPU、内存、磁盘等资源,从而限定每个应用程序可以使用的资源量
前三步: 提交代码、申请资源、App注册
RDD: Resilient Distrubuted Dataset
是分布式内存的抽象概念,提供了一种高度受限的共享内存模型
DAG : Directed Acyclic Graph 有向无环图
反映RDD之间的依赖关系
Executor:运行在工作节点Worker Node的一个进程,负责运行任务,并为应用程序存储数据
应用:Spark程序
任务:Execute上的工作单元
作业:一个作业包含多个RDD及作用于RDD上的各个操作
阶段Stage:作用的基本调度单位,一个作业会分为多组任务,每组任务被称为阶段
集群资源管理器
运行任务的工作节点
每个应用的任务控制节点
每个工作节点上负责具体任务的执行过程
优点:
当执行一个应用时,任务控制节点Driver会向集群管理器(Cluster Manager)申请资源,启动Executor,并向Executor发送应用程序代码和文件,然后在 Executor 上执行任务,运行结束后执行结果会返回给任务控制节点,或者写到HDFS或者其他数据库中
(1)当一个Spark应用被提交时,首先需要为这个应用构建起基本 的运行环境,即由任务控制节点(Driver)创建一个SparkContext,由 SparkContext负责和资源管理器(Cluster Manager)的通信以及进行资源的申请、任务的分配和监控等。SparkContext 会向资源管理器注册并申请运行Executor的资源。
(2)资源管理器为Executor分配资源,并启动Executor进程, Executor运行情况将随着“心跳”发送到资源管理器上。
(3)SparkContext 根据 RDD 的依赖关系构建 DAG 图,DAG 图提 交给 DAG 调度器(DAGScheduler)进行解析,将DAG图分解成多个 “阶段”(每个阶段都是一个任务集),并且计算出各个阶段之间的依 赖 关 系 , 然 后 把 一 个 个 “ 任 务 集 ” 提 交 给 底 层 的 任 务 调 度 器(TaskScheduler)进行处理;Executor 向 SparkContext 申请任务,任务调度器将任务分发给 Executor 运行,同时SparkContext将应用程序代码
发放给Executor。
(4)任务在Executor上运行,把执行结果反馈给任务调度器,然后反馈给DAG调度器,运行完毕后写入数据并释放所有资源。
概念:RDD是一个分布式对象集合,是一个只读的记录分区的集合。
何谓弹性?
存储的弹性:内存与磁盘的自动切换;
容错的弹性:数据丢失可以自动恢复;
计算的弹性:计算出错重试机制;
分片的弹性:可根据需要重新分片。
接收RDD,返回非RDD,一个值或者一个结果
RDD适合对数据集中元素执行相同操作的批式处理,粗粒度
RDD执行过程:
Spark会根据RDD的依赖关系生成DAG,从头开始计算
高容错:
中间结果持久化到内存
存放的数据可以是java对象,避免对象的序列化和反序列化开销
宽依赖
一个父分区对应多个子分区
窄依赖
一个父分区对应一个子分区,或者多个父分区对应一个子分区
map,filter,union
如果在应用程序中多次使用同一个 RDD,可以将该 RDD 缓存起来,该 RDD 只有在第一次计算的时候会根据血缘关系得到分区的数据,在后续其他地方用到该 RDD 的时候,会直接从缓存处取而不用再根据血缘关系计算,这样就加速后期的重用。
调度池
各个RDD的依赖关系生成了G,通过DAG来划分
如何划分呢?
在DAG中进行反向解析,遇到宽依赖就断开,遇到窄依赖就把当前的RDD加入到当前的阶段中,将窄依赖尽量划分在同一个阶段中可以实现流水线计算
Standalone模式(集群模式):
Spark框架自带完整的资源调度管理服务,可以独立的部署到一个集群中,不需要其他系统
Spark on Mesos:
Mesos是一个资源调度框架,比Yarn更灵活
Spark on Yarn:
资源管理和调度依赖YARN,分布式存储依赖HDFS
parallelize 和 makeRDD
val rdd = sc.parallelize(Array(1,2,3,4,5,6,7,8))
差异:makeRDD底层调用的是parallelize方法 ,makeRDD更好理解
makeRDD方法可指定并行分区数,默认为CPU最大的核数
读取文件:
textFile(path)
wholeTextFiles()
: 以文件为单位读取数据,元组的形式(path,text)
output文件:
数据是如何分配数据分区的?
数据如何切分?
len=5, partitionNum=3
for i 0 until partitionNum:
start = i * len / paratitionNum
end = (i+1) * len / paratitionNum
(start, end)
文件分区分配:
spark读取文件是按照hadoop的方式读取的,按行读取 ,和字节数没有关系
totalsize / ParatitionNum
大于10% ,产生新的分区
7 / 3 = 2 …1 > 1.1
所以 ParatitionNum = 2 + 1
数据读取时以偏移量为单位
数据分区的偏移量的范围计算(以偏移量为3为单位)
0 => [0,3]
1 => [3,6]
作用:将每一个分区形成一个数组,形成新的 RDD 类型时 RDD[Array[T]]
Spark 目前支持 Hash 分区和 Range 分区,Hash 分区为当前的默认分区,Spark 中分区器直接决定了 RDD 中分区的个数、RDD 中每条数据经过Shuffle 过程属于哪个分区和 Reduce 的个数
注意:
(1)只有 Key-Value 类型的 RDD 才有分区的,非 Key-Value 类型的 RDD 分区的值是 None
(2)每个 RDD 的分区 ID 范围:0~numPartitions-1,决定这个值是属于那个分区的。
数据格式是(key,value)类型
HashPartitioner 分区的原理:对于给定的 key,计算其 hashCode,并除以分区的个数取余,如果余数小于 0,则用余数+分区的个数(否则加 0),最后返回的值就是这个 key 所属的分区 ID。
map函数是一条数据一条数据的处理,也就是,map的输入参数中要包含一条数据以及其他你需要传的参数。
mapPartitions函数是一个partition数据一起处理,也即是说,mapPartitions函数的输入是一个partition的所有数据构成的“迭代器”,然后函数里面可以一条一条的处理,在把所有结果,按迭代器输出。也可以结合yield使用效果更优。
mapPartitionsWithIndex函数,其实和mapPartitions函数区别不大,因为mapPartitions背后调的就是mapPartitionsWithIndex函数,只是一个参数被close了。mapPartitionsWithIndex的函数可以或得partition索引号;
Spark SQL 是 Spark 用来处理结构化数据的一个模块,它提供了 2 个编程抽象:DataFrame 和 DataSet,并且作为分布式 SQL 查询引擎的作用。
与 RDD 类似,DataFrame 也是一个分布式数据容器。然而 DataFrame 更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即 schema。
Dataframe 是 Dataset 的特列,DataFrame=Dataset[Row] ,所以可以通过 as 方法将 Dataframe转换为 Dataset。Row 是一个类型,跟 Car、Person 这些的类型一样,所有的表结构信息我都用 Row
来表示。
RDD 通过 persist 方法或 cache 方法可以将前面的计算结果缓存,默认情况下 persist() 会把数据以序列化的形式缓存在 JVM 的堆空间中。
但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 时,该 RDD 将会被缓存在计算节点的内存中,并供后面重用。