MR调优实战

本文将从资源分配和Shuffle调优两方面进行调优。

一、资源分配:

在调优资源分配之前,需要先了解一下yarn的资源分配流程。

如何给一个MR任务分配资源将大大影响其运行性能。常用的资源参数有:

  • ① yarn.nodemanager.resource.memory-mb:nodemanager内存资源总大小,节点能够使用的最大内存。可以在yarn的web ui中的activenodes里面看到的每个节点的内存总大小就是这个值。该值需要小于实际的机器物理内存。
  • ② yarn.scheduler.minimum-allocation-mb:单个container申请的最小内存,如果是容量调度or先进先出,该参数还是规整化因子(公平调度规整化因子是yarn.scheduler.increment-allocation-mb)。
  • ③ yarn.scheduler.maximum-allocation-mb:单个container申请的最大内存
  • ④ yarn.nodemanager.pmem-check-enabled:是否开启物理内存监控。如果关闭,任务在实际运行过程中可以使用最大限度的内存,如果有大任务,很可能会占用完整个机器的内存,导致卡死。不建议关闭。
  • ⑤ yarn.nodemanager.vmem-check-enabled:是否开启虚拟内存监控(虚拟空间就是利用磁盘空间 逻辑上充当 物理内存,内存变大了,但是虚拟内存访问是比较物理内存慢的)。
  • ⑥ yarn.nodemanager.vmem-pmem-ratio:虚拟内存 - 物理内存比。
  • ⑦ mapreduce.map.memory.mb:map任务占用内存。
  • ⑧ mapreduce.reduce.memory.mb:reduce任务占用的内存。一般这是为2倍mapreduce.map.memory.mb
  • ⑨ mapreduce.map.java.opts:map任务中,启动的处理任务中的jvm参数。一般设置堆栈值,gc参数等。比如-Xmx2048m。这里需要说明一下,启动的处理任务的堆栈大小默认是任务内存的80%
  • ⑩ mapreduce.reduce.java.opts:同mapreduce.map.java.opts,只不过是reduce任务。
  • ⑪ mapred.max.split.size:map任务处理的split最大值。当map读取大文件时,会将大文件按照mapred.max.split.size并以blocksize为单位切分。比如该值设为1G,当处理2.3G的大文件时,会生成两个1G的split,并产生对应的两个map,剩下0.3G暂时保留(0.3G还要和min做比较)。
  • ⑫ mapred.min.split.size.per.node:每个节点的最小split大小,节点先会按照max split进行切分,然后把剩余不足max的数据,再和min比较,如果大于min,则为其单独生成map处理。否则保留。
  • ⑬ mapred.min.split.size.per.rack:由于max和min split设置的原因,每个node可能会有保留的小数据未分配map处理。此时会将相同rack的node的保留数据进行合并,如果小于该值,则保留,否则合并成一块数据,为其创建map处理。(经过rack合并之后,如果还有保留的数据,最后将全部合并,为其创建map处理。)

参数1-6是针对yarn的设置。参数1是告诉集群本节点有多少内存资源。2和3设置单个container能够申请到的最小最大内存。4是是否物理开启内存监控,监控container实际占用内存是否超标,超标则直接kill掉。5和6分别设置虚拟内存监控开关以及虚拟内存大小。

参数7-10是设置mr内存的,oom了可以调大,想提高并发,可以调小。11-13是设置map处理的split大小的,单个map运行时间才几十秒,说明这个map处理的数据比较小,可以增大split,让单个map处理数据更大,运行更长,当热因为单个map处理的数据变大了,总的map数就降低了。

注意:7-10中的参数中,设置的jvm对大小一定要小于对应任务分配的内存。

  • mapreduce.map.memory.mb > mapreduce.map.java.opts
  • mapreduce.reduce.memory.mb > mapreduce.reduce.java.opts

原因:以map为例,map任务执行中,除开开启java进程处理程序外,还有额外的一些工作需要内存。换而言之:mapreduce.map.java.opts + 其他 = mapreduce.map.memory.mb。如果设置的mapreduce.map.java.opts中的最大内存>=mapreduce.map.memory.mb了,说明允许堆栈增长内存大于mapreduce.map.memory.mb,一般而言是会开启yarn.nodemanager.pmem-check-enabled的,当发现总的内存值大于了mapreduce.map.memory.mb,就会kill掉该map,报错oom。报错信息:

Current usage: 4.4 GB of 4 GB physical memory used; 12.2 GB of 32 GB virtual memory used. Killing container

二、shuffle调优:

想要对shuffle操作进行调优,首先的了解shuffle的流程。

在了解了MR shuffle流程之后,只需要对shuffle流程中各个环节的参数进行适当配置,就能有效加速shuffle的执行过程。shuffle过程中常用性能参数:

  • ① mapreduce.task.io.sort.mb:map任务在shuffle_write阶段的buffer大小,默认100M。
  • ② mapreduce.map.sort.spill.percent:map任务在shuffle_write阶段,当写入buffer达到一定比例会进行spill溢写。默认0.8。
  • ③ mapreduce.task.io.sort.factor:map任务shuffle_write阶段,可能会溢写很多的文件,势必会产生很多小文件,这个时候就需要合并这些小文件。该参数就规定每次合并小文件的个数。
  • ④ mapreduce.map.combine.minspills:在合并spill文件时,如果设置了combiner同时spill文件数大于该值,在合并过程中还会触发combiner,从而减少最终输出的文件大小。
  • ⑤ mapreduce.reduce.shuffle.parallelcopies:在reduce的shuffle_read阶段,会从上游map任务copy数据。该值是copy操作的线程数,默认5。
  • ⑥ mapreduce.reduce.shuffle.input.buffer.percent:reduce的shuffle_read阶段,copy的数据都会放在缓冲区中。该值设置了buffer占用的内存比例,默认0.7。
  • ⑦ mapreduce.reduce.shuffle.merge.percent:reduce的copy缓冲区达到一定比例,将会溢写本地磁盘。默认0.66

三、调优实战(一次帮助用户调优的经历)

用户场景是离线计算一些报表数据,通过hive启动mr任务计算存放于cos上的数据。其中有一条sql计算的数据量大概有1T左右。期初不经过任何调优的情况下,用户任务执行时间长达一下午,无论如何这都是无法容忍的,于是用户希望我们能够帮助进行性能上的调优。用户的集群统一由16核-32G的CVM,共计17台组成(其中 core 12台,master 2台,common 3台, task 0台,执行计算任务的就是其中的12台core和0台task)。

先来说说其中某些现象:

  1. 通过yarn web ui查看activenodes的资源情况,发现每个节点上yarn的最大使用内存是28.8G,vcore是16核,可以猜到yarn.nodemanager.resource.memory-mb值就是28.8G(自行换算成MB单位)。这个值没有设置成机器的最大内存数,是正确的,防止占用全部机器内存,导致机器内存负载过高出现卡死的现象。
  2. 任务执行中,发现acivenodes的资源情况中,每个node的内存都剩余有8G多的内存。
  3. 任务执行中,发现map数量为4000+,reduce数量为1000+
  4. 任务执行中,发现同时为running状态map数只有8左右,reduce数量也只有8左右。
  5. 任务执行中,查看已经完成的map用时,普遍在50s-1min之间。

分析:

  1. 现象2说明集群资源利用不够充分,有剩余资源无法分配。需要想办法分配该部分剩余资源
  2. 现象3、现象4和现象5说明,4000个map,map并发8,每个map大概1分钟(分配资源给map执行时,会有额外时间开销),来算算执行完所有map的用时4000/8 * 1min = 500分钟,尼玛!这TM不止一下午,是要一天的节奏啊。问题有以下几点:
  • map并发太低了。这里就会有疑问,为什么有剩余的内存资源,不分配给map执行呢?答:我看了map任务的内存分配是10G。对,没错,是10G,晕死!reduce分配的20G,这个可以理解,reduce内存一般是map的两倍,但尼玛也太高了吧。现象2里面每个节点剩余8G内存,要想分配一个map来执行,当然分配不出来啦,所以通通给我pending住,只准同步运行可怜的几个map。说到这,解决办法大家可能想到了,没错!就是降低map和reduce的内存分配!从而让集群可以同时运行更多的任务。那到底并发数多少最理想呢?当然是vcore的2-3倍(假设一个任务只占用1核),可能会想问,为什么是2-3倍呢?你想想任务并发等于vcore是最理想的,但是哪个任务没有点IO等待的情况,等IO的时间就可以切换另一个任务来执行卅。当然太多也不好,频繁切换任务的话,因为切换本身是有时间损耗的。所以就2-3倍了!
  • 每个map才执行1分钟,分配资源给map执行的过程都需要几秒钟,额外时间消耗占比太高了(假设任务执行只需要55秒,但是为了执行这个map,要分配资源给它,中间过程就需要5S)。一般会把任务的执行时间控制在5分钟左右。过长说明要么任务有问题,要么单个任务执行的数据太多了,不合理。
  • map总数量过高。可以通过设置split来降低map总数,这样为map分配资源的次数就会减少,分配过程的时间就节约了。

经过一定量的分析,大概知道了需要调整哪些参数来提高任务运行速度。于是帮用户设置了一些参数来运行任务。之前运行需要4-5小时的任务,最后浓缩到了30分钟。

调整参数:

mapreduce.reduce.java.opts=-Xmx6600m; mapreduce.map.java.opts=-Xmx2500m; mapreduce.reduce.memory.mb=6144; mapreduce.map.memory.mb=3072; mapreduce.task.io.sort.mb=512; // 这个参数是为了让溢写的时候少点IO次数,其实还可以调大 mapred.max.split.size=1024000000; mapred.min.split.size.per.node=1024000000; mapred.min.split.size.per.rack=1024000000;

这里设置每个map处理的split最大大小是1G,但是我设置的map堆栈有2G+,原因很简单,处理输入是1G,万一代码中还有各种变化,中间数据之类的,1G堆栈肯定不够啊,反正内存够用,多来点呗,不然OOM了就悲剧了。

其实上面的参数应该还可以调整以提高速度,同时还有一些GC方面的优化没有加进去(一般最后才会想到GC优化),还有代码优化也是重要的环节之一。

文中可能会有一些地方说的不清楚,或者说的不正确的地方,希望大家指点一二,谢谢!

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

架构师必读:Linux 的内存分页管理

内存是计算机的主存储器。内存为进程开辟出进程空间,让进程在其中保存数据。我将从内存的物理特性出发,深入到内存管理的细节,特别是了解虚拟内存和内存分页的概念。

1222
来自专栏西枫里博客

Ajax出错并返回整个页面html的问题

有这样一个例子在thinkPHP视图页面执行一个给评论点赞的功能,为了强化用户体验,一般都采用ajax异步请求后台处理点赞数据,成功后页面执行局部更新后的数据即...

1071
来自专栏安智客

Meltdown、Spectre攻击---CPU乱序执行和预测执行导致的安全问题

俄亥俄州立大学计算机安全实验室 ? 乱序执行(Out-of-Order Execution) [1] 和预测执行(Speculative Execution) ...

3749
来自专栏枕边书

PHP 调用 Go 服务的正确方式 - Unix Domain Sockets

问题 可能是由于经验太少,工作中经常会遇到问题,探究和解决问题的过程总想记录一下,所以我写博客经常是问题驱动,首先介绍一下今天要解决的问题: 服务耦合 我们在开...

34811
来自专栏清晨我上码

第九节 OAuth2

当然具体如何实现,用什么方式实现其实是无所谓,因为只要遵循上面定义的规则就可以。已经有很多造好的轮子了,我们拿过来用就好了,如果想要更深入的研究也可以自己尝试去...

1242
来自专栏Vamei实验室

Linux的内存分页管理

作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载

1682
来自专栏铭毅天下

干货 | 知识库全文检索的最佳实践

很多文档已经被转化成扫描版的PDF,之前我们认为PDF类型是最终的文档格式,现在看来,我们想听听建议(比如:xml是不是更好呢?)

1281
来自专栏智能计算时代

Envoy架构概览(6):异常检测

异常值检测和弹出是动态确定上游群集中的某些主机是否正在执行不同于其他主机的过程,并将其从正常负载平衡集中移除。 性能可能沿着不同的轴线,例如连续的故障,时间成功...

3836
来自专栏数据小魔方

左手用R右手Python系列——使用多进程进行任务处理

数据抓取中的密集任务处理,往往会涉及到性能瓶颈,这时候如果能有多进程的工具来进行支持,那么往往效率会提升很多。 今天这一篇分享在R语言、Python中使用调用多...

2799
来自专栏吕力的专栏

一种理解同步/异步,阻塞/非阻塞,Linux IO 模型,select /poll /epoll 的方法

强迫症不能忍受这种极其绕的概念而不给个说法,这些概念困扰我许久,下面给出这一阶段我个人的理解。

1.2K1

扫码关注云+社区

领取腾讯云代金券