Hadoop 调优

2021-12-13 11:50

HDFS 调优

hdfs-site.xml

1. hadoop 文件块大小,通常为 128MB 或 256MB
<property>
	<name>dfs.block.size</name>
    <value>134217728</value>
</property>

<!-- 134217728 B = 128 MB    268435456 B = 256 M -->
2. NameNode 同时和 DataNode 通信的线程数,默认为10,将其增大为40。
<property> 
    <name>dfs.namenode.handler.count</name> 
    <value>40</value>
</property> 
3. dfs.datanode.max.xcievers 对于 DataNode 来说就 如同 Linux 上的文件句柄的限制,当 DataNode上面的连接数超过配置中的设置时, DataNode就会拒绝连接,修改设置为65536。
<property> 
    <name>dfs.datanode.max.xcievers</name> 
    <value>65536</value>
</property> 
4. 执行 start-balancer.sh 的带宽,默认为1048576(1MB/s),将其増大到20MB/s
<property> 
    <name>dfs.datanode.balance.bandwidthPerSe</name>
    <value>20485760</value>
</property>
5. 控制HDFS文件的副本数,默认为3,当许多任务同时读取一个文件时,读取可能会造成瓶颈,这时增大副本数可以有效缓解这种情况,但是也会造成大量的磁盘空间占用,这时可以只修改 Hadoop 客户端 的配置,这样,从 Hadoop 客户端上传的文件的副本数将以 Hadoop 客户端的为准
<property> 
    <name>dfs.replication</name> 
    <value>3</value> 
</property>
6. 设置 DataNode 在进行文件传输时最大线程数,通常设置为8192,如果集群中有某台 DataNode 主机的这个值比其他主机的大,那么出现的问题是,这台主机上存储的数据相对别的主机比较多,导致数据分布不均匀的问题,即使 balance 仍然会不均匀。
<property> 
    <name>dfs.datanode.max.transfer.threads</name> 
    <value>4096</value> 
</property>

core-site.xml

1.Hadoop的缓冲区大小用于 Hadoop 读HDFS的文件和写HDFS的文件,还有map 的中间结果输出都用到了这个缓冲区容量,默认为4KB,增加为128KB。
<property> 
    <name>io.file.buffer.size</name>
    <value>131072</value> 
</property>

MapReduce 调优

使用 Hadoop 进行大数据运算,当数据量极大时,那么对 MapReduce 性能的调优重要性不言而喻,尤其是 Shuffle 过程中的参数配置对作业的总执行时间影响特别大。

下面总结一些和 MapReduce 相关的性能调优方法,主要从 5 个方面考虑:

数据输入、 Map 阶段、 Reduce 阶段、 Shuffle 阶段和其他调优属性

1. 数据输入

在执行 MapReduce 任务前,将小文件进行合并,大量的小文件会产生大量的 Map 任务,増大 Map 任务装载的次数,而任务的装载比较耗时,从而导致 MapReduce 运行速度较慢。

因此采用 ==CombineTextInputFormat== 来作为输入,解决输入端大量的小文件场景

2. Map 阶段

  1. 减少溢写( spill )次数: 通过调整 io.sort.mb 及 sort.spill.percent 参数值,增大触发 spill 的内存上限,减少 spill 次数,从而减少磁盘 I / O 。
  2. 减少合并( merge )次数: 通过调整 io.sort. factor 参数,增大 merge 的文件数目,减少 merge 的次数,从而缩短 MR 处理时间。
  3. 在 Map 之后,不影响业务逻辑前提下,先进行 combine 处理,减少 I / O 上面提到的那些属性参数,都是位于 marred-default.xml 文件中,这些属性参数的调优方式如表所示。
属性名称类型默认值说明
mapreduce.task.io.sort.mbint100配置排序map输出时使用的内存缓冲区的大小,默认100MB,实际开发中可以设置大一些
mapreduce.map.sort.spill.percentfloat0.80map输出内存缓冲和用来开始磁盘溢出写过程的记录边界索引的阈值,即最大使用环形缓冲内存的阈值。一般默认是80%。也可以直接设置为100%
mapreduce.task.io.sort.factorint10排序文件时,一次最多合并的流数,实际开发中可将这个值设置为100
mapreduce.task.min.num.spills.for.combineint3运行 Combiner 时,所需的最少溢出文件数(如果已指定 Combiner)

3. Reduce 阶段

  1. 合理设置 Map 和 Reduce 数: 两个都不能设置太少,也不能设置太多。太少,会导致 task 等待,延长处理时间;太多,会导致 Map 和 Reduce 任务间竞争资源,造成处理超时等错误。
  2. 设置 Map 和 Reduce 共存: 调整 slowstart.completedmaps 参数,使 Map 运行到定程度后, Reduce 也开始运行,减少 Reduce 的等待时间。
  3. 规避使用 Reduce : 因为 Reduce 在用于连接数据集的时候将会产生大量的网络消耗。通过将 MapReduce 参数 setNumReduceTasks 设置为 0 来创建一个只有 Map 的作业
  4. 合理设置 Reduce 端的 buffer : 默认情况下,数据达到一个國值的时候, buffer 中的数据就会写人磁盘,然后 Reduce 会从磁盘中获得所有的数据。也就是说, buffer 和 Reduce 是没有直接关联的,中间多一个写磁盘→读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得 buffer 中的一部分数据可以直接输送到 Reduce ,从而减少 I / O 开销。这样一来,设置 buffer 需要内存,读取数据需要内存, Reduce 计算也要内存,所以要根据作业的运行情况进行调整。

上面提到的属性参数,都是位于 mapped-default.xml 文件中,这些属性参数的调优方式如表所示。

属性名称类型默认值说明
mapreduce.job.reduce.slowstart.completedmapsfloat0.05当 map task 在执行到5%时,就开始为 reduce申请资源,开始执行 reduce操作, reduce可以开始复制map结果数据和做 reduce shuffle操作
mapred.job.reduce.input.buffer.percentfloat0.0在 reduce过程,内存中保存map输出的空间占整个堆空间的比例。如果 reducer 需要的内存较少,可以增加这个值来最小化访问磁盘的次数

4. Shuffle 阶段

Shuffle 阶段的调优就是给 Shuffle 过程尽量多地提供内存空间,以防止出现内存溢出现象,可以由参数 mapped.child.java.opts 来设置,任务节点上的内存大小应尽量大。

上面提到的属性参数,都是位于 mapred-site.xml 文件中,这些属性参数的调优方式如表所示。

属性名称类型默认值说明
mapped.map.child.java.optsint-Xmx200m当用户在不设置该值情况下,会以最大1GB jvm heap size 启动 map task,有可能导致内存溢出,所以最简单的做法就是设大参数,一般设置为-Xmx1024m
mapred.reduce.child.java.optsint-Xmx200m当用户在不设置该值情况下,会以最大1 GB jvm heap size启动 Reduce task,也有可能导致内存溢出,所以最简单的做法就是设大参数,一般设置为-Xmx1024m

5. 其他调优属性

除此之外, Mapreduce还有一些基本的资源属性的配置,这些配置的相关参数都位于 mapred-default.xml 文件中,可以合理配置这些属性提高 Mapreduce性能,下表列举了部分调优属性。

属性名称类型默认值说明
mapreduce.map.memory.mbint1024一个 Map Task 可使用的资源上限。如果 Map Task 实际使用的资源量超过该值,则会被强制杀死
mapreduce.reduce.memory.mbint1024一个 Reduce Task可使用的资源上限。如果 Reduce Task实际使用的资源量超过该值,则会被强制杀死
mapreduce.map.cpu.vcoresint1每个 Map Task可使用的最多 cpu core数目
mapreduce.reduce.cpu.vcoresint1每个 Reduce Task可使用的最多 cpu core数目
mapreduce.reduce.shuffle.parallelcopiesint5每个 reduce 去map中拿数据的并行数
mapreduce.map.maxattemptsint4每个 Map Task最大重试次数,一旦重试参数超过该值,则认为 Map Task运行失败
mapreduce.reduce.maxattemptsint4每个 Reduce Task最大重试次数,一旦重试参数超过 Int 该值,则认为 Reduce Task运行失败

YARN 调优

1. RM的内存资源配置, 配置的是资源调度相关

ID配置说明
RM1yarn.scheduler.minimum-allocation-mb分配给AM单个容器可申请的最小内存
RM2yarn.scheduler.maximum-allocation-mb分配给AM单个容器可申请的最大内存

最小值可以计算一个节点最大Container数量;一旦设置,不可动态改变

2. NM的内存资源配置,配置的是硬件资源相关

ID配置说明
NM1yarn.nodemanager.resource.memory-mb节点最大可用内存
NM2yarn.nodemanager.vmem-pmem-ratio虚拟内存率,默认2.1

RM1、RM2的值均不能大于NM1的值 NM1可以计算节点最大最大Container数量,max(Container)=NM1/RM1 一旦设置,不可动态改变

3. AM内存配置相关参数,配置的是任务相关

ID配置说明
AM1mapreduce.map.memory.mb分配给map Container的内存大小
AM2mapreduce.reduce.memory.mb分配给reduce Container的内存大小

这两个值应该在RM1和RM2这两个值之间 AM2的值最好为AM1的两倍 这两个值可以在启动时改变

ID配置说明
AM3mapreduce.map.java.opts运行map任务的jvm参数,如-Xmx,-Xms等选项
AM4mapreduce.reduce.java.opts运行reduce任务的jvm参数,如-Xmx,-Xms等选项

这两个值应该在AM1和AM2之间

4. 关于Container

  1. Container是YARN中资源的抽象,它封装了某个节点上一定量的资源(CPU和内存两类资源)。
    它跟Linux Container没有任何关系,仅仅是YARN提出的一个概念(从实现上看,可看做一个可序列化/反序列化的Java类)。
  2. Container由ApplicationMaster向ResourceManager申请的,由ResouceManager中的资源调度器异步分配给ApplicationMaster;
  3. Container的运行是由ApplicationMaster向资源所在的NodeManager发起的,Container运行时需提供内部执行的任务命令(可以使任何命令,比如java、Python、C++进程启动命令均可)以及该命令执行所需的环境变量和外部资源(比如词典文件、可执行文件、jar包等)。

另外,一个应用程序所需的Container分为两大类,如下:

  • 运行ApplicationMaster的Container:这是由ResourceManager(向内部的资源调度器)申请和启动的,用户提交应用程序时,可指定唯一的ApplicationMaster所需的资源;
  • 运行各类任务的Container:这是由ApplicationMaster向ResourceManager申请的,并由ApplicationMaster与NodeManager通信以启动之。

以上两类Container可能在任意节点上,它们的位置通常而言是随机的,即ApplicationMaster可能与它管理的任务运行在一个节点上。

Container是YARN中最重要的概念之一,懂得该概念对于理解YARN的资源模型至关重要。

注意:如下图,map/reduce task是运行在Container之中的,所以上面提到的mapreduce.map(reduce).memory.mb大小都大于mapreduce.map(reduce).java.opts值的大小。

5. 实践

如上图所示,先看最下面褐色部分,

  1. AM参数 mapreduce.map.memory.mb=1536MB,表示AM要为map Container申请1536MB资源,但RM实际分配的内存却是2048MB,因为yarn.scheduler.mininum-allocation-mb=1024MB,这定义了RM最小要分配1024MB,1536MB超过了这个值,所以实际分配给AM的值为2048MB(这涉及到了规整化因子)。
  2. AM参数 mapreduce.map.java.opts=-Xmx 1024m,表示运行map任务的jvm内存为1024MB,因为map任务要运行在Container里面,所以这个参数的值略微小于mapreduce.map.memory.mb=1536MB这个值。
  3. NM参数 yarn.nodemanager.vmem-pmem-radio=2.1,这表示NodeManager可以分配给map/reduce Container 2.1倍的虚拟内存,按照上面的配置,实际分配给map Container容器的虚拟内存大小为2048*2.1=3225.6MB,若实际用到的内存超过这个值,NM就会kill掉这个map Container,任务执行过程就会出现异常。
  4. AM参数 mapreduce.reduce.memory.mb=3072MB,表示分配给reduce Container的容器大小为3072MB,而map Container的大小分配的是1536MB,从这也看出,reduce Container容器的大小最好是map Container大小的两倍。
  5. NM参数 yarn.nodemanager.resource.mem.mb=24576MB,这个值表示节点分配给NodeManager的可用内存,也就是节点用来执行yarn任务的内存大小。这个值要根据实际服务器内存大小来配置,比如我们hadoop集群机器内存是128GB,我们可以分配其中的80%给yarn,也就是102GB。 上图中RM的两个参数分别1024MB和8192MB,分别表示分配给AM map/reduce Container的最大值和最小值。