我有分寸

DataNode的磁盘管理以及HDFS-1362

gnawux datanodehadoopjiravolume

按:英文版在这里

前不久发到JIRA的HDFS-1362是一个关于DataNode的磁盘管理的小Feature,简单的说,就是根据配置文件,重新刷新服务,让新加入的硬盘提供服务,这一切不需要重启计算机或重启DN服务。

动机

和其他的PC集群一样,研究院大云团队的Hadoop集群也常常遇到磁盘故障,更换磁盘会导致节点暂时退服,进而造成不必要的块迁移,因此在线更换硬盘是一个有用的功能。当前的DataNode,实际是FSDataset已经可以在线去掉无法提供服务的磁盘了,不过不能在线激活新的硬盘。要知道,大部分现代的服务器和SATA硬盘都是支持热插拔的,所以,为啥不动手提供这个功能呢?

一开始我们提供了一个简单的接口,可以通过命令行列出、加入、删除卷。不过在11月和Tom White和Todd Lipcon讨论之后,我们决定转而利用HADOOP-7001提供的在线更新配置的机制,提供一个单一的刷新接口,这样也不用担心配置文件和运行的服务不一致这个问题了。

DataNode的卷管理

DataNode实际使用了双重的卷管理。在启动时,DataStorage加载配置的目录,检查这些目录是否存在、是否可用、结构是否正确、版本是否有问题等,并针对目录的情况、依据启动的参数进行升级、回滚、格式化等必要操作。这些卷被存储为一个列表,并提供一个Iterator<StorageDirectory>,用于外部访问。

装载这些目录之后,DN会构造FSDataset来管理卷和卷中的块。FSDataset之中的FSVolumeSet有一个卷的数组,存放着可用的卷,FSDataset中还有一个map,以BlockID为索引,存放着所有的块信息。这个map并没有按照卷的索引,所以,如果要删掉一个卷,需要遍历整个map,才能删掉所有的块,事实上现在的那个删除卷的操作也就是这么干的。

注意上面说的,块加载的时间依赖于卷里面有多少个块,如果卷很满的话,就要花很长时间。

基本思路

HDFS-1362里,大概分四步来进行卷刷新工作:

• 首先读取配置文件,加入到一个新目录的List里面;

• 遍历DataStorage中的StorageDirectory:

• 如果这个sd没在FSDataset的FSVolumeSet的数组中的话,说明它已经因故障被删掉了,所以,从DataStorage里删掉它;

• 如果这个sd包含在上面的新目录列表里的话,从新目录列表里删掉它,因为它已经在提供服务了,不用添加;

• 相反,如果这个sd不包含在新目录列表里的话,也就是说一个在服务中的目录居然没在新的配置列表里,是要删除一个卷么?目前的版本,我们只是留一条warning,不会让卷退服。

• 把剩下的真的新目录添加到DataStorage里面去.

• 把这些卷添加到FSDataset里面去.

加载卷

加载卷操作是基于 DataStorage.revoverTransitionRead来做的,我只是基于它修改了一个revoverTransitionAdditionalRead来加载卷,两者有这么几个区别:

• 不需要初始化 StorageID 和 StorageDirectory 列表;

• 不对所有的SD进行 doTransition ,只针对新加入的;

• 不使用writeAll, 只对新加入的SD执行write;

• 返回一个新加入SD的Collection, 用于FSDataset的重新加载

这里没有用一个函数完成这两个功能的原因其实就是关于writeAll和transition操作,我担心这两者的操作方式差别可能比较大。

让FSDataset加载新卷上的块

这个操作不外乎就是给FSVolumeSet的数组添加卷、载入块的map。不过这里将来可能可以有块加载的优化。

异步服务

FSDataset 使用了 FSDatasetAsyncDiskService 来进行某些在每个卷上执行的异步任务,这个类是基于HashMap管理每个卷上的操作的,所以,只要把构造函数里的添加卷操作剥离出来成为一个单独的函数,让我们的刷新操作也能使用这个函数就可以了。

下一步工作

目前我们对于去掉卷的需求就是给了一个WARNING,将来可以继续讨论,是否可以通过这个接口让卷退服。

gnawux
me!#$!@#$@#$wangxu!@#$%^&*()_me