HDFS学习笔记【Datanode/FsDatasetImpl/缓存】

HDFS引入了集中式缓存管理,允许使用hdfscacheadmin命令将目录放入缓存。FsDatasetCache类通过mmap和mlock系统调用来管理Datanode的内存缓存,包括添加、取消缓存数据块以及状态管理。缓存块的加载和卸载涉及到FsDatasetImpl和FsVolumeImpl的交互,同时Datanode会通过blockReport和cacheReport向Namenode汇报块和缓存信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明

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
### Hadoop 中 `./bin/hdfs dfs -ls /` 和 `./bin/hdfs dfs -ls .` 的区别 在 Hadoop 文件系统 (HDFS) 中,命令的行为取决于其上下文以及如何解析路径。以下是关于为何 `./bin/hdfs dfs -ls /` 能成功执行而 `./bin/hdfs dfs -ls .` 会失败的具体原因。 #### 绝对路径 vs 当前工作目录 - **绝对路径 `/`:** 使用 `hdfs dfs -ls /` 或者通过完整路径调用 `/usr/local/hadoop/bin/hdfs dfs -ls /` 时,指定的是根目录的绝对路径。这表示操作的目标是 HDFS 上的根目录[^1]。 - **相对路径 `.`:** 在 Linux Shell 环境中,`.` 表示当前的工作目录。然而,在 HDFS 命令中,`.` 并不映射到本地文件系统的当前目录,而是尝试将其解释为 HDFS 中的一个路径。由于 HDFS 不维护与本地文件系统相同的当前工作目录概念,因此该命令通常无法找到对应的路径并返回错误[^2]。 #### 工作机制分析 当运行 `hdfs dfs -ls .` 时,客户端试图将 `.` 解析为 HDFS 中的有效路径。但是,HDFS 客户端并不知道用户的本地工作目录是什么,它只会按照默认配置去查找用户主目录下的子路径(通常是 `/user/<username>`)。如果未显式设置任何额外参数,则可能会抛出找不到路径的异常。 另一方面,`/` 是明确指向 HDFS 根目录的全局唯一标识符,无论在哪种环境下都能被正确识别和访问。 ```bash # 正确的方式:列出 HDFS 根目录的内容 /usr/local/hadoop/bin/hdfs dfs -ls / # 错误方式:尝试列出名为 "." 的 HDFS 路径内容 /usr/local/hadoop/bin/hdfs dfs -ls . ``` 上述情况表明,对于 HDFS 来说,“.”并不是一个有效的路径描述符,除非特别定义了一个匹配此符号的实际位置。 ### 总结 为了确保兼容性和准确性,在使用 HDFS CLI 进行资源管理时应始终采用完整的或者至少部分限定的路径名来代替可能引起歧义的相对地址表达形式如“.”这样的标记。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值