首页 > 代码库 > Centralized Cache Management in HDFS
Centralized Cache Management in HDFS
Centralized Cache Management inHDFS
Overview
HDFS中的集中式缓存管理是一个显式的管理缓存的机制,它允许用户指定被HDFS缓存的路径。NameNode将与磁盘上有所需的Block的DataNode通信,命令其在堆外缓存里缓存Block。
HDFS中的集中式缓存管理有许多重要的优势。
1. 明确地防止频繁使用的数据被赶出内存。当工作集的大小超过住内存的大小时,这是特别重要的,这对HDFS负载是很常见的。
2. 因为DataNode缓存被NameNode管理,应用程序在做任务位置决定时可以查询被缓存的Block的位置。将一个task与一个缓存块的一个副本协同工作。
3. 当Block被一个DataNode缓存时,客户端可以使用一个新的,更有效的,0-copy的读操作API。因为缓存的块的checksum检查只被DataNode做一次,客户端可以使用新的API带来0开销的读操作。
4. 集中式缓存可以全面提高了集群内存的利用率。当依赖每个DataNode上操作系统的Buffer Cache时,重复读一个Block将导致这个块的N个副本被放到Buffer Cache中。使用集中式缓存管理,一个用户可以明确的创建m个副本,节省n-m个副本的内存。
User Cases
集中式缓存管理对于重复访问的文件是有用的。例如,hive中的一个小的fact table,在join操作时经常被用到,这个小的fact table就是一个很好的缓存的候选数据。另一方面,缓存一年的查询报告可能用处不大,因为这些历史数据可能只被读一次。
集中式缓存管理对于有服务级别协议的混合负载也是非常有用的。缓存高优先级负载的工作集确保低优先级的负载不竞争磁盘I/O。
Architecture
在这个架构中,NameNode负载协调集群中所有的DataNode栈外缓存。NameNode周期性地从每一个DataNode中收到一个缓存报告,这个报告描述了缓存在特定DataNode上的所有的Block。NameNode通过在心跳消息中背带缓存和不缓存的命令管理DataNode的缓存。
NameNode查询它的一系列缓冲指令来判定应该被缓存的路径。缓冲指令持久化存储在FsImage和editlog文件中,可以通过java或者命令行API被增加,删除和修改。NameNode以存储一系列的缓冲池,这是管理实体为了资源管理和强制许可用来分组缓存指令。
NameNode周期性地扫描命名空间和Active的缓存指令来判定哪一个Block需要被缓存或者移除缓存,分配DataNode的缓存。重新扫描在用户执行像增加或者移除一条缓存指令或者移除一个缓冲池的时候被触发。
目前,当Block正在构建、损坏或者有其他未完成的情况,Block不会被缓存。如果缓存指令是缓存一个符号链接,符号链接的目标不会被缓存。
缓存目前只在文件或者目录级别。Block和子Block的缓存是将来工作中的一条。
Concepts
Cache Directive
一个缓存指令定义了一个应该被缓存的路径。路径要么是目录要么是文件。目录非递归地被缓存,意味着值缓存目录列表中的文件级别的文件。
指令也指定额外的参数,像缓存副本因子和过期时间。副本因子指定被缓存的Block的副本的个数。如果多个缓存指令引用了同一个文件,最小的缓存副本因子将被应用。
过期时间在命令行作为TTL被指定,一个相对的过期时间。在一条缓存指令过期时,当NameNode做缓存决定时,它不在被NameNode考虑。
Cache pool
一个缓冲池是一个管理实体,用来管理缓存指令的分组。缓冲池有类Unix的权限,它限制用户和用户组访问缓冲池。写权限允许用户增加和删除缓冲池中的缓冲指令。读权限允许用户列出缓冲池中的缓冲指令和额外的元数据。没有可执行权限的概念。
缓冲池也被用来资源管理。缓冲池可以设置一个最大值,这个最大值限制缓冲池中指令总的可以被缓存的数据的大小。正常情况下,缓冲池限制的和大约等于集群中HDFS缓存的总的剩余。缓冲池也追踪很多的统计数据来帮助集群用户判断应该缓存什么。
缓冲池也可以设置最大的过期时间。这将限制增加到缓冲池中的指令的最大的过期时间。
cacheadmin command-line interface
在命令行中,管理员和用户可以通过hdfs cacheadmin子命令与缓冲池和指令交互。
缓冲指令通过一个全局唯一的,不重复的64为整数ID来标识。即使缓存之后再之后被删除,ID也不会被重用。
缓冲池通过一个全局唯一的字符串名字标识。
Cache directive commands
AddDirective
Usage:hdfs cacheadmin-addDirective -path <path> -pool <pool-name> [-force] [-replication<replication>] [-ttl <time-to-live>]
增加一个新的缓存指令:
<path> | A path to cache. The path can be a directory or a file. |
<pool-name> | The pool to which the directive will be added. You must have write permission on the cache pool in order to add new directives. |
-force | Skips checking of cache pool resource limits. |
<replication> | The cache replication factor to use. Defaults to 1. |
<time-to-live> | How long the directive is valid. Can be specified in minutes, hours, and days, e.g. 30m, 4h, 2d. Valid units are [smhd]. "never" indicates a directive that never expires. If unspecified, the directive never expires. |
removeDirective
Usage: hdfs cacheadmin-removeDirective <id>
移除一个缓存指令。
<id> | The id of the cache directive to remove. You must have write permission on the pool of the directive in order to remove it. To see a list of cachedirective IDs, use the -listDirectives command. |
removeDirectives
Usage: hdfs cacheadmin-removeDirectives <path>
移除所有路径列表中指定的缓存指令。
<path> | The path of the cache directives to remove. You must have write permission on the pool of the directive in order to remove it. To see a list of cache directives, use the -listDirectives command. |
listDirectives
Usage: hdfs cacheadmin-listDirectives [-stats] [-path <path>] [-pool <pool>]
列出所有的缓存指令。
<path> | List only cache directives with this path. Note that if there is a cache directive forpath in a cache pool that we don‘t have read access for, it will not be listed. |
<pool> | List only path cache directives in that pool. |
-stats | List path-based cache directive statistics. |
Cache pool commands
addPool
Usage: hdfs cacheadmin -addPool<name> [-owner <owner>] [-group <group>] [-mode <mode>][-limit <limit>] [-maxTtl <maxTtl>
增加一个新的缓冲池。
<name> | Name of the new pool. |
<owner> | Username of the owner of the pool. Defaults to the current user. |
<group> | Group of the pool. Defaults to the primary group name of the current user. |
<mode> | UNIX-style permissions for the pool. Permissions are specified in octal, e.g. 0755. By default, this is set to 0755. |
<limit> | The maximum number of bytes that can be cached by directives in this pool, in aggregate. By default, no limit is set. |
<maxTtl> | The maximum allowed time-to-live for directives being added to the pool. This can be specified in seconds, minutes, hours, and days, e.g. 120s, 30m, 4h, 2d. Valid units are [smhd]. By default, no maximum is set. A value of "never " specifies that there is no limit. |
modifyPool
Usage: hdfs cacheadmin-modifyPool <name> [-owner <owner>] [-group <group>] [-mode<mode>] [-limit <limit>] [-maxTtl <maxTtl>]
修改一个已经存在的缓冲池的元数据。
<name> | Name of the pool to modify. |
<owner> | Username of the owner of the pool. |
<group> | Groupname of the group of the pool. |
<mode> | Unix-style permissions of the pool in octal. |
<limit> | Maximum number of bytes that can be cached by this pool. |
<maxTtl> | The maximum allowed time-to-live for directives being added to the pool. |
removePool
Usage: hdfs cacheadmin-removePool <name>
移除一个缓冲池。这将同时移除相关的路径。
<name> | Name of the cache pool to remove. |
listPools
Usage: hdfs cacheadmin -listPools[-stats] [<name>]
显示一个或者多个缓冲池的信息,例如名字,所有者,用户组,权限等等。
-stats | Display additional cache pool statistics. |
<name> | If specified, list only the named cache pool. |
Help
Usage: hdfs cacheadmin -help<command-name>
关于一个命令的详细的帮助信息。
<command-name> | The command for which to get detailed help. If no command is specified, print detailed help for all commands. |
Configuration
Native Libraries
为了将Block文件锁定在内存,DataNode依赖libhadoop.so中的本地JNI代码。如果你使用HDFS集中式缓存管理的话,确定开启了JNI。
Configuration Properties
Required
确定配置了下面的配置:
1. dfs.datanode.max.locked.memory
这决定了一个DataNode将要用来被做HDFS缓存的内存的最大值。用ulimit –l可以用来查看DataNode节点的程序锁定内存的限制,用户需要增加这个值以适应这个配置的参数。当设置了这个值之后,请记住,你将需要内存中的空间做其他事,像DataNode和应用的JVM的堆栈和操作系统的页面缓存。
Optional
下面的属性是不必要的,担在调优的时候可以指定:
1. dfs.namenode.path.based.cache.refresh.interval.ms
NameNode将使用这个值作为两次连续的缓存扫描的时间间隔。这将计算缓存的块数和每个包含一个Block的副本的DataNode应该缓存这个Block。
2. dfs.datanode.fsdatasetcache.max.threads.per.volume
DataNode将使用这个值作为每个Volume用来缓存新块的最大的线程数。
默认,这个值被设置为4.
3. dfs.cachereport.intervalMsec
DataNode将使用这个值作为两次发送完整的缓存状态的报告到NameNode的时间间隔。
默认,这个值被设置为10000,也就是10秒。
4. dfs.namenode.path.based.cache.block.map.allocation.percent
我们申请用来缓存Block的java堆的百分比。这个Map是一个HashMap。如果缓存块的数量太大,比较小的Map可能访问很慢,较大的map将会消耗更多的内存(hashmap的机制)。默认是0.25。
OS Limits
如果你得到一个错误,Cannot start datanode because the configured maxlocked memory size... is more than the datanode‘s available RLIMIT_MEMLOCKulimit,,这个意思是说,操作系统在你lock的内存总量设置了一个比你配置的值低的limit。为了修复这个错误,你必须调整运行DataNode的机器的ulimit -l的值。通常,这个值在 /etc/security/limits.conf中被设置。但是,根据你使用的操作系统和发行版的不同会有变化。
当你在shell运行ulimit -l命令时,你将知道你是否正确的设置了新的值。这个命令应该返回一个高于你在dfs.datanode.max.locked.memory中设置的值,或者是字符串“ulimited”,代表没有限制。注意,ulimit-l的输出通常是KB,但是dfs.datanode.max.locked.memory必须以byte设置。