Hadoop 怎么调优?看完这篇就够了

3,124 阅读13分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

引子

小明又来了~

image.png

小明转行大数据后成功找到了一份大数据的工作,这是一个小公司,公司的大数据平台使用的是比较经典的 Apache Hadoop 框架,存储层是HDFS,计算引擎是MapReduce,调度引擎是YARN,领导给小明安排的活是接管 Hadoop 集群的运维加部分开发工作,第一份任务是希望小明能对现有的Hadoop集群调下优,因为 Hadoop 集群运行时间比较长了,出于稳定性和成本的考虑不会去更换平台的架构,但是现有的集群性能方面不太够满足需要了,于是就希望小明能做点什么,毕竟是一家小公司嘛。

小明接手平台后,先在网上搜索了一下 Hadoop 怎么去调优,发现很多博客都不全面

image.png

于是小明又想起了自己的远房表哥大明,大明听说后,给小明传了一份文档。

文档内容如下:

正文

Hadoop调优.png 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 。

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

[root@hadoop ~]# ulimit -Sn
1024
[root@hadoop ~]# ulimit -Hn
4096
[root@hadoop ~]#

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

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

Soft nofile 4096 
Hard nofile 4096 

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

[root@hadoop ~]# sysctl -p

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

[root@hadoop ~]# sysctl -a

磁盘设置

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

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

测试磁盘I/O速度

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

$ 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 )。

以下是一个例子

# hostname -- fqdn
hadoop1.localdomain
#

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

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

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

# 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 。

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

# swapoff - a

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

# swapon - s

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

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

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

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

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

vm.swappiness=10

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

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

Cloudera 专家建议将其设置为 1

禁用 SELinux

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

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

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

# getenforce

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

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

# setenforce 0

关闭 IPv6

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

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

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

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

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

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

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

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

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

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

export HADOOP_OPTS=-Djava.net.preferIPv4Stack=true 

禁用 IP 表

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

# service iptables stop
# service iptables status

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

设置 Limits

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

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

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

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

soft nofile 32768
hard nofile 32768
soft nproc 32768
soft nproc 32768

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

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

关闭透明大页(THP)压缩

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

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

$ echo 'never'; defrag_file_pathname

检查连通性

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

HDFS 调优

1. hdfs-site.xml

<propertv> 
    <name>dfs.block.size</name>
    <value>134217728</value>
</property>

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

<property> 
    <name>dfs.namenode.handler.count</name> 
    <value>40</value>
</property> 

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

<property> 
    <name>dfs.datanode.max.xcievers</name> 
    <value>65536</value>
</property> 

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

<property> 
    <name>dfs.datanode.balance.bandwidthPerSe</name>
    <value>20485760</value>
</property>

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

<property> 
    <name>dfs.replication</name> 
    <value>3</value> 
</property>

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

<property> 
    <name>dfs.datanode.max.transfer.threads</name> 
    <value>4096</value> 
</property>

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

2. core-site.xml

<property> 
    <name>io.file.buffer.size</name>
    <value>131072</value> 
</property>

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

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之间

实践

在这里插入图片描述

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

  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的最大值和最小值。

尾声

小明根据上面的文档针对自家的集群情况写了一份《调优方案》,得到了领导的嘉奖!

image.png