美文网首页
关于Hdfs拆锁的学习和思考

关于Hdfs拆锁的学习和思考

作者: _Kantin | 来源:发表于2021-10-22 17:22 被阅读0次

    背景

    • 最近学习腾讯/美团关于如何拆namenode大锁的方案,总体方案上大概相似,特此进行记录。

    • 笔者目前在hdfs使用和原理上相对熟悉,但是源码层面的实现原理阅读不多,也经常关注社区关于分布式存储的动态,希望在不久能看懂各位大佬的优秀思路和实现。

    • 这是一篇关于namenode锁优化的常更文章,非全部原创。内容来源于笔者日常阅读和学习。

    全局锁机制

    hdfs HA部署架构
    • 从下图hdfs HA部署架构图中可看出是比较复杂的。部署上要求至少要引入三个 zookeeper 节点,三个 JournalNode 节点,两个 ZKFC 节点。文件系统的 inode 信息和 block 信息以及 block 的 location 信息全部在 NameNode 的内存中维护,这使得 NameNode 对内存的要求非常高,需要定制大内存的机器才能承载更大的元数据量。


      hdfs部署架构
    hdfs 全局锁的分类
    • 首先关于锁的类型,在NameNode使用了JDK提供的可重入读写锁,一句话概括就是:读锁并行写锁排它。
    • 全局锁管理的主要数据结构大概分为下列三种
      • 目录树:文件系统的全局目录视图。获取目录树上任一节点的信息必须先拿到全局读锁;目录树上任一节点新增、删除、修改都必须先拿到全局写锁
      • 数据块集合:文件系统的全量数据信息。获取其中任一数据块信息必须先拿到全局读锁;新增、删除,修改都必须先拿到全局写锁。
      • 集群信息:HDFS集群节点信息的集合。获取节点信息等必须先拿到全局读锁;注册,下线或者变更节点信息请求处理时必须先拿到全局写锁


        NN全局锁的作用范围
    hdfs 锁的类型
    • 从NameNode的核心处理逻辑路径上有两把锁:FSNamesystemLock和FSEditLogLock,其中FSNamesystemLock类型采用可重入读写锁,也是待优化的全局锁,而FSEditLogLock则采用Synchronized排它锁。
    • 当一个client请求如果涉及到对数据写操作,则需要持有的锁流程是:(1)获取全局锁(FSNamesystemLock)入口:外部RPC请求从IPC层进入NameNode和内部线程请求;(2)获取局部锁(FSEditLogLock)入口:主要来源外部RPC请求对元数据的写操作;
    • 以RPC请求mkdir为例,其步骤如下:
      • (1)RPC请求从IPC层进入NameNode;
      • (2)获取全局写锁(FSNamesystemLock#writeLock#lock),如果持有读锁或者写锁的请求正在被处理,排队等待;
      • (3)更新内存目录树结构;
      • (4)释放全局写锁(FSNamesystemLock#writeLock#unlock);
      • (5)获取EditLog排它锁;
      • (6)写EditLog;
      • (7)释放EditLog排它锁;
      • (8)通过IPC层将结果返回客户端;
    关于hdfs两把锁的拆分
    • 在这里笔者思考下为何不把EditLog读写锁也并在FSNamesystemLock锁内执行,这种不更符合全局一把锁的含义?当前这样会带来很差的性能瓶颈,也不符合锁越少越好的软件设计初衷。但是为啥性能会查很多?我觉得主要与EditLog的流程相关。
    • 我们都知道NameNode修改一条元数据后需要写一条edits log并保证都有一个全局顺序递增(加锁)的transactionId,再写本地磁盘 + 网络传输给journalnodes。磁盘写 /网络写都是巨大的性能瓶颈,因此分开成两个锁本身就有很强的必要性,关于写editlog的过程hadoop也做了很大的优化。

    关于拆锁的过程

    关于拆锁的必要性讨论
    • 首先先明确下拆锁的必要性,得出的结论必须拆
    • 在这里也先明确下拆锁是一件很复杂很难的事情。
    • 为什么要拆?首先全局上看主要是分离的两把锁,在通常情况下,FSNamesystemLock锁范围要远大于FSEditLogLock锁范围。考虑负载较高的大规模集群,按照9:1读写比预估,只有10%请求需要同时获取FSNamesystemLock和FSEditLogLock,但是100%请求需要获取全局锁FSNamesystemLock。而EditLog写入性能可以依赖新型硬件IO性能的提高,但全局锁FSNamesystemLock由于一定会请求到,那么在集群规模增加和负载增高后必然成为瓶颈!
    关于腾讯分享的拆锁实践。
    • 首先是确定拆锁的粒度,腾讯和美团一样,都是对到INODE级别进行加锁,但是这里也需要考虑到如果每个hdfs handle同时处理很深路径的请求,假设每个锁100b大小的话,也会占据很大的内容空间
    • 针对上述问题腾讯这边借鉴了 Alluxio 2.0来引入的 LockPool 的概念。也就是有一个锁资源池,每个Inode 不再关联(新增)一个 Lock 了,而是需要 Lock 加锁的时候,就去资源池里申请锁,同时引用计数会增加,用完了 unlock 掉的时候,引用计数会减少。通过这样来减少锁的个数
    • 关于拆锁后最重要的问题都是如何预防死锁和数据错乱
      • 预防死锁的话,基本上现有方案都是采用自上而下的加锁方式,其中需要单独把rename等操作拎出来重点考虑。
      • 而数据错乱这边则查询类的一般全链路加读锁,这类请求一般也占到极大比例。属性修改类的只对最深目录加写锁,而增删类算是最麻烦的则需要考虑读写锁的结合了。
    • 总体上拆锁后关于死锁和数据正确性需要考虑的问题,如下图所示。


      NN拆锁问题关注点

    不拆锁如何优化?(可执行的方案)

    • 如HDFS-10872 添加了NameNode锁住时间对应的Metrics。NameNode的锁队列长度堆积过高的时候,可以查看到NN全局锁对应的锁住时间和对某些锁占用时间过长的情况,然后再进行具体的分析,对很多锁优化对细节很有帮助。

    相关文章

      网友评论

          本文标题:关于Hdfs拆锁的学习和思考

          本文链接:https://www.haomeiwen.com/subject/axpcaltx.html