MapReduce&Yarn增强

1. MapReduce并行度机制详解

MapReduce&Yarn增强_第1张图片

maptask并行度机制 : 逻辑规划 (逻辑切片)

时间 : 客户端提交mr程序之前 main(客户端) , job.submit()

地点 : 客户端

参与者 : 待处理数据目录 FileInputFormat.getSplits()

规则 : 对待处理目录下逐个遍历文件 , 以切片大小对文件进行逻辑规划

​ split size == block size ==128M

结果 : 把形成的规划信息写在文件中 job.split

​ 随着客户端提交程序 , 把规划文件提交yarn指定的路径下

问题1 : 如何决定分片大小的 ?

查看源码TextInputFormat中FileInputFormat中的getSplits()中的computeSplitSize()方法

Math.max(minSize, Math.min(maxSize, blockSize))
minSize 默认为1 
blockSize 默认为128M
maxSize 是Long.max

既然切片大小可以通过参数修改决定 , 有一个方向尽量保证split size == block size

特殊1 : 小文件 , 如果存储了许多小文件该怎么办 ?

由于一个文件在小我们也需要用一个切片来进行存储 , 因此就会占用nn很大一部分内存

解决办法 :

  • hdfs 的shell命令中的appendToFile()
  • 本地java IO进行小文件合并
  • 修改默认规则 , 源码 , combineInputFormat

我们一般先在本地把小文件合并成大文件(最好是block size)

特殊2 : 文件特别大

当文件特别大时 , 我们又该怎么去处理 ?

解决方案 : 改变hdfs上block size 256M 512M , 这时候默认切片大小等于block size , dfs.blicksize

特殊3 : 当文件大小刚刚超过128M , 怎么处理 ?

bytesRemaining)/splitSize > SPLIT_SLOP(1.1即超过10%才进行分片)
剩下未切的/切片大小 > 1.1  如果满足 , 继续切
						如果不满足 , 剩下的全部作为最后一个切片
如 : 129/128 = 1.0078 < 1.1129M作为一个切片

特殊4 : 当数据在一部分在上一个切片的最后一行 , 另一部分在下一个切片的最上面一行时怎么办 ?

由于hdfs在存储文件的时候不会考虑数据的完整性 , 只要够128M就切一刀 , 因此

只能在mr读数据的层面解决 :

每个maptask都多读取下一个切片的第一行

如果maptask不是第一个 , 都舍弃自己的第一行 , 从第二行读取

特殊5 : 如果切片大小就是不等于block大小 , 怎么办 ?

如果切片大小不等于block大小 , 意味着有的文件需要跨块读取 , 相对麻烦

2. Reducetask并行度机制

Reducetask 数量的决定是可以直接手动设置 : job.setNumReduceTasks(4) , 如果分布不均匀 , 就可能产生数据倾斜

MapReduce&Yarn增强_第2张图片

当数据产生倾斜 , 怎么处理?

  • 把倾斜的数据单独拉取处理 , 单独处理(有充足的服务器资源)
  • 把倾斜的分开 , 哈希打散
    • 根据数据倾斜量评估一个打散数N(可以根据比例来确定N)
    • 在之前的数据旧key上依次凭借N形成新的key

具体操作可以看上图演示

注意 : reducetask 数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需要计算全局汇总结果,就只能有 1 个 reducetask。

3. Task并行度经验之谈

如何评估每个task执行的时间

  • 重写父类的 setup cleanUp 通过两者时间查进行评估

最终方向 : 最好每个task的执行事件至少一分钟==>可以在setup()初始化方法中增加开始时间 , cleanup()结束方法中增加结束时间 , 两者进行相减获得task执行时间

由于map或reduce task申请资源都需要耗费很大一部分时间 , 若执行时间较短, 很快就结束了 , 如果在需要又得申请资源 , 导致申请资源的时间过于多 , 而运行的时间太短 , 性能浪费太大 .

4. MapReduce 工作机制详解

4.1 MapTask 工作

MapReduce&Yarn增强_第3张图片

  • 读取数据组件InputFormat(默认TextInputFormat)会通过getSplits方法对输入目录中文件进行逻辑切片规划得到splits , 有多少个 split 就对应启动多少个 MapTask。split 与 block 的对应关系默认是一对一。

  • 将 输 入 文 件 切 分 为 splits 之 后 , 由 RecordReader对 象 ( 默 认LineRecordReader)进行读取,以\n 作为分隔符,读取一行数据,返回。Key 表示每行首字符偏移值,value 表示这一行文本内容

  • 读取 split 返回,进入用户自己继承的 Mapper 类中,执行用户重写的 map 函数。RecordReader 读取一行这里调用一次。

  • map 逻辑完之后,将 map 的每条结果通过 context.write 进行 collect 数据收集。在 collect 中,会先对其进行分区处理,默认使用 HashPartitioner

    MapReduce 提供 Partitioner 接口,它的作用就是根据 key 或 value 及 reduce 的数量来决定当前的这对输出数据最终应该交由哪个 reduce task 处理。默认对 key hash 后再以reduce task 数量取模。默认的取模方式只是为了平均 reduce 的处理能力,如果用户自己对 Partitioner 有需求,可以订制并设置到 job 上。

  • 接下来,会将数据写入内存,内存中这片区域叫做环形缓冲区,缓冲区的作用是批量收集 map 结果,减少磁盘 IO 的影响。我们的 key/value 对以及Partition 的结果都会被写入缓冲区。当然写入之前,key 与 value 值都会被序列化成字节数组。

    环形缓冲区其实是一个数组 , 默认大小是100M , 当数据达到80%是开始溢出(即开始写入磁盘)

  • 当溢写线程启动后,需要对这 80MB 空间内的 key 做排序(Sort)。排序是MapReduce 模型默认的行为,这里的排序也是对序列化的字节做的排序。

  • 每次溢写会在磁盘上生成一个临时文件 , 当整个数据处理结束之后开始对磁盘中的临时文件进行merge 合并,因为最终的文件只有一个,写入磁盘,并且为这个文件提供了一个索引文件,以记录每个 reduce 对应数据的偏移量。

4.2 ReduceTask工作机制

MapReduce&Yarn增强_第4张图片

Reduce 大致分为copy、sort、reduce三个阶段,重点在前两个阶段。copy阶段包含一个eventFetcher来获取已完成的map列表 , 由Fetcher线程去copy数据 , 会启动inMemoryMerger 和onDiskMerger,分别将内存中的数据 merge到磁盘和将磁盘中的数据进行 merge。待数据copy完成之后 , copy阶段完成 , 进行sort阶段 , sort阶段主要是执行finalMerge操作 , 纯粹的sort阶段 , 完成之后就是reduce阶段 , 调用用户定义的reduce函数进行处理.
MapReduce&Yarn增强_第5张图片

由上图可以得出 , 合并分为三种情况 :

  • 内存到内存 , 默认不采用
  • 内存到磁盘
  • 磁盘到磁盘

4.3 Shuffle机制

map 阶段处理的数据如何传递给reduce 阶段,是 MapReduce 框架中最关键的一个流程,这个流程就叫 shuffle

shuffle: 洗牌、发牌——(核心机制:数据分区,排序,合并)。

MapReduce&Yarn增强_第6张图片

shuffle 是 Mapreduce 的核心,它分布在 Mapreduce 的 map 阶段和 reduce阶段。一般把从 p Map 产生输出开始到 e Reduce 取得数据 作为输入 之前 的过程 称作 作 shuffle

MapReduce&Yarn增强_第7张图片

MapReduce&Yarn增强_第8张图片

5. MapReduce优化参数

5.1 资源相关参数

以下参数是在用户自己的 MapReduce 应用程序中配置就可以生效

  • mapreduce.map.memory.mb : 一个 Map Task 可使用的内存上限(单位:MB),默认为1024。如果 Map Task 实际使用的资源量超过该值,则会被强制杀死。
  • mapreduce.reduce.memory.mb : 一个 Reduce Task 可使用的资源上限(单位:MB),默认为 1024。如果 Reduce Task 实际使用的资源量超过该值,则会被强制杀死。
  • mapreduce.map.cpu.vcores : 每个 Maptask 可用的最多 cpu core 数目, 默认值: 1
  • mapreduce.reduce.cpu.vcores : 每个 Reducetask 可用最多 cpu core 数目默认值: 1
  • mapreduce.map.java.opts : Map Task 的 JVM 参数,你可以在此配置默认的 java heap size 等参数, 例如:“-Xmx1024m -verbose:gc -Xloggc:/tmp/@[email protected]”(@taskid@会被 Hadoop 框架自动换为相应的 taskid), 默认值: “”
  • mapreduce.reduce.java.opts : Reduce Task 的 JVM 参数,你可以在此配置默认的 java heap size 等参数, 例如:“-Xmx1024m -verbose:gc -Xloggc:/tmp/@[email protected]”, 默认值: “”

应该在 yarn 启动之前就配置在服务器的配置文件中才能生效

  • yarn.scheduler.minimum-allocation-mb : RM 中每个容器请求的最小配置,以 MB 为单位,默认 1024。
  • yarn.scheduler.maximum-allocation-mb : RM 中每个容器请求的最大分配,以 MB 为单位,默认 8192。
  • yarn.scheduler.minimum-allocation-vcores 1
  • yarn.scheduler.maximum-allocation-vcores 32
  • yarn.nodemanager.resource.memory-mb 表示该节点上YARN可使用的物理内存总量,默认是 8192(MB),注意,如果你的节点内存资源不够 8GB,则需要调减小这个值,而 YARN不会智能的探测节点的物理内存总量。

shuffle 性能优化的关键参数,应在 yarn 启动之前就配置好

  • mapreduce.task.io.sort.mb 100 shuffle 的环形缓冲区大小,默认 100m
  • mapreduce.map.sort.spill.percent 0.8 环形缓冲区溢出的阈值,默认 80% , 即达到80%就溢出

shuffle是一个过程 , 描述了mr中maptask的数据如何交给reducetask处理之前的种种阶段。

从maptask输出数据到内存缓冲区开始 到reducetask取得数据进行reduce聚合之前

  • shuffle是mr中核心过程 属于map阶段的主要步骤:数据分区进入内存缓冲区、数据溢出、数据合并
  • 属于reduce阶段主要步骤:拉取数据、数据合并、数据排序分组

在shuffle的过程中,涉及了数据内存到磁盘 、磁盘到内存、内存再到磁盘的过程、所以十分耗时 性能不高
MapReduce&Yarn增强_第9张图片

见以前的图 , 我们可以看到shuffle的工作位置

5.2 容错相关参数

  • mapreduce.map.maxattempts : 每个 Map Task 最大重试次数,一旦重试参数超过该值,则认为 Map Task 运行失败,默认值:4。
  • mapreduce.reduce.maxattempts : 每个Reduce Task最大重试次数,一旦重试参数超过该值则认为 Map Task 运行失败,默认值:4。
  • mapreduce.map.failures.maxpercent : 当失败的 Map Task 失败比例超过该值,整个作业则失败,默认值为 0.
  • mapreduce.reduce.failures.maxpercent : 当失败的 Reduce Task 失败比例超过该值为,整个作业则失败,默认值为 0.
  • mapreduce.task.timeout : 如果一个task在一定时间内没有任何进入,即不会读取新的数据,也没有输出数据,则认为该 task 处于 block 状态,可能是临时卡住,也许永远会卡住。为了防止因为用户程序永远 block 不退出,则强制设置了一个超时时间(单位毫秒),默认是600000,值为 0 将禁用超时。

5.3 效率跟稳定性参数

  • mapreduce.map.speculative : 是否为 Map Task 打开推测执行机制,默认为 true, 如果为 true,则可以并行执行一些 Map 任务的多个实例。
  • mapreduce.reduce.speculative : 是否为 Reduce Task 打开推测执行机制,默认为 true
  • mapreduce.input.fileinputformat.split.minsize: FileInputFormat做切片时最小切片大小,默认 1。
  • mapreduce.input.fileinputformat.split.maxsize : FileInputFormat做切片时最大切片大小

推测执行机制(Speculative Execution):它根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。(通过算法找出拖后腿的短板任务,为其启动备份任务,备份任务跟原任务一模一样,最终谁先处理完,谁的结果就作为最终结果。)

6. MapReduce其他功能

  • 6.1 计数器应用

MapReduce 计数器(Counter)为我们提供一个窗口,用于观察 MapReduce Job 运行期的各种细节数据。

内置计数器包括:

​ 文件系统计数器(File System Counters)
​ 作业计数器(Job Counters)
​ MapReduce 框架计数器(Map-Reduce Framework)
​ Shuffle 错误计数器(Shuffle Errors)
​ 文件输入格式计数器(File Output Format Counters)
​ 文件输出格式计数器(File Input Format Counters)

Hadoop也支持自定义计数-----全局计数 , 如果我们不自定义计数会造成线程的锁事务

mr自定义计数器 最大的用处在于 全局计数

Counter counter = context.getCounter("ItcastCounter", "helloCounter");
counter.increment(1);
public class WordCount{
	static class WordCount Mapper extends Mapper<LongWritable, Text, Text, 	LongWritable> {
	@Override
	protected void map(LongWritable key, Text value, Context context) throws IOException,InterruptedException {
		Counter counter =context.getCounter(“SelfCounters”,”myCounters”);
		String[] words = value.toString().split(",");
		for (String word : words) {
		if("hello".equals(word)){counter.increment(1)};
		context.write(new Text(word), new LongWritable(1));
		}
	}
}

7. Apache Hadoop YARN

MapReduce&Yarn增强_第10张图片

Apache Hadoop YARN (Yet Another Resource Negotiator,另一种资源协调者)是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统和调度平台,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处。

可以把 yarn 理解为相当于一个分布式的操作系统平台,而 mapreduce 等运算程序则相当于运行于操作系统之上的应用程序,Yarn 为这些程序提供运算所需的资源(内存、cpu)

  • yarn 并不清楚用户提交的程序的运行机制

  • yarn 只提供运算资源的调度(用户程序向 yarn 申请资源,yarn 就负责分配资源)

  • yarn 中的主管角色叫 ResourceManager

  • yarn 中具体提供运算资源的角色叫 NodeManager

  • yarn与运行的用户程序完全解耦,意味着yarn上可以运行各种类型的分布式运算程序,比如 mapreduce、storm,spark,tez ……

  • spark、storm 等运算框架都可以整合在 yarn 上运行,只要他们各自的框架中有符合yarn 规范的资源请求机制即可

  • yarn 成为一个通用的资源调度平台.企业中以前存在的各种运算集群都可以整合在一个物理集群上,提高资源利用率,方便数据共享

7.1 Yarn基本架构

MapReduce&Yarn增强_第11张图片

YARN 是一个资源管理、任务调度的框架,主要包含三大模块:ResourceManager(RM)、NodeManager(NM)、ApplicationMaster(AM)。

​ ResourceManager 负责所有资源的监控、分配和管理;
​ ApplicationMaster 负责每一个具体应用程序的调度和协调;
​ NodeManager 负责每一个节点的维护。

对于所有的 applications,RM 拥有绝对的控制权和对资源的分配权。而每个 AM 则会和RM 协商资源,同时和 NodeManager 通信来执行和监控 task。

7.2 Yarn三大组件介绍

  • ResourceManager
    • ResourceManager(RM) 主角色 负责整个集群的资源管理和分配,是一个全局的资源管理系统。
    • NodeManager(NM) 以心跳的方式向 ResourceManager 汇报资源使用情况(目前主要是 CPU 和内存的使用情况)。RM 只接受 NM 的资源回报信息,对于具体的资源处理则交给 NM 自己处理。
    • YARN Scheduler 根据 application 的请求为其分配资源,不负责 application job 的监控、追踪、运行状态反馈、启动等工作。
  • NodeManager
    • NodeManager(NM) 从角色 是每个节点上的资源和任务管理器,它是管理这台机器的代理,负责该节点程序的运行,以及该节点资源的管理和监控。
    • NodeManager 定时向 ResourceManager 汇报本节点资源(CPU、内存)的使用情况和Container 的运行状态。当 ResourceManager 宕机时 NodeManager 自动连接 RM 备用节点。
    • NodeManager 接收并处理来自 ApplicationMaster 的 Container 启动、停止等各种请求。
  • ApplicationMaster (AM) 应用程序的大哥 负责yarn上每个程序内部的管理调度 负责向RM申请资源
    • 用户提交的每个应用程序均包含一个ApplicationMaster ,它可以运行在ResourceManager 以外的机器上。
    • 负责与 RM 调度器协商以获取资源(用 Container 表示)
    • 将得到的任务进一步分配给内部的任务(资源的二次分配)
    • 与 NM 通信以启动/停止任务
    • 监控所有任务运行状态,并在任务运行失败时重新为任务申请资源以重启任务
    • 当前 YARN 自带了两个 ApplicationMaster 实现,一个是用于演示 AM 编写方法的实例程序 DistributedShell,它可以申请一定数目的 Container 以并行运行一个 Shell 命令或者 Shell 脚本;另一个是运行 MapReduce 应用程序的 AM—MRAppMaster。

注 :RM 只负责监控 AM,并在 AM 运行失败时候启动它。RM 不负责 AM 内部任务的容错,任务的容错由 AM 完成。

在这种机制下,任何程序在yarn上执行变成如下模式:

  • 首先申请资源用于运行自己程序的老大ApplicationMaster(对于mr类型的程序,有默认的具体实现MRAppMaster)
  • 其实再是由ApplicationMaster继续申请资源用于程序后续的执行

7.3 Yarn 运行流程

MapReduce&Yarn增强_第12张图片

由上图我们得知mr提交yarn的交互流程

  • 客户端请求运行程序 hadoop jar wordcount.jar xxx
  • 检查申请是否符合运行的需求 , 生成一个jobid , 提交资源的路径
  • 返回给客户端
  • 请求资源用于运行本次程序的applicationMaster(MrAppMaster)
  • RM收到请求 , 并且通过NM返回一个可用的资源容器所在的机器位置NM1
  • 返回地址
  • 客户端到指定的机器容器里启动本次程序的MrAPPMaster , 申请对应的container
  • MrAPPMaster启动成功之后向RM注册自己 , 并且保存通信
  • MrAppMaster通过读取本次任务切片信息 , 向RM申请对应数量的容器用于运行MapTask , 比如切片数3
  • 向RM申请资源运行MapTask
  • RM接收到请求 , 并且通过NM返回与申请数量对应的资源容器位置(NM1,NM2,NM2)
  • 返回给MrAppMaster
  • MrAppMaster到返回的容器里启动MapTask , 并且追踪task的执行情况
  • maptask运行结束 , MrAppMaster向RM申请 , 容器资源使用完毕 , 请注销
  • 如果程序还有下一个阶段ReduceTask , MrAppMaster继续去申请容器资源
  • 当所有的task执行完毕 , MrAppMaster向RM申请注销自己 , 收回资源

官方语言解释

  • client 向 RM 提交应用程序,其中包括启动该应用的 ApplicationMaster 的必须信息,例如 ApplicationMaster 程序、启动 ApplicationMaster 的命令、用户程序等。

  • ResourceManager 启动一个 container 用于运行 ApplicationMaster。

  • 启动中的 ApplicationMaster 向 ResourceManager 注册自己,启动成功后与 RM 保持心跳。

  • ApplicationMaster 向 ResourceManager 发送请求,申请相应数目的 container。

  • ResourceManager 返回 ApplicationMaster 的申请的 containers 信息。申请成功的container,由 ApplicationMaster 进行初始化。container 的启动信息初始化后,AM与对应的 NodeManager 通信,要求 NM 启动 container。AM 与 NM 保持心跳,从而对 NM上运行的任务进行监控和管理

  • container 运行期间,ApplicationMaster 对 container 进行监控。container 通过 RPC
    协议向对应的 AM 汇报自己的进度和状态等信息。

  • 应用运行期间,client 直接与 AM 通信获取应用的状态、进度更新等信息。

  • 应用运行结束后,ApplicationMaster 向 ResourceManager 注销自己,并允许属于它的
    container 被收回。

7.4 Yarn调度Scheduler

Yarn 中,负责给应用分配资源的就是 Scheduler

在Yarn中有三种调度器可以选择:FIFO Scheduler,Capacity Scheduler,FairScheduler

  • FIFO Scheduler

    FIFO Scheduler 把应用按提交的顺序排成一个队列,这是一个 先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。就一个通道 , 先进先出 , 如果前面有耗时的大队列 , 会造成阻塞

MapReduce&Yarn增强_第13张图片

  • Capacity Scheduler

    Capacity 调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。分为大和小的两个通道 , 当小的多时 , 大的通道利用较低 , 因此造成资源利用不合理

MapReduce&Yarn增强_第14张图片

  • Fair Scheduler

    Fair 调度器会为所有运行的job 动态的调整系统资源。

    会动态的调整 , 但是当程序申请停止某些资源 , 在执行小文件 , 这时候是很费性能的

MapReduce&Yarn增强_第15张图片

示例:Capacity 调度器 配置使用

调度器的使用是通过 yarn-site.xml 配置文件中的
yarn.resourcemanager.scheduler.class 参数进行配置, 默认采用 CapacityScheduler 调度器。假设我们有如下层次的队列:

root
├── prod
└── dev
├── mapreduce
└── spark

文件名为 capacity-scheduler.xml

<configuration>
    <property>
    <name>yarn.scheduler.capacity.root.queuesname>
    <value>prod,devvalue>
    property>
    <property>
    <name>yarn.scheduler.capacity.root.dev.queuesname>
    <value>mapreduce,sparkvalue>
    property>
    <property>
    <name>yarn.scheduler.capacity.root.prod.capacityname>
    <value>40value>
    property>
    <property>
    <name>yarn.scheduler.capacity.root.dev.capacityname>
    <value>60value>
    property>
    <property>
    <name>yarn.scheduler.capacity.root.dev.maximum-capacityname>
    <value>75value>
    property>
    <property>
    <name>yarn.scheduler.capacity.root.dev.mapreduce.capacityname>
    <value>50value>
    property>
    <property>
    <name>yarn.scheduler.capacity.root.dev.spark.capacityname>
    <value>50value>
    property>
configuration>

​ 我们可以看到,dev 队列又被分成了 mapreduce 和 spark 两个相同容量的子队列。dev的 maximum-capacity 属性被设置成了 75%,所以即使 prod 队列完全空闲 dev 也不会占用全部集群资源,也就是说,prod 队列仍有 25%的可用资源用来应急。我们注意到,mapreduce和 spark 两个队列没有设置 maximum-capacity 属性,也就是说 mapreduce 或 spark 队列中的 job 可能会用到整个 dev 队列的所有资源(最多为集群的 75%)。而类似的,prod 由于没有设置 maximum-capacity 属性,它有可能会占用集群全部资源。

​ 关于队列的设置,这取决于我们具体的应用。比如,在 MapReduce 中,我们可以通过mapreduce.job.queuename 属性指定要用的队列。如果队列不存在,我们在提交任务时就会收到错误。如果我们没有定义任何队列,所有的应用将会放在一个 default 队列中。

​ 注意 : 对于 Capacity 调度器,我们的队列名必须是队列树中的最后一部分,如果我们使用队列树则不会被识别。

  • 动态平衡点
/root
	/prod   40%
	/dev    60%   --->75%
蚕食

当集群设置队列以后 提交mr程序需要指定队列名
队列名必须是队列树中的最后一部分
mapreduce.job.queuename = /root/dev/mapreduce   xxxxx
mapreduce.job.queuename = mapreduce    对
mapreduce.job.queuename = prod         对

你可能感兴趣的:(大数据,MapReduce,yarn)