深入理解 Hadoop (三)HDFS文件系统设计实现

深入理解 Hadoop (一)网络通信架构与源码浅析
深入理解 Hadoop (二)HDFS架构演进
深入理解 Hadoop (三)HDFS文件系统设计实现
深入理解 Hadoop (四)HDFS源码剖析
深入理解 Hadoop (五)YARN核心工作机制浅析
深入理解 Hadoop (六)YARN核心设计理念与工作流程剖析
深入理解 Hadoop (七)YARN资源管理和调度详解

HDFS FileSystem NameNode 端抽象实现

HDFS 磁盘元数据文件解读

在这里插入图片描述
共有五种格式的文件:
edits_0000000000000041912-0000000000000041913:该 LogSegment 记录了 transaction id 在 41912-41913 之间的事务日志。(最多保留 50 个)
edits_inprogress_0000000000000041914:正在使用的 编辑日志文件,从 transaction id = 41914 开始,之后的事务都往这个文件中进行记录,直到进行了 rollLog 操作:生成一个新的 edits_inprogress_start_transaction_id 文件,把旧的 edits_inprogress_start_transaction_id 改名成 edits_(start_transaction_id)_(end_transaction_id) 。
fsimage_0000000000000041843 和 fsimage_0000000000000041843.md5:transaction id = 41843 以前的事务,都合并到了这个 fsimage 文件中了,.md5 文件存储了它的校验信息(最多保留 2 个)
seen_txid:存储最新的 fsimage 文件的 最新的 transaction id
VERSION:版本信息

HDFS FileSystem NameNode 内部结构

在这里插入图片描述
类比 ZooKeeper 存储模型中的 DataTree + DataNode,NameNode 内存树抽象为 FSDirectory + INode(两个实现类:INodeDirectory: 内部有一个集合 List< INodeDirectory> 或 INodeFile + 文件内部 List< Block>),每个 INode 内部有维护有一个 INode parent。

NameNode 元数据内存部分

也即 FSDirectory 维护的名称空间
在这里插入图片描述
上图涉及到的核心抽象:

  • FileSystem:具体实现: DistributedFileSystem、LocalFileSystem、FSNameSystem
  • FSDirectory
  • INode(INodeDirectory + INodeFile)
  • FSImage
  • FSEditlog

NameNode 磁盘部分核心抽象

public class FSImage implements Closeable {
    // 管理磁盘编辑日志
    protected FSEditLog editLog = null;
    // 管理存储目录
    protected NNStorage storage;
    // 元数据存储目录格式化
    void format(...) throws IOException {}
    // 加载磁盘编辑日志恢复到内存
    long loadEdits(...) throws IOException {}
    // 加载磁盘 fsimage 镜像文件恢复到内存
    void loadFSImage(....) throws IOException {}
    // 生成 fsimage 镜像文件
    void saveFSImage(...) throws IOException {}
    // 保存命名空间
    void saveNamespace(...) throws IOException {}
    // 接收到 SecondaryNameNode 发送的要进行 checkpoint 的请求之后执行的操作
    NamenodeCommand startCheckpoint(...) throws IOException {
        CheckpointSignature sig = rollEditLog(layoutVersion);
        return new CheckpointCommand(sig, needToReturnImg);
    }
}

public class FSEditLog implements LogsPurgeable {
    // dfs.namenode.shared.edits.dir 目录 = qjournal://bigdata02:8485;bigdata03:8485;bigdata04:8485/hadoop330ha
    private final List<URI> editsDirs;
    // dfs.namenode.shared.edits.dir 目录 = qjournal://bigdata02:8485;bigdata03:8485;bigdata04:8485/hadoop330ha
    private final List<URI> sharedEditsDirs;
    private JournalSet journalSet = null;
    EditLogOutputStream editLogStream = null;
    // 事务控制
    private long beginTransaction() {}
    private void endTransaction(long start) {}
    // 记录日志操作, 记录一条日志到 edit_inprogress 文件里面
    void logEdit(final FSEditLogOp op) {}
    synchronized void logEdit(final int length, final byte[] data) {}
    // 开启一个新的编辑日志 LogSegment
    void startLogSegment() throws IOException {}
}

HDFS FileSystem DataNode 端抽象实现

HDFS DataNode 磁盘数据文件解读

HDFS DataNode 支持多磁盘存储,通过以下配置生效:

<property>
    <name>dfs.datanode.data.dir</name>
    <value>dir1,dir2,dir3</value>
</property>

数据目录下的目录结构如下:

  • dir1
    • blockpool 1
      • current
        • finalized 已写成功的数据块的存储目录
          • 还会划分两级存储目录,然后再存数据块
        • rbw 正在执行写操作的数据块
        • layzpresistent:懒持久化,可以配置,写入数据块的时候,先写到内存中,然后到某了合适的时间,再持久化到磁盘
      • tmp
    • blockpool 2
  • dir2
    • blockpool 1
    • blockpool 2
  • dir3
    • blockpool 1
    • blockpool 2

注意:每个 blockpool 对应联邦集群中的一个 NameService

DataNode 的每个数据存储目录结构示例如下:

// 这个 current 就表示是某一个 配置的存储目录(dir1, dir2, dir3 的其中之一)
├── current
    // 块池目录
    ├── BP-2052521754-192.168.123.102-1614493867466
    ├── BP-2052521754-192.168.123.102-1614493867477
    │ ├── current
    │ │ ├── dfsUsed
    │ │ ├── finalized
    │ │ │ └── subdir0
    │ │ │ ├── subdir0
    │ │ │ ├── subdir1
    │ │ │ ├── subdir10
    │ │ │ │ ├── blk_1073744394
    │ │ │ │ ├── blk_1073744394_3617.meta
    │ │ │ │ ├── blk_1073744618
    │ │ │ │ └── blk_1073744618_3841.meta
    │ │ │ ├── subdir11
    │ │ │ │ ├── blk_1073744640
    │ │ │ │ ├── blk_1073744640_3863.meta
    │ │ │ │ ├── blk_1073744892
    │ │ │ │ └── blk_1073744892_4115.meta
    │ │ │ ├── subdir12
    │ │ │ │ ├── blk_1073744948
    │ │ │ │ ├── blk_1073744948_4171.meta
    │ │ │ │ ├── blk_1073745141
    │ │ │ │ └── blk_1073745141_4375.meta
    │ │ │ ├── subdir2
    │ │ │ ├── subdir3
    │ │ │ ├── subdir4
    │ │ │ ├── subdir5
    │ │ │ ├── subdir6
    │ │ │ ├── subdir7
    │ │ │ ├── subdir8
    │ │ │ │ ├── blk_1073744026
    │ │ │ │ ├── blk_1073744026_3243.meta
    │ │ │ │ ├── blk_1073744038
    │ │ │ │ └── blk_1073744038_3261.meta
    │ │ │ └── subdir9
    │ │ │ ├── blk_1073744252
    │ │ │ ├── blk_1073744252_3475.meta
    │ │ │ ├── blk_1073744377
    │ │ │ └── blk_1073744377_3600.meta
    │ │ ├── rbw
    │ │ └── VERSION
    │ ├── scanner.cursor
    │ └── tmp
    └── VERSION
├── in_use.lock

上述目录结构的一些相关解释:
BP-2052521754-192.168.123.102-1614493867477:在 HDFS Fedaration 集群中,有多个NameSpace,对应多组 NameNode,每一组 NameNode 都有一个独立的 BlockPool 块池,一个 BlockPool 块池目录保存了 该 BlockPool 在当前存储目录中的所有数据块。
VERSION:版本文件,该文件是一个标准的 Properties 文件,可自行查看
finalized:数据块存储目录,保存的是写入成功的数据块,包含数据块文件和 .meta 校验文件
rbw:数据块存储目录,保存的是正在写入的数据块,包含数据块文件和 .meta 校验文件
tmp:数据块存储目录
scanner.cursor:DataNode 对数据块进行校验的一个遍历游标,用来记录此时遍历到的数据块的位置
in_use.lock:DataNode 线程持有的目录锁,防止多线程对该文件夹进行修改操作

DataStorage 抽象

DataStorage 管理与组织磁盘存储目录。
在这里插入图片描述

public abstract class Storage extends StorageInfo {
    // 一个 DataNode 可以配置多个存储目录
    private final List<StorageDirectory> storageDirs = new CopyOnWriteArrayList<>();
}

public class DataStorage extends Storage {
    public final static String BLOCK_SUBDIR_PREFIX = "subdir";
    final static String STORAGE_DIR_DETACHED = "detach";
    public final static String STORAGE_DIR_RBW = "rbw";
    public final static String STORAGE_DIR_FINALIZED = "finalized";
    public final static String STORAGE_DIR_LAZY_PERSIST = "lazypersist";
    public final static String STORAGE_DIR_TMP = "tmp";
    
    // BlockPoolSliceStorage 负责管理块池目录
    private final Map<String, BlockPoolSliceStorage> bpStorageMap = Collections.synchronizedMap(
        new HashMap<String, BlockPoolSliceStorage>());
}

FsDatasetImpl 抽象

管理和组织 DataNode 上的数据块及其元数据。
在这里插入图片描述

// FsDatasetImpl 负责为 DataNode 提供磁盘服务
class FsDatasetImpl implements FsDatasetSpi<FsVolumeImpl> {
    // DataNode 上的所有数据块的一个管理载体
    final ReplicaMap volumeMap;
    // 存储目录管理组件
    private final FsVolumeList volumes;
}

// FsVolumeList 就是对多个存储目录 FsVolumeImpl 的一个封装抽象
class FsVolumeList {
    private final CopyOnWriteArrayList<FsVolumeImpl> volumes = new CopyOnWriteArrayList<>();
}

// 一个 FsVolumeImpl 负责管理一个存储目录下的所有数据块,一个存储目录下又有多个块池,所以映射到多个 BlockPoolSlice 来进行管理
public class FsVolumeImpl implements FsVolumeSpi {
    // 记录存储位置信息
    private final StorageLocation storageLocation;
    // 对应的数据块管理组件
    private final FsDatasetImpl dataset;
    // 一个 FsVolumeImpl 映射到多个块池,BlockPoolSlice 负责管理一个块池
    private final Map<String, BlockPoolSlice> bpSlices = new ConcurrentHashMap<String, BlockPoolSlice>();
}

class ReplicaMap {
    // 一个 BlockPool 一个 TreeSet
    private final Map<String, FoldedTreeSet<ReplicaInfo>> map = new HashMap<>();
}
  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值