HDFS BlockInfoContiguous BlockInfo DatanodeStorageInfo 侵入式双链表

BlockInfoContiguous/BlockInfo DatanodeStorageInfo

说明:笔者阅读的hadoop源码为2.7版本,在这个版本中存在BlockInfoContiguous,其他版本为BlockInfo类,但是数据结构是一致的,均为侵入式双链表

前言:HDFS Datanode中,可以配置多个数据存储目录,即配置项dfs.datanode.data.dir,在异构存储中,每一个存储目录支持不同的存储类型(StorageType),如HDD、SSD等。而HDFS NameNode在内存维护着数据块(BlockInfoContiguous)跟Datanode存储目录(DatanodeStorageInfo)的对应关系。在支持异构存储之前,Datanode节点的存储目录只有一种存储类型,维护的只是数据块——>datanode(DatanodeDescriptor)的对应关系。本文中,我们简单介绍一下BlockInfoContiguous跟DatanodeStorageInfo这两个类使用的数据结构,即侵入式双链表。

1. 侵入式双链表

没有追根溯源,据说是linux内核在使用,毕竟不懂C/C++,所以没有仔细的去看,有关java的实现这里有讨论

https://stackoverflow.com/questions/3726681/intrusive-list-implementation-for-java

简单的来说,普通双链表,一般会有两个类的参与,一个是List类,一个是Node类,其中Node维护prev和next双指针,List类维护head和tail指针,同时暴露操作链表的API。

而侵入式双链表,是在Node中维护自身(this)存在于哪些链表中,同时维护着自己在这些链表中的prev和next指针,一般会有一个Object[]来维护这些元数据。这个Object[]是以一个三元组(triplets)的形式进行组织的。

e.g.

存在链表list1、list2,其中各含有4个元素a, a1, a2,a3,组织如下:

list1:a <–> a1 <–> a2 <–> a3

list2:a3 <–> a2 <–> a1 <–> a

Node a = new Node();
Node a1 = new Node();
Node a2 = new Node();
Node a3 = new Node();

List list1 = new List();
List list2 = new List();
//list1
a.tripltes[0] = list1;
a.triplets[1] = null;
a.triplets[2] = a1;
//list2
a.triplets[3] = list2; //存放在哪个链表中
a.triplets[4] = a1; //存放在该链表中的前驱节点prev
a.triplets[5] = null; //存放在该链表中后继节点next

//a1、a2、a3类似

这种数据结构组织形式,个人认为是使用额外的空间,大大提升插入和删除的效率。当然,有一个前提是,一个节点(Node)不能同时存在于太多个链表(List)中,否则要占用太多的内存空间。

2. HDFS中的侵入式双链表

其实,在HDFS中,比较早的就应用了这种数据结构,即BlockInfoContiguous(Node)和DatanodeStorageInfo(List),但是在2.X(具体哪个版本没有考究)实现Cache模块的时候,在源码中才第一次提出了侵入式双链表的概念,对应的类为IntrusiveCollection,有兴趣的可以研究研究,巩固一下。

还是需要一点基础知识的哈。

  1. HDFS默认是3副本策略,即一个数据块以3副本的形式存在。

  2. HDFS的数据块存储在Datanode中,Namenode持久化存储了(写到磁盘上)目录结构(FsImage)和操作记录文件(EditLog),但是每一个数据块存储在哪一个数据节点,这一部分并不是Namenode去记录的,而是Datanode负责管理并在启动后主动向Namenode汇报的。这部分的映射关系就描述成了数据块(BlockInfoContiguous)–>Datanode存储目录(DatanodeStorageInfo)。同时呢,DatanodeStorageInfo中,又想知道自己管理这哪些数据块,这就要用到集合了,具体用什么数据结构呢,频繁的插入、删除操作,当然要选择链表了。

而这里用的就是侵入式双链表,BlockInfoContiguous类作为Node(也可以叫做Element),使用三元组数组Object[] triplets维护着自己是存储在哪些数据节点(DatanodeStroageInfo)中,同时又要记录在每个DatanodeStoragInfo中自己的前驱节点prev和后继节点next。同时,HDFS副本策略(replication factor/the number of replicas),假设为i,那么数组triplets的长度就是3xi。

int len = triplets.length;
len % 3 == 0 --> DatanodeStorageInfo
len % 3 == 1 --> prev BlockInfoContiguous
len % 3 == 2 --> next BlockInfoContiguous

3. 总结 && 参考

简单的过了一下数据结构,这部分的源码相对更好理解一些了

参考:

<Hadoop 2.X HDFS源码剖析>
https://blog.csdn.net/Androidlushangderen
https://tech.meituan.com/2016/08/26/namenode.html
https://issues.apache.org/jira/browse/HDFS-2832

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值