HDFS 细粒度锁优化,FusionInsight MRS有妙招
摘要:华为云FusionInsight MRS通过FGL对HDFS NameNode锁机制进行优化,有效提升了NameNode的读写吞吐量,从而能够支持更多数据,更多业务请求访问,从而更好的支撑政企客户高效用数,业务洞见更准,价值兑现更快。
本文分享自华为云社区《FusionInsight MRS HDFS 细粒度锁优化实践》,作者:pippo。
背景
HDFS依赖NameNode作为其元数据服务。NameNode将整个命名空间信息保存在内存中提供服务。读取请求(getBlockLocations、listStatus、getFileInfo)等从内存中获取信息。写请求(mkdir、create、addBlock)更新内存状态,并将日志事务写入到日志服务(QJM)。
HDFS NameNode的性能决定了整个Hadoop集群的可扩展性。命名空间性能的改进对于进一步扩展Hadoop集群至关重要。
Apache HDFS 整体架构如下:
Apache HDFS 交互信息如下:
痛点
HDFS NameNode的写操作的性能受全局命名空间系统锁的限制。每个写操作都会获取锁并保留锁,直到该操作执行完成。这样可以防止写入操作的并发执行,即使它们是完全独立的,例如命名空间中的对象不相交部分。
什么是Fine Grained Locking(FGL)
FGL【细粒度锁】的主要目的是通过在独立命名空间分区上用多个并发锁替换全局锁,允许写入操作的并发。
当前状态
HDFS设计思路为一次写,多次读。读操作使用共享锁,写操作使用独占锁。由于HDFS NameNode元数据被设计为单个内存空间中的命名空间树,因此树的任何级别的写操作都会阻塞其它写操作,直到当前写操作完成。虽然写是一次,但是当涉及大量并发读/写操作时,这就会影响整体性能。
在HDFS NameNode中,内存中的元数据有三种不同的数据结构:
- INodeMap: inodeid -> INode
- BlocksMap: blockid -> Blocks
- DataNodeMap: datanodeId -> DataNodeInfo
INodeMap结构中包含inodeid到INode的映射,在整个Namespace目录树种存在两种不同类型的INode数据结构:INodeDirectory和INodeFile。其中INodeDirectory标识的是目录树中的目录,INodeFile标识的是目录树中的文件。
BlocksMap结构中包含blockid到BlockInfo的映射。每一个INodeFile都会包含数量不同的Block,具体数量由文件大小以及每个Block大小来决定,这些Block按照所在文件的先后顺序组成BlockInfo数组,BlockInfo维护的是Block的元数据;通过blockid可以快速定位Block。
DataNodeMap结果包含datanodeid到DataNodeInfo的映射。当集群启动过程中,通过机架感知逐步建立起整个集群的机架拓扑结构,一般在NameNode的生命周期内不会发生大变化。
通过INodeMap和BlocksMap共同标识存储在HDFS中的每个文件及其块的信息。随着文件数量的增加,此数据结构大小也会随之增加,并对单个全局锁的性能产生很大影响。下面我们采用简单的文件目录树结构来演示现有的单一全局锁在文件系统的缺点。
HDFS NameNode 内存目录树结构
如上图所示,/D11/D21/D31/F2 和 /D12/D24/D38/F16是不相交的文件,即有不同的父节点和祖父节点。可以看到F2和F16是两个独立的文件,对其中一个文件的任何操作都不应该影响另一个文件。
设计
如前所述,HDFS NameNode将文件信息和元数据结构在内存中保存为一个目录树结构。当修改任意两个独立的文件时,第二次操作需要等到第一次操作完成并释放锁。释放锁以后,只有第二个操作获取锁后才能继续修改文件系统。类似的,后续操作也会阻塞,直到第二次操作释放锁。
在下面的例子中,我们考虑2个文件并发写入(创建、删除、追加。。。)操作。F2和F16是文件系统下的2个独立文件(具有不同的父节点和祖父节点)。在将内容追加到F2时,F16也可以同时进行修改。但是由于整个目录树全局对象锁,对F16的操作必须等对F2的操作完成后才能执行。
代替全局锁,可以将锁分布在一组名为“分区”的文件中,每个分区都可以有自己的锁。现在F2属于分区-1,F16属于分区-2。F2文件操作可以通过获取分区-1的锁来进行修改,F16文件操作可以通过获取分区-2的锁来进行修改。
和以前一样,需要先获取全局锁,然后搜索每个文件属于哪个分区。找到分区后,获取分区锁并释放全局锁。因此全局锁并不会完全被删除。相反,通过减少全局锁时间跨度,一旦释放全局锁,则其它写操作可以获取全局锁并继续获取分区锁来进行文件操作。
分区的数量如何决定?如果有效的定义分区从而获得更高的吞吐量?
默认情况下,分区大小为65K,溢出系数为1.8。一旦分区达到溢出条件,将会创建新分区并加入到分区列表中。理想情况下,可以拥有等于NameNode可用CPU核数的分区数,过多的分区数量将会使得CPU过载,而过少的分区数量无法充分利用CPU。
实现
引入新的数据结构-PartitionedGSet,它保存命名空间创建的所有分区信息。PartitionEntry是一个分区的对象结构。LatchLock是新引入的锁,用于控制两级锁--顶层锁和子锁。
PartitionedGSet
PartitionedGSet是一个两级层次结构。第一层RangeMap定义了INode的范围,并将它们映射到相应的分区中。分区构成了层次结构的第二级,每个分区存储属于指定范围的INode信息。为了根据键值查找INode,需要首先在RangeMap中找到对应键值的范围,然后在对应的RangeSet,使用哈希值获取到对应的INode。
HDFS NameNode 两级层次结构
RangeGSet的容量有一定的阈值。当达到阈值后,将创建新的RangeGSet。空的或者未充分利用的RangeGSet由后台RangeMonitor守护程序来进行垃圾回收。
HDFS NameNode启动时,根据镜像中的INode数量计算合理的初始分区数。同时还需要考虑CPU核数,因为将分区数量提高到远超CPU核数并不会增加系统的并行性。
- 动态分区:分区的大小有限,可以像平衡树一样可以进行分裂和合并。
- 单个分区:只有一个分区,且只有一个与之相对应的锁,并且应和全局锁类似。这适用于小型集群或写入负载比较轻的集群。
- 静态分区:有一个固定的RangeMap,不添加或者合并现有分区。这适用于分区均匀增长的文件系统。而且这将消除锁定RangeMap的要求,允许并行使用锁。
Latch Lock
RangeMap与RangeGSet分别有单独的锁。Latch Lock是一种锁模式,其中首先获取RangeMap的锁,以查找与给定INode键对应的范围,然后获取与分区对应的RangeGSet的锁,同时释放RangeMap锁。这样针对任何其它范围的下一个操作都可以开始并发执行。
在RangeMap上持有锁类似于全局锁。目录删除、重命名、递归创建目录等几个操作可能需要锁定多个RangeGSet。这要确保当前HDFS语义所要求的操作的原子性。例如,如果重命名将文件从一个目录移动到另一个目录,则必须锁定包含文件、源和目标目录的RangeMap,以便使重命名成为原子。此锁定模式的一个理想优化是允许某些操作的Latch Lock与其他操作的全局锁结合使用。
INode Keys
HDFS中的每个目录和文件都有一个唯一的INode,即使文件被重命名或者移动到其它位置,该INode会保持不变。INode键是以文件INode本身结尾,前面包含父INode的固定长度序列。
Key Definition: key(f) = <ppId, pId, selfId>
selfId是文件的INodeId,pId是父目录的INodeId,ppId是父目录的父目录的INodeId。INode键的这种表达不仅保证了同级,同时也保证了表亲(相同祖父节点)在大多数情况下被分区到相同的范围中。这些键基于INodeId而非文件名,允许简单的文件和目录进行重命名,称为就地重命名,而无需重新进行分区。
效果
经过测试验证使用和不使用FGL功能性能,在主要写入操作情况下,吞吐量平均提高了25%左右。
详细性能对比
使用Hadoop NN Benchmarking工具(NNThroughputBenchmark)来验证NameNode的性能。每个写入API验证并观察到平均25%的性能提升。有很少一部分轻微或者没有提升的API,分析并发现这些API均是轻量级API,因此没有太大的提升。
NNThroughputBenchmark是用于NameNode性能基准测试工具。该工具提供了非常基本的API调用,比如创建文件,创建目录、删除。在这个基础上进行了增强,从而能够支持所有写入API,并能够捕获使用和不使用FGL的版本的性能数据。
用于测试的数据集:线程数 1000、文件数 1000000、每个目录文件数 40。
写入调用频率高的API
其它内部写API
常用读取API:
通过完整的FGL实现,读取API也有很好的性能提升。
运行基准测试工具的命令:
./hadoop org.apache.hadoop.hdfs.server.namenode.NNThroughputBenchmark -fs file:/// -op create -threads 200 -files 1000000 -filesPerDir 40 –close
./hadoop org.apache.hadoop.hdfs.server.namenode.NNThroughputBenchmark -fs hdfs:x.x.x.x:dddd/hacluster -op create -threads 200 -files 1000000 -filesPerDir 40 -close
参考
与FGL相关的社区讨论
Hadoop Meetup Jan 2019 — HDFS Scalability and Consistent Reads from Standby Node, which covers Three-Stage Scalability Plan. Slides 21–25
社区中跟踪与NameNode可扩展性相关的其它Jira
HDFS-5453. Support fine grain locking in FSNamesystem
HDFS-5477. Block manager as a service
HDFS-8286. Scaling out the namespace using KV store
HDFS-14703. Namenode Fine Grained Locking (design inspired us to implement it fully)
总结
华为云FusionInsight MRS云原生数据湖为政企客户提供湖仓一体、云原生的数据湖解决方案,构建一个架构可持续演进的离线、实时、逻辑三种数据湖,支撑政企客户全量数据的实时分析、离线分析、交互查询、实时检索、多模分析、数据仓库、数据接入和治理等大数据应用场景。
华为云FusionInsight MRS通过FGL对HDFS NameNode锁机制进行优化,有效提升了NameNode的读写吞吐量,从而能够支持更多数据,更多业务请求访问,从而更好的支撑政企客户高效用数,业务洞见更准,价值兑现更快。
HDFS 细粒度锁优化,FusionInsight MRS有妙招的更多相关文章
- Java 中常见的细粒度锁实现
上篇文章大致说了下 ReentrantLock 类的使用,对 ReentrantLock 类有了初步的认识之后让我们一起来看下基于 ReentrantLock 的几种细粒度锁实现. 这里我们还是接着用 ...
- FusionInsight MRS:你的大数据“管家”
摘要:4月24日-26日,HDC.Cloud2021在深圳大学城成功举办,华为云FusionInsight MRS云原生数据湖带来最懂行的大数据解决方案,为政企客户提供湖仓一体.云原生的大数据解决方案 ...
- 解密华为云FusionInsight MRS新特性:一架构三湖
摘要:华为云安全网关产品总监郭冕在"华为云TechWave云原生2.0专题日"上发表<华为云FusionInsight MRS,一个架构实现三种数据湖>的主题演讲,分享 ...
- Java细粒度锁实现的3种方式
最近在工作上碰见了一些高并发的场景需要加锁来保证业务逻辑的正确性,并且要求加锁后性能不能受到太大的影响.初步的想法是通过数据的时间戳,id等关键字来加锁,从而保证不同类型数据处理的并发性.而java自 ...
- mysql 锁优化
一.myisam存储引擎锁优化 1.合理理由读写优先级MyISAM 的表锁,写互相阻塞的表锁,默认系统是写优先,可改为读有先:low_priority_updates=1如果我们的系统是一个以读为主, ...
- JVM-并发-线程安全与锁优化
线程安全与锁优化 1.线程安全 (1)当多个线程访问一个对象时,如果不考虑这些线程在执行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获 ...
- 深入理解java虚拟机(7)---线程安全 & 锁优化
关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...
- Java的锁优化
高效并发是从JDK 1.5到JDK 1.6的一个重要改进,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋(Adaptive Spinning).锁消除(Lo ...
- JVM中锁优化简介
本文将简单介绍HotSpot虚拟机中用到的锁优化技术. 自旋锁 互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性能带来了很大的压力.而在很多 ...
随机推荐
- 前端每日实战:96# 视频演示如何用纯 CSS 和 D3 创作一艘遨游太空的宇宙飞船
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/oMqNmv 可交互视频 此视频是可 ...
- ps基础总结
1.复制图层:首先选中移动工具(V),鼠标右键选中需要复制的图层(快捷方式:上面勾选自动选择),接着一只手按住Alt键,另一只手点击鼠标左键(不松开),往左往右移动即可.若是对多个图层起作用,就可将需 ...
- 前端眼里的docker
docker是什么 可以简单的认为docker容器是一个虚拟机,封装就是把这个虚拟机打包,打包后能在任何系统跑,docker装上即用.也可以形象的比喻成一个集装箱,把所有货物都打包好放到箱子里,不需要 ...
- GoF设计模式-23大设计模式(表格)-程序员必备+必背
在GoF经典著作<设计模式:可复用面向对象软件的基础>中一共描述了23种设计模式. <Design Patterns:Elements of Reusable Object-Orie ...
- Struts的Logic标签的用途
Struts的Logic标签可以根据特定的逻辑条件来判断网页的内容,或者循环遍历集合元素,它和HTML,Bean标签是Struts应用中最常用的三个标签. 它的功能主要是比较运算,进行字符串的匹配,判 ...
- github账号&文章选题
----------------------------------------------------------- https://github.com/yanpanjiao github ...
- vue报错解决方案
Vue build faild 解决办法: https://blog.csdn.net/u011169370/article/details/83346176 ? jbcmVideo git:(oah ...
- ZXing Blazor 扫码组件 , ssr/wasm通用
项目介绍 本项目是利用 ZXing 进行封装的 Blazor 组件库 直接调用手机或者桌面电脑摄像头进行扫码 项目截图 项目地址 https://github.com/den ...
- Spring Framework 学习笔记——核心技术之Spring IOC
Spring Framework 官网文档学习笔记--核心技术之Spring IOC 官方文档 spring-framework-5.3.9 1. Spring Framework 核心技术 1.1 ...
- JVM虚拟机类加载机制(一)
类从被加载到虚拟机内存中开始,到卸载出内存截止,整个生命周期包括:加载.验证.准备.解析,初始化.使用.卸载七个阶段.其中验证.准备.解析三个部分统称为连接. 类初始化情况: 遇到new.getsta ...