以下整理内容参考https://issues.apache.org/jira/browse/HDFS-8791
前言
HDFS中为了统计每个DN数据节点上的存储使用量,DN节点上会对每块盘路径周期性的执行DU操作,汇报到Namenode节点上,就可以统计到总存储的使用量,每个点的存储使用量。默认10min会执行一次du操作,尽量保证数据使用量的实时性。在存储使用量不大的情况下,执行对每块盘的du操作,对整个系统的IO影响 不太明显,但是当节点存储使用率比较高的情况下,du操作引发IO高的问题对整个系统的影响就很大了,很可能会引发阻塞IO,影响整个节点上的服务。
Du性能问题
du:disk usage,它的统计原理在于将目标路径下的当前没有被删除的文件进行大小累加,然后得出总使用量。这种计算方式在文件数量少时往往不会表现出什么问题。但是当目标路径目录多,文件多的时候,du会表现出明显的时间执行耗时,而在这一点上,df命令则用的是另一种更加高效的方式,它的统计值来通过文件系统获取的。但是df命令的一个最不适用的地方在于它不能按照具体目录进行使用量的统计。df是按照所在磁盘级别进行统计的。换句话说,用df命令在属于同一块物理盘的子路径下执行df命令,获取的值会是完全一致的。比较遗憾,这种情况将无法支持DataNode多block pool共用一块盘的情况。
解决方案研究
A.适当调大datanode du执行间隔
通过调整fs.du.interval配置来加大datanode du执行间隔,减少一些存储使用量的实时性来缓解Du带来的IO高问题。
B.从Liunx层面调整cache相关配置
linux的VFS Inode Cache、directory cache相关原理这里不做细致介绍,主要是缓存inode相关信息,linux文件系统上,用户对文件、目录的访问都是先访问对应的inode信息,所以适当调整文件系统的cache配置可以提高访问效率。
vm.vfs_cache_pressure
该项表示内核回收用于directory和inode cache内存的倾向:
缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比
降低该值低于100,将导致内核倾向于保留directory和inode cache
增加该值超过100,将导致内核倾向于回收directory和inode cache。
C.减少数据存储的现有目录层级[HDFS-8791]
HDFS-8791 introduces a new datanode layout format. This layout is identical to the previous block id based layout except it has a smaller 32x32 sub-directory structure in each data storage. On startup, the datanode will automatically upgrade it's storages to this new layout. Currently, datanode layout changes support rolling upgrades, on the other hand downgrading is not supported between datanode layout changes and a rollback would be required.
HDFS-8791里介绍通过DataNode Layout升级减少现有目录层级,减少du性能影响。
以前的datanode存储目录是256 * 256的层级结构,是64K个叶子目录,最大的问题就是这64k的叶子目录。
在节点上运行大量的任务,会推出几乎所有的buffer 去cache,du操作在这种情况下会变得非常慢。可以发现大型任务可以在整个集群中引发搜索风暴。
为了减少du的性能问题,社区在新的版本中进行了目录数的减少,将256x256的目录数改变为了32x32,总目录数从65k降到了1024。很明显,这将大大减少目录数的访问。这个其实是涉及到DN的Layout升级的问题了,HDFS采用的办法很简单,将时与之计算的16进制数从0xff变为了0x1f,相当于这里少包含了3个位数的计算,于是实现了在单目录层级8倍的降维。
datanode layout升级步骤:
上述DN Layout的升级并不依赖于大版本的升级,也不会有实际物理数据的move操作。
DN目录层级从256x256变为32x32,是需要DN Layout升级改动的。重启datanode后,会进行一次自动的layout的更新。具体原理步骤如下:
1)rename当前current目录,到previous.tmp。
2)新建current目录,并且建立hardlink从previous.tmp到新current目录。
3)rename目录previous.tmp为previous目录。
上述阶段其实是DN的Upgrade过程,等待真正执行了finalize操作之后,上面的previous才会被真正清除。NN收到admin的finalize命令后下发到所有的datanode节点。
rollback流程:
执行rollback:启动dtanode命令上添加rollback参数的方式。在Rollback过程中,Upgrad过程中的previous目录会重新rename为current目录。另外还有其它局部目录的更新。