HDFS优化方案
一、短路本地读取(Short Circuit Local Reads)
1.1 背景
在HDFS中,不管是Local Reads ( DFSClient和Datanode在同一个节点)还是Remote Reads ( DFSClient和Datanode不在同一个节点),
底层处理方式都是一样的,都是先由Datanode读取数据,然后再通过RPC(基于TCP )把数据传给DFSClient。
这样处理是比较简单的,但是性能会受到一些影响,因为需要Datanode在中间做一次中转。
尤其Local Reads的时候,既然DFSClient和数据是在一个机器上面,那么很自然的想法,就是让DPSClient绕开Datanode自己去读取数据。
所谓的“短路”读取绕过了DataNode,从而允许客户端直接读取文件。显然,这仅在客户端与数据位于同一机器的情况下才可行。短路读取为许多应用提供了显着的性能提升。
1.2 设计方式
在Linux中,有个技术叫做Unix Domain Socket。Unix Domain Socket是一种进程间的通讯方式,它使得同一个机器上的两个进程能以Socket的方式通讯。
HDFS客户端的“短路”本地读取,就是客户端通过Unix Domain Socket技术与客户端和DataNode通信,通过Unix Domain Socket技术获取到要读取文件的文件描述符,客户端就能读取该文件的内容了
你需要设置一个路径给该套接字,而且DataNode要能够创建该路径。另一方面,除了HDFS用户和root用户,其他用户不可能创建该路径。正因如此,所以,通常才使用在/var/run或者/var/lib下的路径。
客户端和DataNode通过在/dev/shm上的一段共享内存来交换信息。
短路本地读需要在DataNode和客户端上同时配置。
总结:datanode获取数据的文件描述符,通过通过Unix Domain Socket技术将文件描述符传递给客户端,客户端通过文件描述符读取文件内容
1.3 相关配置参数
dfs.client.read.shortcircuit false 该参数打开short-circuit local reads 功能。
dfs.domain.socket.path 可选。该参数是一个指向UNIX域套接字的路径,用于DataNode和本地HDFS客户端通信。如果在该路径中出现了字符串"_PORT",会被替换成DataNode的TCP端口。
dfs.client.read.shortcircuit.skip.checksum false 如果设置了该参数,short-circuit local reads功能将跳过checksums校验。通常不推荐这么做,但是该参数对于特殊场合可能有用。如果你在HDFS之外自己做checksum校验,那么就该考虑设置该参数。
dfs.client.read.shortcircuit.streams.cache.size 256 DFSClient维护着一个用于保存最近已打开的文件描述符的缓存。该参数控制着此缓存的容量。增大该缓存的容量就可以使用更多文件描述符,但是,在涉及大量seek操作的负载上可能带来更好的性能。
dfs.client.read.shortcircuit.streams.cache.expiry.ms 300000 该参数控制着文件描述符因为长期不活跃而被关闭之前需要在客户端缓存上下文中驻留的最小时间。
以下是示例配置。
hdfs-site.xml
<configuration>
<property>
<name>dfs.client.read.shortcircuit</name>
<value>true</value>
</property>
<property>
<name>dfs.domain.socket.path</name>
<value>/var/run/hadoop-hdfs/dn._PORT</value> #官网示例为/var/lib/hadoop-hdfs/dn_socket
</property>
<property>
<name>dfs.client.read.shortcircuit.skip.checksum</name>
<value>false</value>
</property>
<property>
<name>dfs.client.read.shortcircuit.streams.cache.size</name>
<value>1000</value>
</property>
<property>
<name>dfs.client.read.shortcircuit.streams.cache.expiry.ms</name>
<value>10000</value>
</property>
</configuration>
1.4 配置
1.配置libhadoop.so
因为Java不能直接操作Unix Domain Socket,所以需要安装Hadoop的native包libhadoop.so。在编译Hadoop源码的时候可以通过编译native模块获取。可以用如下命令来检查native包是否安装好。
hadoop checknative # 检查当前集群是否安装native包
Native library checking:
hadoop: true /usr/local/hadoop-3.1.4/lib/native/libhadoop.so #可以看到默认二进制包安装好的
zlib: true /lib64/libz.so.1
zstd : false
snappy: true /usr/local/hadoop-3.1.4/lib/native/libsnappy.so.1
lz4: true revision:10301
bzip2: true /lib64/libbz2.so.1
openssl: false Cannot load libcrypto.so (libcrypto.so: 无法打开共享对象文件: 没有那个文件或目录)!
ISA-L: false libhadoop was built without ISA-L support
PMDK: false The native code was built without PMDK support.
2.修改配置文件
hdfs-site.xml
<property>
<name>dfs.client.read.shortcircuit</name>
<value>true</value>
</property>
<property>
<name>dfs.domain.socket.path</name>
<value>/var/run/hadoop-hdfs/dn._PORT</value> #官网示例为/var/lib/hadoop-hdfs/dn_socket
</property>
3.创建socket路径
mkdir -p /var/run/hadoop-hdfs # 这里创建的是文件夹hadoop-hdfs,而上述配置中的dn_socket是datanode自己创建的
4.启动服务
start-dfs.sh
5.检查日志
grep -n 'Listening on UNIX domain socket:' /{install_path}/logs/hadoop-{run_username}-datanode-{hostname}.log
2982:2022-12-29 14:51:11,879 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: Listening on UNIX domain socket: /var/run/hadoop-hdfs/dn.9866 #确保监听并自动创建 dn_PORT文件
ll /var/run/hadoop-hdfs/dn.9866
5.下载文件测试
hadoop fs -put anaconda-ks.cfg /data/ #从当前机器上传下载一个文件
hadoop fs -get /data/anaconda-ks.cfg /tmp
grep -n 'SHORT_CIRCUIT_FDS' /usr/local/hadoop/logs/hadoop-root-datanode-hdp01.dialev.com.log #查看日志是否有SHORT_CIRCUIT_FDS关键字
HDFS数据可能并不总是在DataNode之间均匀分布。一个常见的原因是向现有群集中添加了新的DataNode。
HDFS提供了一个Balancer程序,分析block放置信息并且在整个DataNode节点之间平衡数据,直到被视为平衡为止。
所谓的平衡指的是每个DataNode的利用率(本机已用空间与本机总容量之比)与集群的利用率(HDFS整体已用空间与HDFS集群总容量的比)之间相差不超过给定阈值百分比。
2.2 命令指南
参考链接:https://hadoop.apache.org/docs/r3.1.4/hadoop-project-dist/hadoop-hdfs/HDFSCommands.html#balancer
hdfs balancer --help
Usage: hdfs balancer
[-policy <policy>] the balancing policy: datanode or blockpool
[-threshold <threshold>] Percentage of disk capacity
[-exclude [-f <hosts-file> | <comma-separated list of hosts>]] Excludes the specified datanodes.
[-include [-f <hosts-file> | <comma-separated list of hosts>]] Includes only the specified datanodes.
[-source [-f <hosts-file> | <comma-separated list of hosts>]] Pick only the specified datanodes as source nodes.
[-blockpools <comma-separated list of blockpool ids>] The balancer will only run on blockpools included in this list.
[-idleiterations <idleiterations>] Number of consecutive idle iterations (-1 for Infinite) before exit.
[-runDuringUpgrade] Whether to run the balancer during an ongoing HDFS upgrade.This is usually not desired since it will not affect used space on over-utilized machines.
-threshold 10 #集群平衡条件,DataNode间磁盘使用率相差阈值,区间选择0~100
-policy datanode #平衡策略,默认datanode,
-exclude -f /path/to/file # 默认为空,指定不参与balance的节点IP
-include -f /path/to/file # 默认为空,只允许参与balance的节点IP
-idleiterations 5 #迭代
2.3 运行balance
hdfs dfsadmin -setBalancerBandwidth newbandwidth #设置运行时带宽,避免影响业务,以每秒字节数为单位 例:100M = 1024*1024*100 = 104857600
hdfs balancer -threshold 10
服务器一般可以通过挂载多块磁盘来扩大单机的存储能力。
在Hadoop HDFS中,DataNode负责最终数据block的存储,在所在机器上的磁盘之间分配数据块。当写入新block时,DataNodes将根据选择策略(循环策略或可用空间策略)来选择block的磁盘(卷)。
名词解释:
循环策略︰它将新block均匀分布在可用磁盘上。默认此策略。
可用空间策略︰此策略将数据写入具有更多可用空间(按百分比)的磁盘。
在长期运行的群集中采用循环策略时,DataNode有时会不均匀地填充其存储目录(磁盘/卷),从而导致某些磁盘已满而其他磁盘却很少使用的情况。发生这种情况的原因可能是由于大量的写入和删除操作,也可能是由于更换了磁盘。
如果我们使用基于可用空间的选择策略,则每个新写入将进入新添加的空磁盘,从而使该期间的其他磁盘处于空闲状态。这将在新磁盘上创建瓶颈。
因此,需要一种Intra DataNode Balancing ( DataNode内数据块的均匀分布)来解决Intra-DataNode偏斜(磁盘上块的不均匀分布),这种偏斜是由于磁盘更换或随机写入和删除而发生的。
因此,Hadoop 3.0中引入了一个名为Disk Balancer的工具,该工具专注于在DataNode内分发数据。
3.2 简介
HDPS disk balancer是Hladoop 3中引入的命令行工具,用于平衡DataNode中的数据在磁盘之间分布不均匀问题。这里要特别注意,HDFS disk balancer与HDFS Balancer是不同的:
HDFS disk balancer针对给定的DataNode进行操作,并将块从一个磁盘移动到另一个磁盘,是DataNode内部数据在不同磁盘间平衡;
HDFS Balancer平衡了DataNode节点之间的分布。
3.3 HDPS disk balancer功能
1.数据传输报告
为了衡量集群中哪些计算机遭受数据分布不均的影响,磁盘平衡器定义了Volume Data Density metric(卷/磁盘数据密度度量标准)和Node Data Density metric(节点数据密度度量标准)。
卷(磁盘)数据密度∶比较同台机器上不同卷之间的数据分布情况
计算公式:
1 理想存储密度=所有磁盘使用的总容量/所有磁盘的总容量
2.卷存储密度=单个磁盘使用量/单个磁盘容量
3.卷数据密度 =理想存储密度-卷存储密度 #如果值为正数表示磁盘利用率有待提高,如果是否负数,则相反
节点数据密度∶比较的是不同机器之间的
计算公式:
1 理想存储密度=所有磁盘使用的总容量/所有磁盘的总容量
2.卷存储密度=单个磁盘使用量/单个磁盘容量
3.节点数据密度= 卷存储密度+卷存储密度+卷存储密度+...... #所有卷存储密码之和,较高的值表示该节点磁盘利用率有待提高,较低则相反
以下为示例:
disk1 disk2 disk3 disk4
容量 200GB 300GB 350GB 500GB
使用空间 100GB 76GB 300GB 4750GB
使用率 0.5 0.25 0.85 0.95
卷数据密度 0.20 0.45 -0.15 -0.24
卷(磁盘)数据密度:
Total Capacity= 200 + 300 + 350 + 500 = 1350 GB
Total Used= 100 + 76 + 300 + 475 = 951 GB
因此,每个卷/磁盘上的理想存储为∶
ldeal Storage = Total Used ÷ Total Capacity= 951÷1350 = 0.70
也就是每个磁盘应该保持在70%理想存储容量。
Volume Data Density = Ideal Storage - dfs Used Ratio
比如Diskl的卷数据密度= 0.70 - 0.50 = 0.20。其他以此类推。
节点数据密度:
上述例子中的节点数据密度=0.20+0.45-0.15-0.24=1.04
2.磁盘平衡
当指定某个DataNode节点进行disk数据平衡,就可以先计算或读取当前的volume Data Density(磁卷数据密度)。有了这些信息,我们可以轻松地确定哪些卷已超量配置,哪些卷已不足。
为了将数据从一个卷移动到DataNode中的另一个卷,Hadoop开发实现了基于RPC协议的Disk Balancer。
3.4 开启HDPS disk balancer
# 默认情况下,Hadoop群集上已经启用了Disk Balancer功能。通过在hdfs-site.xml中调整dfs.disk.balancer.enabled参数值,选择在Hadoop中是否启用磁盘平衡器。
相关命令:
plan 计划
命令:hdfs diskbalancer -plan <datanode>
-out #控制计划文件的输出位置
-bandwidth #设置用于运行Disk Balancer的最大带宽.默认带宽10 MB/s.
-thresholdPercentage #定义磁盘开始参与数据重新分配或平衡操作的值.默认的thresholdPercentage值为10%,这意味着仅当磁盘包含的数据比理想存储值多10%或更少时,磁盘才用于平衡操作.
-maxerror #它允许用户在中止移动步骤之前为两个磁盘之间的移动操作指定要忽略的错误数.
-v #详细模式,指定此选项将强制plan命令在stdout上显示计划的摘要.
-fs #此选项指定要使用的NameNode.如果未指定,则Disk Balancer将使用配置中的默认NameNode.
Execute执行
命令:hdfs diskbalancer -execute <JSON file path
execute命令针对plan生成计划的DataNode执行计划。
Query查询
命令:hdfs diskbalancer -query <datanode
query命令从运行计划的DataNode获取HDFS磁盘平衡器的当前状态。
Cancel取消
命令:hdfs diskbalancer -cancel <JSON file path>
hdfs diskbalancer -cancel planID node <nodename>
cancel命令取消运行计划。
Report汇报
命令:hdfs diskbalancer -fs hdfs://nn_host:8020 -report
四、
为了提供容错能力,HDFS会根据replication factor(复制因子)在不同的DataNode上复制文件块。
默认复制因子为3(注意这里的3指的是1+2=3,不是额外3个),则原始块除外,还将有额外两个副本。每个副本使用100%的存储开销,因此导致200%的存储开销。这些副本也消耗其他资源,例如网络带宽。
在复制因子为N时,存在N-1个容错能力,但存储效率仅为1/N。
4.2 Erasure Coding(EC)简介
纠删码技术(Erasure coding)简称EC,是一种编码容错技术。最早用于通信行业,数据传输中的数据恢复。它通过对数据进行分块,然后计算出校验数据,使得各个部分的数据产生关联性。当一部分数据块丢失时,可以通过剩余的数据块和校验块计算出丢失的数据块。
Hadoop 3.0 之后引入了纠删码技术(Erasure Coding),它可以提高50%以上的存储利用率,并且保证数据的可靠性。
4.3 部署及操作
1.集群和硬件配置
编码和解码工作会消耗HDFS客户端和DataNode上的额外CPU。
纠删码文件也分布在整个机架上,以实现机架容错。这意味着在读写条带化文件时,大多数操作都是在机架上进行的。因此,网络带宽也非常重要。
对于机架容错,拥有足够数量的机架也很重要,每个机架所容纳的块数不超过EC奇偶校验块的数。机架数量=(数据块+奇偶校验块)/奇偶校验块后取整。
比如对于EC策略RS(6,3),这意味着最少3个机架(由(6 + 3)/ 3 = 3计算),理想情况下为9个或更多,以处理计划内和计划外的停机。对于机架数少于奇偶校验单元数的群集,HDFS无法维持机架容错能力,但仍将尝试在多个节点之间分布条带化文件以保留节点级容错能力。因此,建议设置具有类似数量的DataNode的机架。
2.纠删码策略设置
纠删码策略由参数dfs.namenode.ec.system.default.policy指定,默认是RS-6-3-1024k,其他策略默认是禁用的。
可以通过hdfs ec [-enablePolicy -policy <policyName>]命令启用策略集。
3.启用英特尔ISA-L(智能存储加速库)
默认RS编解码器的HDFS本机实现利用Intel ISA-L库来改善编码和解码计算。要启用和使用Intel ISA-L,需要执行三个步骤。
建立ISA-L库;
使用ISA-L支持构建Hadoop;
使用-Dbundle.isal将isal.lib目录的内容复制到最终的tar文件中。使用tar文件部署Hadoop。确保ISA-L在HDFS客户端和DataNode上可用。
| 软件 | 版本 |
| ----------------------------------------------------------- | ------- |
| Hadoop | 3.1.4 |
| [isa-l](https://github.com/intel/isa-l/releases) | 2.28.0 |
| [nasm](https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/) | 2.14.02 |
| yasm | 1.2.0 |
1.安装yasm和nasm
#在Hadoop集群所有节点上安装yasm和nasm。
yum install -y yasm
yum install -y nasm
#注意:isa-l-2.28.0对nasm和yasm有版本要求,低版本在安装时会报错。
2.编译安装isa-l-2.28.0
#在Hadoop集群所有节点上编译安装isa-l-2.28.0。
tar -zxvf isa-l-2.28.0.tar.gz
cd isa-l-2.28.0
./autogen.sh
./configure --prefix=/usr --libdir=/usr/lib64
make
make install
make -f Makefile.unx
#检查libisal.so*是否成功
ll /lib64/libisal.so*
############如果有,则跳过##############
############如果没有有,则复制##############
cp bin/libisal.so bin/libisal.so.2 /lib64
3.Hadoop上检查是否启用isa-l
Native library checking:
hadoop: true /usr/hdp/3.0.0.0-1634/hadoop/lib/native/libhadoop.so.1.0.0
zlib: true /lib64/libz.so.1
zstd : false
snappy: true /usr/hdp/3.0.0.0-1634/hadoop/lib/native/libsnappy.so.1
lz4: true revision:10301
bzip2: true /lib64/libbz2.so.1
openssl: true /lib64/libcrypto.so
ISA-L: true /lib64/libisal.so.2 -------------> Shows that ISA-L is loaded.
命令:
hdfs ec
Usage: bin/hdfs ec [COMMAND]
[-listPolicies]
[-addPolicies -policyFile <file>]
[-getPolicy -path <path>]
[-removePolicy -policy <policy>]
[-setPolicy -path <path> [-policy <policy>] [-replicate]]
[-unsetPolicy -path <path>]
[-listCodecs]
[-enablePolicy -policy <policy>]
[-disablePolicy -policy <policy>]
[-help <command-name>]
常用参数:
[-setPolicy -path <path> [-policy <policy>] [-replicate]] #在指定路径的目录上设置擦除编码策略。 #path:HDFS中的目录。这是必填参数。设置策略仅影响新创建的文件,而不影响现有文件。 #policy:用于此目录下文件的擦除编码策略。默认RS-6-3-1024k策略。 #-replicate在目录上应用默认的REPLICATION方案,强制目录采用3x复制方案。replicate和-policy <policy>是可 选参数。不能同时指定它们。
[-getPolicy -path < path >] #获取指定路径下文件或目录的擦除编码策略的详细信息。
[-unsetPolicy -path < path >] #取消设置先前对目录上的setPolicy的调用所设置的擦除编码策略。如果该目录从祖先目录继承了擦除编码策略 ,则unsetPolicy是no-op。在没有显式策略集的目录上取消策略将不会返回错误。
[-listPolicies] #列出在HDFS中注册的所有(启用,禁用和删除)擦除编码策略。只有启用的策略才适合与 setPolicy命令一起使用。
[-addPolicies -policyFile <文件>] #添加用户定义的擦除编码策略列表。
[-listCodecs] #获取系统中支持的擦除编码编解码器和编码器的列表。
[-removePolicy -policy <policyName>] #删除用户定义的擦除编码策略。
[-enablePolicy -policy <policyName>] #启用擦除编码策略。
[-disablePolicy -policy <policyName>] #禁用擦除编码策略。
"一劳永逸" 的话,有是有的,而 "一劳永逸" 的事却极少