文章涵盖了hadoop框架的三个组成架构各自的优化方法,涉及存储,计算,故障排除等多个方面的具体调优内容,先后解决HDFS,MapReduce,Yarn的常见问题,最终结合小文件问题给出了Hadoop综合调优.
Hadoop2.x系列,NN内存默认2000M,根据服务器(以4G为例)的3/4来配:
hadoop-env.sh文件中配置:HADOOP_NAMENODE_OPTS=-Xmx3072m
Hadoop3.x系列,hadoop-env.sh文件中说明了内存自动分配.
通过命令 jmap -heap < jps查看到的进程的PID >可知NameNode和DataNode占用内存都是自动分配的,且相等。不是很合理。
手动配置:hadoop-env.sh
export HDFS_NAMENODE_OPTS="-Dhadoop.security.logger=INFO,RFAS -Xmx1024m"
export HDFS_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS -Xmx1024m"
NameNode有一个工作线程池,用来处理不同DataNode的并发心跳以及客户端并发的元数据操作。
线程数dfs.namenode.handler.count默认是10,按企业经验hdfs-site.xml中该值设为
将删除的文件在不超时的情况下恢复,防止误删
考虑到Java后台拉取的数据用多久能上传到集群,以及从HDFS上拉取数据的时间,因此对集群压测以测出HDFS的读写性能
说明:HDFS的读写性能主要受限于网络和磁盘.
前提:设置集群网速为100Mbps单位是bit;换算后为12.5M/s
测试步骤:
yarn-site.xml中设置关闭虚拟内存检测(避免centos和jdk的不兼容),分发
向HDFS写10个128M的文件(文件数>两个节点总核数就行,保证每个节点都有任务)
命令:hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -write -nrFiles 10 -fileSize 128MB
结果分析:
结论:说明所有网络资源已用满,因此写速度主要受限于网络传输速度
将上面10个文件读取:
hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -read -nrFiles 10 -fileSize 128MB
测试完毕,收尾,删除测试数据
hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -clean
观察到读取结果远大于网络带宽
结论:
测试节点存在文件副本,就近读取,读的本地磁盘,没经过网络,读速度不受网络限制,只受磁盘读写速度限制.
NN本地目录配置为多个,每个目录存放内容相同
说明:备份了nn,提高了可靠性,但不是高可用,nn所在节点挂掉集群仍无法工作
步骤:
DN可以配置成多目录,不同于nn的备份,dn多目录存放不同数据,解决磁盘空间不足问题
步骤:
增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。
说明:这是Hadoop3.x新特性,单节点内部磁盘均衡
步骤:
在白名单的主机IP地址才可以用来存储数据。可以尽量防止黑客恶意访问攻击。
步骤:
动态增加服务器,不重启集群即可实现服役新服务器,主要解决数据节点容量不足.
步骤:
如果常在某个节点提交任务,由于数据本地性原则,该节点数据量过多,造成数据节点间量的 差距,或者,新服役的服务器数据量比较少,需要执行集群均衡命令。
步骤:
说明:
Hadoop3.x引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。
确切的说:给hdfs的一个路径设置单副本存储策略
纠删码策略:
说明(以第一种为例):
使用RS编码,每3个数据单元,生成2个校验单元,共5个单元,也就是说:这5个单元中,只要有任意的3个单元存在(不管是数据单元还是校验单元,只要总数=3),就可以得到原始数据。每个单元的大小1024k=1024*1024=1048576。
步骤:
异构存储,又叫冷热数据分离,它不同于纠删码的单副本,它是给hdfs的一个路径设置多副本存储策略,手段:不同的数据,存储在不同类型的硬盘中,达到最佳性能
存储类型:
policy存储策略(上–>下:快–>慢):
shell操作命令:
具体实施步骤:
在需修改的节点修改hdfs-site.xml配置文件的参数:
统一副本数:dfs.replication
开启异构存储:dfs.storage.policy.enabled
修改该节点磁盘存储类型:dfs.datanode.data.dir
格式化nn,重启集群
未设置存储策略,所有文件块都存储在DISK下。所以,默认存储策略为HOT
修改存储策略,给数据升温/降温:set命令(可以看到文件块依然放在原处)
hdfs mover xxx:让HDFS按照存储策略自行移动文件块,可以看到副本移动到策略里指定的类型的磁盘
补充:
关于LAZY_PERSIST策略的说明:
文件就不会按该策略如期出现在指定类型的磁盘,即一个副本存储在RAM_DISK,其他副本存储在DISK中,因为:
前置工作:
问题解决:
说明:
前面HDFS架构中可以了解到: nn比2nn目录下多了一个正在追加写的Edits文件,里面写了集群最新的操作内容,所以这种故障的排除有个前提,就是近期的追加写文件里没有操作,才算完全恢复,因此该方式不算高可用(后期使用HA解决)
安全模式:文件系统只接受读数据请求,而不接受删除、修改等变更请求
进入安全模式场景:
1)nn在加载镜像文件和编辑日志期间处于安全模式;
2)NameNode再接收DataNode注册时,处于安全模式
退出安全模式条件(以下需全部满足):
1)可用数据节点>0
2)最多丢失一块block的所有副本
3)满足前两个条件并稳定30s
相关命令
命令 | 功能 |
---|---|
hdfs dfsadmin -safemode get | 查看安全模式状态 |
hdfs dfsadmin -safemode enter | 进入安全模式状态 |
hdfs dfsadmin -safemode leave | 离开安全模式状态 |
hdfs dfsadmin -safemode wait | 等待安全模式状态 |
案例1:启动集群进入安全模式
启动集群后立即(30s以内)来到集群web界面删除数据,提示集群处于安全模式
案例2:磁盘修复
删除两个块的所有副本,重启集群–>web界面提示块数量对不上警告–>输入命令离开安全模式–>依然警告–>不管则每次安全模式开启时都会警告–>解决办法:将警告信息中的已经丢失的文件块对应的元数据删除,或者联系磁盘厂家修复–>集群正常
案例3:模拟等待安全模式
先进入安全模式(不可hdfs写入)–>编写脚本:包含等待安全模式命令,以及hdfs写入命令–>使用另一个窗口执行脚本–>当安全模式退出时即可完成脚本中的hdfs写入
如何发现慢磁盘?
通过心跳未联系时间(3s)
fio命令,测试磁盘的读写性能
命令 | 功能 |
---|---|
sudo yum install -y fio | 安装测试命令 |
sudo fio -filename=/home/用户名/test.log -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=test_r | 顺序读测试 |
sudo fio -filename=/home/用户名/test.log -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=test_w | 顺序写测试 |
sudo fio -filename=/home/用户名/test.log -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=test_randw | 随机写测试 |
sudo fio -filename=/home/用户名/test.log -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=test_r_w -ioscheduler=noop | 混合随机读写 |
随机写相比较顺序写,写入位置不连贯,增加了寻址时间,效率下降
测试出慢磁盘不要慌,推荐使用慢磁盘存储冷数据,做到 合理存放
问题:
hdfs存储小文件时,按128M的块存储,小文件相比大文件更消耗nn大量内存,导致hdfs存储效率低下…
解决手段:
使用文件存档工具:HAR文件(存档文件)
步骤:
启动yarn:因为要提交作业执行程序将小文件读取,后写入到归档文件
把/input目录里面的所有文件归档成一个叫input.har的归档文件,并把归档后文件存储到/output路径下:
hadoop archive -archiveName input.har -p /input /output
查看归档:
hadoop fs -ls /output/input.har
hadoop fs -ls har:///output/input.har
解归档文件:hadoop fs -cp har:///output/input.har/* /
上两步其实就是普通的hadoop命令加入了har协议
硬件和程序两个方面
计算机性能
1)CPU是否充足
2)内存是否够用
3)磁盘速度+冷热分离
4)网络带宽限制
I/O操作优化
1)数据倾斜:某个ReduceTask处理分区数据过多
2)Map运行时间太长,导致Reduce等待过久
3)小文件过多,MapTask并行度过高,资源不够
自定义分区,将map的输出数据合理分担到多个maptask,可以减少数据倾斜
减少环形缓冲区溢写次数,即减少溢写的文件个数:
mapreduce.task.io.sort.mb,缓冲区大小默认100–>200
mapreduce.map.sort.spill.percent,开始反向溢写的阈值默认80–>90
增加每次Merge合并次数(前提,系统内存充足):
mapreduce.task.io.sort.factor默认10–>20
合理增加预聚合Combiner
可采用Snappy或LZO压缩
MapTask内存:
mapreduce.map.memory.mb默认1024M,前面使用压缩这里相应增加内存
同时保持MapTask堆内存(mapreduce.map.java.opts)和该值一致
适当增加MapTask的核数:mapreduce.map.cpu.vcores
异常重试:mapreduce.map.maxattempts默认是4适当修改
提高Reduce去Map中拉取数据的并行数:
mapreduce.reduce.shuffle.parallellcopies默认5–>10
拉取数据的缓存在Reduce内存占比:
mapreduce.reduce.shuffle.input.buffer.percent默认0.7–>0.8
数据在缓存占比多少开始向磁盘溢写:
mapreduce.reduce.shuffle.merge.percent默认0.66–>0.75
ReduceTask内存上限:
mapreduce.reduce.memory.mb默认1024适当提高
同时修改堆内存mapreduce.reduce.java.opts与其一致
ReduceTask核数:
mapreduce.reduce.cpu.vcores默认是1可提高到2-4个
异常重试:
mapreduce.reduce.maxattempts默认是4适当修改
MapTask完成的比例达到该值后才会为ReduceTask申请资源:
mapreduce.job.reduce.slowstart.completedmaps:0.05
任务超时时间:
mapreduce.task.timeout默认600000(10分钟)
Reduce能不用就省,没有reduce过程就可以不经过shuffle过程
数据频率倾斜——某一个区域的数据量要远远大于其他区域。
数据大小倾斜——部分记录的大小远远大于平均值。
解决办法:
mapjoin/分区/预聚合/空值key打散
空值过多:
要么过滤空值,要么保留就得自定义分区,将空值加随机数打散,在二次聚合
map能先处理就先处理:Combiner或者MapJoin
分区并设置多个reduce个数
ResourceManager相关
1)处理调度器请求的线程数量:
yarn.resourcemanager.scheduler.client.thread-count
2)配置调度器:
yarn.resourcemanager.scheduler.class
NodeManager相关
1)NodeManager使用内存大小:
yarn.nodemanager.resource.memory-mb
2)使用CPU核数:
yarn.nodemanager.resource.cpu-vcores
3)是否将虚拟核数当作CPU核数:
yarn.nodemanager.resource.count-logical-processors-as-cores
4)虚拟核数和物理核数乘数,例如:4核8线程,该参数就应设为2:
yarn.nodemanager.resource.pcores-vcores-multiplier
5)是否让yarn自己检测硬件进行配置:
yarn.nodemanager.resource.detect-hardware-capabilities
6)是否开启物理内存检查限制container:
yarn.nodemanager.pmem-check-enabled
7)是否开启虚拟内存检查限制container:
yarn.nodemanager.vmem-check-enabled
8)虚拟内存物理内存比例:
yarn.nodemanager.vmem-pmem-ratio
Container容器相关
1)容器最小内存:
yarn.scheduler.minimum-allocation-mb
2)容器最大内存;
3)容器最小核数:
yarn.scheduler.minimum-allocation-vcores
4)容器最大核数;
容量调度器和公平调度器的使用:
详见:
yarn架构
在数据采集的时候,就将小文件或小批数据合成大文件再上传HDFS
Hadoop Archive文件归档,高效的将小文件放入HDFS块中的文件存档工具,能够将多个小文件打包成一个HAR文件,从而达到减少NameNode的内存使用
CombineTextInputFormat用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片。
开启uber模式.实现JVM重用:
让同一个Job的多个Task运行在一个JVM中,不必为每个Task都开启一个JVM。
开启uber模式:需在mapred-site.xml配置文件中添加以下参数:
1)开启uber模式:mapreduce.job.ubertask.enable
2)将最大的mapTask数量向下修改mapreduce.job.ubertask.maxmaps
3)将最大的reduce数量向下修改mapreduce.job.ubertask.maxreduces
4)将最大的输入数据量,默认使用dfs.blocksize 的值向下修改mapreduce.job.ubertask.maxbytes
该模式优势:
1)开启的容器数锐减:因为多个task共用一个容器
2)减少了开关jvm时间