说明
HDFS引入了集中式缓存管理功能,使用hdfs cacheadmin命令可以显示的将目录放到集中式缓存中。
可以配置datanode缓存内存占比
FsDatasetImpl中和缓存相关的方法调用了FsDatasetCache对应的方法。
FsDatasetCache类
- 提供管理Datanode上缓存数据块的功能
- 通过调用mmap(2)和mlock(2)系统调用在Datanode的内存中缓存数据块
- mappableBlockMap字段保存了当前Datanode上所有的缓存数据块信息,保存了blockId和(state,mmapableBlock)映射关系。
state字段
caching
caching_cancelled
cached
uncaching: 从缓存中移除的数据块
mappableBlock
缓存的HDFS数据块,包含的重要字段mmap,lock,以及重要的load方法
- mmap(MappedByteBuffer类型)
JDK提供的直接字节缓冲区,内容是文件的内存映射区域 - mmap的初始化
MappableBlock.load调用NIO,FileChannel.map文件映射到内存,操作mappedbuffer,操作系统flush到数据块中。 - mmap的lock
需要lock这部分内存,防止被swap出去 - mmap的校验
load调用verifyChecksum方法 - mmap使用
零拷贝读
cacheBlock
- 在mappableBlockMap字段中增加新的数据块映射关系,设置数据块的状态是caching
- 调用FsVolumeImpl异步加载任务,就是调用MappableBlock.load()将数据块映射到内存
- 更改缓存快状态为CACHED
- 更新FsDatasetCache.mappableBlockMap的mappableBlock的引用
- 设置副本可以短路读
uncacheBlock
看mappableBlockMap的状态
- 如果map中没有记录,那么就不操作
- 如果是caching,那么修改状态为caching_cancelled,异步任务cachingTask发现状态改变为caching_cancelled时,会删除map中数据块信息。(修改map加锁)
- cached状态,构造移除任务。(uncachingTask)MappableBlockMap中删除记录。
FsDatasetImpl.cache
最终调用cacheBlock()方法
代理模式,获取副本的blockFileName,length,genstamp以及FsVolumeImpl的cacheExecutor对象,然后调用FsDatasetCache.cacheBlock()方法。
FsDatasetImpl.uncached
数据块从缓存中移除,最终调用的是FsDatasetCache.uncacheBlock()方法
数据块汇报方法
FsDatasetImpl的getBlockReports()和getCacheReport()用户获取块汇报和缓存汇报信息。
getBlockReports
DatanodeProtocol.blockReport方法向Namenode汇报数据节点对应块池所有数据块副本信息。
- getBlockReport参数,返回值
bpid
Map<DatanodeStorage,BlockListAsLongs>
保存了存储目录和所有块副本对应信息,DatanodeStorage通过FsVolumeImpl.toDataStorage获取,副本信息通过FsDatasetImpl的volumeMap即可获取。 - 不同状态的副本放入到不同的集合中,返回。
BlockListAstLongs就是不同状态volumeMap的集合。
一个DN上会具有多个FsVolume,对应多个目录。每个目录有有多个块池,所以按照volume遍历,FsVolumeImpl中保存了各个状态块副本信息。
缓存块汇报方法
datanode通过DatanodeProtocol.cacheReport向Namenode汇报,获取当前池块在当前Datanode上所有数据副本块的信息。
- FsDatasetCache.getCacheBlocks()方法
- 遍历FsDatasetCache.mappableBlockMap字段中保存的缓存数据块,过滤状态为CACHED的缓存数据块保存到一个集合中,返回。
- 输入,返回
blockId
List<Long>:保存的是BlockId