概述

Hadoop 集群的调优可以从四方面着手:

  1. Linux 调优
  2. HDFS 调优
  3. MapReduce 调优
  4. YRAN 调优

一、Linux调优

修改内核参数

管理员通常会保持 Linux 服务器内核的默认设置,这并不是一个明智的做法,因为这有可能对集群的性能产生不利的影响!

下表给出了在 Hadoop 生产集群中推荐使用的 Linux 内核参数配置。

Linux 内核参数配置参数说明
fs.file-mx=6815744文件描述符总数
fs.aio-max-nr=1048576最大并发I/O请求数
net.core.rmem_default=262144操作系统接收缓冲区的默认大小
net.core.wmem_default=262144操作系统发送缓冲区的默认大小
net.core.rmem_max=16777216系统接收缓冲区最大值
net.core.wmem_max=16777216系统发送缓冲区最大值
net.ipv4.tcp_rmem=409626214416777216接收窗口尺寸的最小、默认、最大值
net.ipv4.tcp_wmem=409626214416777216发送窗口尺寸的最小、默认、最大值

增加文件限制

为了避免集群中的任何文件描述符错误,需要增加单个用户或进程一次可以打开的文件数量的限制。

默认值只有 128 。

可以使用以下命令检査当前限制(第一个为软限制第二个为硬限制)。

1
2
3
4
5
[root@hadoop ~]# ulimit -Sn
1024
[root@hadoop ~]# ulimit -Hn
4096
[root@hadoop ~]#

需要将 ulimit 值至少提高至4096( Hortonworks等推荐10000或者更多)。

可以通过编辑 /etc/security/limits.conf 文件来执行此操作,如下所示:

1
2
Soft nofile 4096 
Hard nofile 4096

且更改了内核设置,则可以通过执行以下命令来动态加载新设置

1
[root@hadoop ~]# sysctl -p

可以通过发出以下命令来确认新的内核设置:

1
[root@hadoop ~]# sysctl -a

磁盘设置

确保在挂载所有磁盘时使用 noatime 时间以及挂载所有目录时使用 nodir 时间。

这样, 可以避免在对 Linux 文件系统中的文件或目录进行读取操作时的不必要写入操作,从而提高集群性能。

测试磁盘I/O速度

使用 hdparm -t 命令测试磁盘速度,如下所示

1
2
$ hdparm -t /dev/sdal
复制代码

如果没有看到 70MB/S 以上的速度,这意味着有一个潜在的问题存在

检查服务器的 BIOS 设置

通过确保不启用磁盘驱动器的 IDE 仿真等功能来保证服务器 BIOS 为最佳性能配置。

存储和系统管理员会关注这个配置。

注意:在挂磁盘驱动器之前,将所有 Hadoop 目录下的文件权限更改为 700 这样在却驱动器时,向这些驱动器写入的任何进程都不会占满操作系统。

网卡绑定

为了提高吞吐量和弹性,最好通过执行NC绑定来组合网络接口。

启用 NTP

确保集群所有节点的时钟是同步的。

如果集群无法访问 Intenet ,则必须将集群中的一个服务器设置为 NTP 服务器。

通过编辑 /etc/sysconfig/ntpd 文件启用 NTP 守护进程来同步所有集群节点上的网络时间同步所有集群节点上的网络时间对于诸如 ZooKeeper 、 Kerberos 和 HBase 之类的应用程序至关重要。

当通过日志文件对集群进行故障排除时,在集群中使用同步时间也很重要。

注意尽管不是必须的,但最好使用单独的虚拟局域网( VLAN )为 Hadoop 提供专用交换基础设施。

在 CentOS8 中默认不再支持 ntp 软件包,时间同步将由 chrony 来实现,可以通过修改 /etc/chrony.conf 实现。

检查 DNS

使用主机名而不是 IP 地址来标识集群节点。

在理想情况下,集群中的所有节点都必须被配置 DNS 和反向 DNS 。

确保将所有主机名设置为完全限定域名( FQDN )。

以下是一个例子

1
2
# hostname -- fqdn
hadoop1.localdomain

如果由于某些原因无法配置 DNS ,确保编辑所有节点的 /etc/hosts 文件,将集群中的所有节点列入其中。

每个主机必须能够执行正向查找(利用主机名)和反向査找(利用 IP 地址)。

主机命令可帮助验证正向和反向查找,如下所示

1
2
3
4
# host hadoop1
hadoop1.localdomain has address 10.192.2.29
# host 10.192.2.29
10.192.2.29 in-addr.arpa domain name pointer hadoop1.localdomain

由于 Hadoop 大量使用基于网络的服务(如 DNS ),因此启用名称服务器缓存守护程序( nscd )以降低名称解析延迟是个好主意

禁用 swap

理想情况下,服务器都不应该 swap ,尤其是 DataNode 。

可以使用以下命令在这些服务器上完全禁用该功能。

1
swapoff - a

可以使用以下命令检查服务器上的 swap 状态

1
swapon - s

默认情况下,大多数 Linux 操作系统的 swappiness 被设置为 60 。

如果 swappiness 设置为零,除非内存不足, Linux 将避免使用磁盘,而设置为 100 表示操作系统立即将程序切换到磁盘。

我们知道,设置为 60 意味着从内存使用量达到操作系统分配的内存的半左右的时间开始,操作系统会相当频繁地使用磁盘上的交换文件。

例如,如果将 swappiness 调低到 10 ,则只有当 RAM 占用率达到 90 %左右时,操作系统才会使用磁盘上的交换文件。

Linux 管理员可以将以下设置添加到 /etc/sysctl.conf 文件中来更改系统的 swappiness

1
vm.swappiness=10

管理员必须重新启动服务器才能使新的 swappiness 设置生效。

对于将 swappiness 值设置为多低,没有特别明确的强制规定。

Cloudera 专家建议将其设置为 1

禁用 SELinux

虽然这并不是一个绝对的要求,但 SELinux 有时会干扰 Hadoop 的安装,所以在开始安装 Hadoop 之前最好禁用 SELinux 。

此外, SELinux 会对集群造成 7 %~ 10 %的性能损失。

可以执行以下命令获取当前的 SELinux 状态

1
getenforce

如果当前模式的值为 enforcing ,则 SELinux 处于启用状态。

可以将状态更改为 permissive 来禁用它,如下所示:

1
setenforce 0

关闭 IPv6

需要为某些网络相关的 Hadoop 配置参数设置值 0.0.0.0 ,将 Hadoop 绑定到服务器的 IPv6 地址。

如果没有连接到 IPv6 网络,则可以简单地禁用集群节点上的 IPv6 。

可以通过编辑 /etc/sysctl.conf 文件并在文件末尾添加以下行来禁用 IPv6 :

1
2
3
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.io.disable_ipv6 = 1

对 sysctl.conf 文件进行更改后,必须重新启动服务器。

重新启动后,执行以下命令来检查更改是否成功:

1
$ cat /proc/sys/net/ipv6/conf/all/disable_ipv6 

如果禁用 IPv6 ,输出应该为 1 ,否则为 0 。

也可以通过为环境变量 HADOOP_OPTS 添加以下值来禁用 Hadoop 的 IPv6 。

将此行添加到集群的 hadoop-env.sh 文件中:

1
export HADOOP_OPTS=-Djava.net.preferIPv4Stack=true 

禁用 IP 表

在安装 Hadoop 时,最好关掉网络防火墙(并进行检査),如下所示

1
2
service iptables stop
service iptables status

安装完成后,可以重新启用 IP 表。

设置 Limits

可以通过 shell 来限制用户能利用的集群资源。

为此,可以编辑 /etc/security/limits.conf 文件,该文件规定了如何限制用户使用资源。

limits.conf 文件用于配置重要的操作系统属性的“软”和“硬”限制,如文件大小、堆栈大小和进程的优先级(精度)等,如下所示。

将以下行添加到 /etc/security/limits.conf 文件中:

1
2
3
4
soft nofile 32768
hard nofile 32768
soft nproc 32768
soft nproc 32768

nofile 属性限制每个用户进程打开的文件描述符的数量, nproc指定最大进程数。

软限制设置意味着警告,硬限制设置是实际的资源限制

关闭透明大页(THP)压缩

据 Cloudera 和 Hortonworks 的专家介绍,THP压缩会降低 Hadoop的性能。

所以,禁用碎片整理是一个很好的做法,具体方法如下所示(将此行添加到 /etc/rc.local 文件):

1
$ echo 'never'; defrag_file_pathname

检查连通性

检查节点之间的无密码连接,以确保对SSH进行了正确的配置。

HDFS调优参数

1. hdfs-site.xml

1
2
3
4
<propertv> 
<name>dfs.block.size</name>
<value>134217728</value>
</property>

解释: 该参数表示 Hadoop 的文件块大小,通常设为128MB或者256MB。

1
2
3
4
<property> 
<name>dfs.namenode.handler.count</name>
<value>40</value>
</property>

解释: 该参数表示 NameNode 同时和 DataNode 通信的线程数,默认为10,将其增大为40。

1
2
3
4
<property> 
<name>dfs.datanode.max.xcievers</name>
<value>65536</value>
</property>

解释: dfs.datanode.max.xcievers 对于 DataNode 来说就 如同 Linux 上的文件句柄的限制,当 DataNode上面的连接数超过配置中的设置时, DataNode就会拒绝连接,修改设置为65536。

1
2
3
4
<property> 
<name>dfs.datanode.balance.bandwidthPerSe</name>
<value>20485760</value>
</property>

解释: 该参数表示执行 start-balancer.sh 的带宽,默认为1048576(1MB/s),将其増大到20MB/s

1
2
3
4
<property> 
<name>dfs.replication</name>
<value>3</value>
</property>

解释: 该项参数表示控制HDFS文件的副本数,默认为3,当许多任务同时读取一个文件时,读取可能会造成瓶颈,这时增大副本数可以有效缓解这种情况,但是也会造成大量的磁盘空间占用,这时可以只修改 Hadoop 客户端 的配置,这样,从 Hadoop 客户端上传的文件的副本数将以 Hadoop 客户端的为准

1
2
3
4
<property> 
<name>dfs.datanode.max.transfer.threads</name>
<value>4096</value>
</property>

解释: 该参数表示设置 DataNode 在进行文件传输时最大线程数,通常设置为8192,如果集群中有某台 DataNode 主机的这个值比其他主机的大,那么出现的问题是,这台主机上存储的数据相对别的主机比较多,导致数据分布不均匀的问题,即使 balance 仍然会不均匀。

2. core-site.xml

1
2
3
4
<property> 
<name>io.file.buffer.size</name>
<value>131072</value>
</property>

解释: Hadoop的缓冲区大小用于 Hadoop 读HDFS的文件和写HDFS的文件,还有map 的中间结果输出都用到了这个缓冲区容量,默认为4KB,增加为128KB。

MapReduce调优

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

MapReduce优化方法主要从六个方面考虑:数据输入、Map阶段、Reduce阶段、IO传输、数据倾斜问题和常用的调优参数。

1. 数据输入

  1. 合并小文件:在执行MR任务前将小文件进行合并,大量的小文件会产生大量的Map任务,增大Map任务的装载次数,而任务的装载比较耗时,从而导致MR运行较慢。
  2. 采用 ==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

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 计算也要内存,所以要根据作业的运行情况进行调整。

4、I/O传输

  1. 采用数据压缩的方式,减少网络IO的时间。安装Snappy和LZO压缩编码器。
  2. 使用SequenceFile二进制文件。

5. 数据倾斜问题

  1. 抽样和范围分区(预处理):提前对原始数据进行抽样得到的结果集来预设分区边界值。

    简单来说就是对本身分布不均匀的数据进行预处理,比如提前过滤Key预先对数据进行聚合重新将Key打撒(hash)等。这种方式治标不治本,当原始数据改变还是容易出现数据倾斜。优点就是简单效果好。

  2. 自定义分区:基于Key进行自定义分区,将导致倾斜的Key单独发送给一个Reduce处理。

  3. Combine:使用Combine可以大量减少小数据倾斜,Combine的目的就是聚合并精简数据。

  4. 采用Map Join,精良避免Reduce Join。

  5. 提高并行度:提高Reduce并行度本质还是打撒Key。

没有一种方式能完美解决数据倾斜问题,更多的还是基于实际情况使用多种方案组合处理。

6. 调优参数

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

配置参数参数说明
mapreduce.map.memory.mb一个MapTask可使用的资源上限(单位:MB),默认为1024。如果MapTask实际使用的资源量超过该值,则会被强制杀死。
mapreduce.reduce.memory.mb一个ReduceTask可使用的资源上限(单位:MB),默认为1024。如果ReduceTask实际使用的资源量超过该值,则会被强制杀死。
mapreduce.map.cpu.vcores每个MapTask可使用的最多cpu core数目,默认值: 1
mapreduce.reduce.cpu.vcores每个ReduceTask可使用的最多cpu core数目,默认值: 1
mapreduce.reduce.shuffle.parallelcopies每个Reduce去Map中取数据的并行数。默认值是5
mapreduce.reduce.shuffle.merge.percentBuffer中的数据达到多少比例开始写入磁盘。默认值0.66
mapreduce.reduce.shuffle.input.buffer.percentBuffer大小占Reduce可用内存的比例。默认值0.7
mapreduce.reduce.input.buffer.percent指定多少比例的内存用来存放Buffer中的数据,默认值是0.0

(2)Shuffle性能优化的关键参数,应在YARN启动之前就配置好(mapred-default.xml)

配置参数参数说明
mapreduce.task.io.sort.mbShuffle的环形缓冲区大小,默认100m
mapreduce.map.sort.spill.percent环形缓冲区溢出的阈值,默认80%

7、小文件处理

小文件的优化无非以下几种方式:

(1)在数据采集的时候,就将小文件或小批数据合成大文件再上传HDFS。

(2)在业务处理之前,在HDFS上使用MapReduce程序对小文件进行合并。

(3)在MapReduce处理时,可采用CombineTextInputFormat提高效率。

JVM优化小文件:对于大量小文件Job,可以开启JVM重用会减少45%的运行时间。

具体设置mapreduce.job.jvm.numtasks 值在10-20之间。

YARN调优

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

配置说明
yarn.scheduler.minimum-allocation-mb分配给AM单个容器可申请的最小内存
yarn.scheduler.maximum-allocation-mb分配给AM单个容器可申请的最大内存
yarn.scheduler.minimum-allocation-vcores每个Container申请的最小CPU核数,默认值:1
yarn.scheduler.maximum-allocation-vcores每个Container申请的最大CPU核数,默认值:32

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

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

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

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

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

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

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

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

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

参考