[译]HDFS的中心化缓存 (Centralized Cache Management in HDFS)

原文

概览

HDFS上的中心化缓存是一个显式的缓存机制, 使得用户可以指定哪个路径被缓存. Namenode和拥有指定文件块的DataNode们通讯, 并命令他们将文件块缓存到堆外缓存中.

HDFS的中心化缓存管理有如下的明显优势:

  1. 明确的固定(pinning)可以防止被频繁使用的数据被从内存中移除. 这对那些数据尺寸超过主存的情况很重要, 而这类情况在HDFS上是非常常见.

  2. 因为DataNode的缓存是由NameNode管理的, 应用方可以查询被缓存的文件块的位置, 并决定任务的位置. 将任务和缓存的文件块副本放在一起改善了读的性能.

  3. 当文件块被DataNode缓存后, 客户端可以使用更新, 更高效, 和零拷贝的读API. 因为缓存文件块的校验和验证由DataNode执行了一次, 客户端就能以0开销地使用新API(问: 什么新API?).

  4. 中心化缓存可以改善整个集群的内存使用情况. 当只能依靠各个DataNode的操作系统高速缓存时, 重复地读取一块文件块会导致该块的n个拷贝被读入高速缓存. 使用中心化缓存管理后, 一个用户可以显示指定只有n个副本中的m个可以被固定在缓存中, 并节省n-m的内存.

使用场景

中心化缓存对于被常重复访问的文件非常有用. 例如, Hive里一个较小的事实表, 经常要和其他表在查询中连接, 这就是需要被缓存的一个好候选.
反之, 缓存一个某年的查询报告就没那么必要, 因为历史数据一般就被读一次.

中心化缓存管理对那种有服务等级协议(SLA)有多样差异化的运行负载也非常有用. 缓存那些优先级高的的工作集数据, 可以保证它不用和低优先级的工作集数据竞争磁盘IO. (就像机场的VIP候机厅)

架构

hdfs-central-cache.png

在这个架构中, NameNode负责协调集群中所有DataNode的堆外缓存. NameNode定期地接收各个DataNode发送过来的缓存报告, 报告描述了任意DataNode上被缓存的所有文件块. NameNode通过在心跳响应中发送的缓存和踢出缓存命令来管理DataNode上的缓存.

NameNode查询自身的缓存指令(directives?)来决定哪些路径应该被缓存. 缓存指令被永久存储在文件系统映像(fsimage)和操作日志(edit log)中, 并且可以把java和命令行的api进行添加,删除和修改. NameNode也存储了一些缓存池, 这些管理实体被用来将缓存指令分组, 进行资源管理和权限控制.

NameNode定期地扫描命名空间和缓存指令来决定,哪些文件块要被缓存,哪些要踢出缓存, 并将缓存动作指派到DataNode上. 扫描亦可由用户动作发起, 例如添加或者删除缓存指令, 或删除一个缓存池.

我们当前不会缓存那些, 构建中, 损坏或者不完整的文件块. 如果一个缓存指令涉及到文件链接, 这个链接的目标文件不会被缓存.

当前可以缓存文件或者目录. 文件块或更低级别的缓存将在未来实现.

概念

缓存指令

一个缓存指令定义了要缓存的一个路径. 路径可以是目录或者文件. 目录是不会被递归式缓存的, 只有当前目录这一级的文件会被缓存.

指令同时定义了额外参数, 例如缓存复制因子和过期时间. 缓存复制因子指定缓存要复制多少次. 如果多个缓存指令要缓存某一个文件, 那么最大缓存复制因子就被应用.

过期时间由命令行指定为存活时间(time-to-live, TTL), 一个在未来的相对时间. 当一个缓存指令过期后, 就不会再被NameNode在做缓存决定时考虑到.

缓存池

缓存池作为一个管理实体, 管理着缓存指令的分组. 缓存池有一个UNIX那种权限, 限制哪些用户和组可以访问某个池. 写权限允许用户在某个池上添加和删除缓存指令. 读权限允许用户列出一个池中的缓存指令, 读额外的元数据. 执行权限目前没用到.

缓存池也用以管理资源. 池可以指定当前池中能缓存的数据尺寸的最大限制(byte). 通常, 所有池的缓存限制之和,等于HDFS集群中所有的保留内存(哪里指定?)之和. 缓存池同时也跟踪记录了很多统计来提升用户如何决定什么应该被缓存.

池也可以强制定义一个最大存活时间TTL. 这个定义限制了缓存指令在这个池中的最大存活时间.

缓存管理 命令行接口

在命令行下, 管理员和用户可以通过hdfs cacheadmin命令集, 来操作缓存池和缓存指令.

缓存指令通过一个唯一, 不重复的64位整数ID来识别. 即使这个缓存指令被删掉后, ID也不会被重复使用.

缓存指令命令

addDirective

用法: hdfs cacheadmin -addDirective -path 路径 -pool 缓存池名 [-force] [-replication 复制因子] [-ttl 存活时间]
添加一个新的缓存指令

参数 说明
路径 要缓存的路径, 这个路径可以是目录或文件(通配符可以吗?)
缓存池名 要把这个缓存指令加到哪个缓存池中. 你必须要有这个缓存池的写权限才能加缓存指令
-forece 不检查这个缓存池的最大尺寸限制
缓存复制因子 缓存复制多少份,默认是1
存活时间 这个缓存指令的有效期, 可以指定为分钟, 小时, 天. 例如 30m, 4h, 2d. 有效单位是smhd. 用"never"来指定一个缓存永远存活, 如果不指定, 这个缓存指令就永不过期

removeDirective

用法: hdfs cacheadmin -removeDirective
删除一个缓存指令

参数 说明
id 要删除的缓存指令的id, 你必须有这个缓存指令的缓存池的写权限才能删除它. 要列出缓存指令的id, 请用-listDirectives命令

removeDirectives

用法: hdfs cacheadmin -removeDirectives 路径
删除指定路径相关所有的缓存指令

参数 说明
路径 要删除的缓存指令的路径, 你必须有这个缓存指令的缓存池的写权限才能删除它. 要列出缓存指令的id, 请用-listDirectives命令

listDirectives

用法: hdfs cacheadmin -listDirectives [-stats] [ -path 路径 ] [ -pool 池]
列出缓存指令

参数 说明
路径 只列出这个路径相关的缓存指令. 注意, 如果对应这个路径的某个缓存指令所在的缓存池你没有读权限, 那这个缓存指令就不会列出.
缓存池 只列出这个缓存池中的缓存指令
-stats 列出基于路径的缓存指令统计汇总

缓存池命令

addPool

用法: hdfs cacheadmin -addPool 缓存池名 [-owner 所有者用户名] [-group 用户组] [-mode 模式] [-limit 尺寸限制] [-maxTtl 最大存活时间]

参数 说明
缓存池名 缓存池的名字(最大长度?特殊字符?)
所有者 这个缓存池所有者的用户名, 默认是当前用户名
用户组 这个池的用户组. 默认值是当前用户的主组的名字
模式 这个池的UNIX风格的权限模式. 权限模式用8进制表示. 例如. 0755. 默认值是0755
尺寸限制 结合这个池上所有缓存指令, 这个池能缓存的最大字节数. 默认值是没有限制
最大存活时间 对这个池,缓存指令能指定的最大存活时间. 可以指定为 秒, 分, 时, 天. 例如 120s, 30m, 4h, 2d. 有效单位是[smhd]. 默认是没有最大值限制. 也可以用"never"来表示没有限制

modifyPool

用法: hdfs cacheadmin -modifyPool 缓存池名 [-owner 所有者用户名] [-group 用户组] [-mode 模式] [-limit 尺寸限制] [-maxTtl 最大存活时间]
修改一个已经存在的缓存池的元数据

参数 说明
缓存池名 缓存池的名字
所有者 这个缓存池所有者的用户名
用户组 这个池的用户组
模式 这个池的Unix风格的8进制权限
尺寸限制 这个池能缓存的最大byte数
最大存活时间 这个池里缓存指令的最大存活时间

listPools

用法: hdfs cacheadmin -listPools [-stats] [名字]
列出一个或者多个缓存池的信息, 例如: 名字, 所有者, 权限, 等等

参数 说明
-stats 显示为额外缓存池的统计信息
名字 如果指定, 只列出命名为此的缓存池

help

用法: hdfs cacheadmin -help 命令名
显示某个命令的详细帮助信息

参数 说明
命令名 要查看帮助的命令. 如果没有指定,显示所有命令的详细帮助

配置

Native Libraries (原生库)

为了将文件块锁定在内存中, DataNode依赖于libhadoop.so或者hadoop.dll(windows)中的JNI代码. 要用HDFS中心缓存管理, 请确保启动JNI.

配置属性

必须项

确保以下配置:

  • dfs.datanode.max.locked.memory
    这个属性决定一个DataNode可以用以缓存的最大内存数量. 在Unix类系统, "locked-in-memorysize" 在ulimit(ulimit -l)中, DataNode的用户必须将其增加到和这个属性配置对应的值. (请参考OS限制). 配置这个值时, 请留意其他需要内存的程序, 例如DataNode和Jvm应用堆内存和操作系统缓存.

这个配置和延迟序列化写特性共享. 数据节点会确保中心化缓存管理和延迟序列化写特性所使用的内存的总额不会超过dfs.datanode.max.locked.memory配置的值.

可选项

以下配置属性不是必须的, 但可能用于调优:

  • dfs.namenode.path.based.cache.refresh.interval.ms
    NameNode用这个配置的毫秒数为周期进行路径缓存扫描. 这个扫描计算要缓存的文件块和要缓存文件块副本的各个DataNode
    默认下, 这个参数的值是300000毫秒, 5分钟.

  • dfs.datanode.fsdatasetcache.max.threads.per.volume
    DataNode用这个配置作为每个卷的最大线程数, 来缓存新数据.
    默认下, 这个参数是4

  • dfs.cachereport.intervalMsec
    DataNode以这个毫秒数为周期来向NameNode发送其缓存状态的报告
    默认下, 这个参数是10000毫秒, 10秒钟.

  • dfs.namenode.path.based.cache.block.map.allocation.percent
    这个参数决定我们要分配多少Java堆内存给缓存文件块map. 缓存文件块map是一个用链式哈希的一个哈希map. 如果map比较小,而缓存的文件块数量大, 那访问map速度就慢. 比较大的map会消耗更多内存. 默认值是0.25%.

OS Limits 操作系统限制

如果你看到这个错误:"Cannot start datanode because the configured max locked memory size… is more than the datanode’s available RLIMIT_MEMLOCK ulimit" (无法启动DataNode, 因为配置的max locked memory大于DataNode可用的RLIMIT_MEMLOCK ulimit). 这个表示操作系统配置的内存限制比你配置在HDFS里的要小. 要修复, 你要调整DataNode运行的ulimit -l值. 通常, 这个值是配置在 /etc/security/limits.conf 文件. 不过, 也取决于你使用的操作系统的版本.

当你可以从shell里执行"ulimit -l"并得到一个值大于你配置到dfs.datanode.max.locked.memory的值,或者"unlimited",意味着没有限制,就说明你已经正确地配置了系统的限制. 请注意, "ulimit -l"命令输出的memory lock limit的单位是KB,但dfs.datanode.max.locked.memory的单位必须指定为byte.

这个提示并不能应用到windows上的部署. 因为windows上没有"ulimit -l"对应的命令

引用:
https://blog.csdn.net/chenKFKevin/article/details/61196409

你可能感兴趣的:([译]HDFS的中心化缓存 (Centralized Cache Management in HDFS))