HDFS缓存与缓存块
HDFS的缓存与我们平常所说的缓存(cache)在作用上是一致的,主要是为了减少重复的数据请求过程。但是在具体实现上,我们平常所用的缓存可能只由一个简单的缓冲数组构成,而HDFS用的是缓存块(cacheblock)的概念。HDFS的缓存块由普通的文件块转换而来,同样也可以转换回去。HDFS缓存的出现可以大大提高用户读取文件的速度,因为它是缓存在DataNode内存中的,此过程无需进行读取磁盘的操作。
HDFS物理层面缓存块
物理层面缓存块这个词在HDFS源码中的解释如下:“利用mmap、mlock这样的系统调用将块数据锁入内存,以此达到在DataNode上缓存数据的效果。”大意为利用mmap、mlock系统调用将块锁入内存。没接触过底层操作系统知识的人可能不是很清楚mmap、mlock调用是怎么一回事,下面简单介绍一下。mmap系统调用,它是一个内存映射调用。mmap主要作用是将一个文件或者其他对象映射进内存。将文件或其他对象映射进内存。
缓存块的生命周期状态
缓存块的生命周期不仅仅只有Cached(已缓存)和UnCached(未缓存)两种。从源码中可以看出
Cache状态信息总共分为四类:
-
CACHING 表示块正在被缓存。
-
CACHING_CANCELLED 正在被缓存的块已处于被取消的状态。
-
CACHED 表明数据块已被缓存。
-
UNCACHING 表明缓存块正处于取消缓存的状态。
HDFS缓存相关配置
<property>
<name>dfs.datanode.max.locked.memory</name>
<value>0</value>
<description>
DataNode用来缓存块的最大内存空间大小,单位用字节表示。
系统变量RLIMIT_MEMLOCK至少需要设置得比此配置值要大,否则DataNode会出现启动失败的现象。
在默认的情况下,此配置值为0,表明默认关闭内存缓存的功能。
得比此配置值要大,否则DataNode会出现启动失败的现象。
在默认的情况下,此配置值为0,表明默认关闭内存缓存的功能。
</description>
</property>
这个配置项的名称与实际所使用的功能情况不太一致,有点歧义的感觉,可能叫dfs.datanode.max.cache.memory比较好理解一些。
注意·
第一点,此配置项会受系统最大可使用内存大小(RLIMIT_MEMLOCK)的影响,造成启动DataNode失败的现象,会有如下的错误输出:
上面的记录表明操作系统不能提供相应大小的内存,可以通过ulimit–l<value>命令对此进行调整。一般而言,这个值是在/etc/security/limits.conf文件中配置的。
第二点,此配置项并不是HDFS缓存机制所独有的,它与HDFS的LAZY_PERSIST策略会共享dfs.datanode.max.locked.memory配置。换句话说,如果用于LAZY_PERSIST的存储数据块多了,那么HDFS缓存所能使用的空间自然就会变少。
最后附上几个与HDFS缓存相关的配置参数:
- dfs.datanode.fsdatasetcache.max.threads.per.volume:用于缓存块数据的最大线程数,这个线程数是针对每个存储目录而言,默认值为4。
- dfs.cachereport.intervalMsec:缓存块上报间隔,默认10秒。
HDFS缓存功能默认是关闭的,可以通过配置dfs.datanode.max.locked.memory的值来开启此功能,对于文件数据的读性能将会带来不小的提升。
HDFS缓存适用场景
缓存HDFS中的热点公共资源文件和短期临时的热点数据文件。
第一种场景:公共资源文件。这些文件可以是一些存放于HDFS中的依赖资源jar包,或是一些算法学习依赖的.so文件等。像这类数据文件,放在HDFS上的好处是我们可以在HDFS上全局共享,不用依赖本地机器的资源文件。此外这种做法易于管理,如果想要进行资源包的升级,可以直接更新到HDFS上。但是这种场景更好的做法是把它做成分布式缓存,否则在程序中将会发送大量的请求到NameNode中去获取这些资源文件的内容。而且这种请求量是非常恐怖的,不是说请求一次就够了,而是使用一次就请求一次。
第二种场景:短期临时的热点数据文件。比如集群中每天运行统计的报表数据,需要读取前一天的或是最近一周的数据做离线分析。但是超出这个期限内的数据基本就很少再用到了,就可以视为冷数据了。那么这个时候我们就可以把符合这个时间段的数据做缓存处理,如果数据过期了,就直接从缓存中清除。
以上两种情况,都是HDFS缓存非常适用的场景。
缓存总结构图
HDFSCacheAdmin命令使用
HDFS中用于缓存块操作的相关命令使用。这些命令都集中在hdfscacheadmin命令下,在Hadoop客户端中输入如下指令,就会弹出所有使用命令:
{14:16}~ ➭ hdfs cacheadmin
Usage: bin/hdfs cacheadmin [COMMAND] # 以下为hdfscacheadmin的所有使用命令
[-addDirective -path <path> -pool <pool-name> [-force] [-replication <replication>] [-ttl <time-to-live>]] # 添加缓存单元命令
[-modifyDirective -id <id> [-path <path>] [-force] [-replication <replication>] [-pool <pool-name>] [-ttl <time-to-live>]] # 修改缓存单元命令
[-listDirectives [-stats] [-path <path>] [-pool <pool>] [-id <id>] # 列出满足条件的缓存单元列表
[-removeDirective <id>] # 删除指定id的缓存单元命令
[-removeDirectives -path <path>] # 删除指定路径的缓存单元命令
[-addPool <name> [-owner <owner>] [-group <group>] [-mode <mode>] [-limit <limit>] [-maxTtl <maxTtl>] # 添加新的缓存池
[-modifyPool <name> [-owner <owner>] [-group <group>] [-mode <mode>] [-limit <limit>] [-maxTtl <maxTtl>]] # 修改新的缓存池
[-removePool <name>] # 删除新的缓存池
[-listPools [-stats] [<name>]] # ...
[-help <command-name>] # 查阅具体某条命令的使用帮助信息
以上命令中除了最后一个help帮助命令之外,其余9个命令都与缓存操作相关。在这些命令中,还可以划分为两大类:一类是CachePool相关命令,另一类是CacheDirective相关命令。分类图如下图所示。
HDFS快照管理
快照的概念
在分析HDFS内部的快照管理之前,需要先了解快照的概念。首先有一个根本的原则:“快照不是数据的简单拷贝,快照只做差异的记录。”
这一原则在其他很多系统的快照概念中都是适用的,比如磁盘快照,也是不保存真实数据的。因为不保存实际的数据,所以快照的生成往往非常迅速。在HDFS中,如果在其中一个目录比如/A下创建一个快照,则快照文件中将会存在与/A目录下完全一致的子目录文件结构以及相应的属性信息,通过fscat命令也能看到里面具体的文件内容。但是这并不意味着快照已经对此数据进行完全的拷贝。这里遵循一个原则:对于大多不变的数据,你所看到的数据其实是当前物理路径所指的内容,而发生变更的INode数据才会被快照额外拷贝,也就是前面所说的差异拷贝。
HDFS快照相关命令
一个快照目录下可以有多个快照文件,快照目录可以创建、删除自身目录下的快照文件,同时快照目录本身又被快照目录管理器所管理。这里面就引出了更深层次的内容:HDFS内部的快照管理机制。
快照结构关系(源码)
1、快照管理器管理多个快照目录
其实每个快照目录就是我们非常熟悉的INodeDirectory类。
2、一个快照目录拥有多个快照文件。快照在快照目录中的存放不是很明显,它是作为一个额外属性存在于INodeDirectory的父类INodeWithAdditionalFields中。INodeWithAdditionalFields内部存放有基本的一些变量属性,例如名称、权限、最近修改时间等等,代码中的定义如下:
快照列表存在于一个叫DirectorySnapshottableFeature的Feature继承类中,源码中的定义如下:
由此可见,快照结构如下:
快照调用流程
快照的调用过程,整个过程以快照管理器(SnapshotManager)作为处理中心。
SnapshotManager负责接收快照操作请求,继而调用相关类进行处理。这里的相关类是INodeDirectory中的Feature继承类。所以全部过程分为如下两部分:
上游请求的接收
请求的下游处理
在上游请求接收阶段中,其接收方式与以往直接接收NameNodeRPC请求的方式略有不同,中间还经过了一层FSDirSnapshotOp类。在这个类中调用了SnapshotManager的操作方法。这样做还是有好处的,可以在FSNamesystem的众多操作里很好地辨别和区分操作的类型。
HDFS快照的使用
HDFS的快照有两大用处,下面是具体的使用场景:
·丢失数据的恢复。这里丢失数据指的是相对于创建快照时间点之后丢失的数据。在HDFS的快照中,只会额外复制发生变更的数据,所以在快照内部,自然会存在丢失数据的一个备份,这个时候只需要将对应快照文件目录拷贝一份即可。
·元数据的差异比较。HDFS的快照能够提供diff比较的功能。比较的结果会展示相对于源端快照,目标快照中发生的文件目录的变更记录。这个差异结果可以用于数据的同步,比如快照在DistCp命令中的使用。用DistCp中的diff参数附加两个from、to快照,进行元数据变更的同步,然后利用DistCp的功能,进行真实数据的拷贝,以此实现集群数据间的同步。这也是HDFS快照的一个很好的使用场景。
当然,HDFS快照还可以有其他使用场景,关键看你怎么去利用这个功能特性。