HDFS

HDFS 学习

HDFS文件系统

具有高容错率,每个block的size为128MB,为的是减少寻址时间。整个hadoop集群中分为了NamenodeDatanode,其中Namenode保存着metadata,也就是整个HDFS文件系统的树和块信息。而Datanode则负责具体block的存取,并且周期性地向Namenode报告它所拥有的数据块。

datanode自身因为会把block复制几遍,所以已经有了容错机制了。而namenode则可以将metadata持久化到其他的文件系统中,或者运行一个secondary namenode。这个secondary namenode的主要作用是不断地合并log,避免log文件过大。但是由于这两个namenode之间还是有延迟的,所以数据的丢失是肯定的。在主要的namenode失效的情况下的做法通常是将文件系统中的metadata拷贝到secondary namenode中,让它作为primary namenode

HDFS结合

可以以有多个namenode,分管一部分namespace

HDFS高可用性

namenode失效恢复机制

  • 装载命名空间镜像到内存
  • 重现编辑log
  • 接受足够多的块报告,以便离开安全模式

这个通常会花费超过30mins的时间。因此有计划的宕机更重要。Hadoop 2通过增加高可用性来解决了这个问题。通过增加一个随时待命的namenode。而这个standbynamenode也将secondary namenode的职责也承担下来了。

故障转移

从激活的namenode转移到standby namenode需要failover controller。需要许多的failover controller

fencing用于保证下线的namenode不会造成数据冲突

QJM一次只允许一个namenode往编辑log里写东西。然而,之前的namenode还是会为旧的客户请求提供服务,因此需要设置一个SSH fencing command来杀死这个namenode的进程。更激进的fencing方法用于NFS共享log。因为不可能只让每时刻只有一个namenode写log。这也是为什么QJM是被推荐的。一个方法是取消这个namenode访问共享存储目录的权限,关闭它的网络接口。最后的招数是直接击毙这个节点,也就是关闭电源。而客户端会逐个尝试配置文件中的namenode address

命令行接口

有两个属性需要设置

1
fs.defaultFS=hdfs://localhost/

HDFS守护进程会使用这个东西去查找HDFSnamenode的地址和端口。HDFS clients也会通过这个查找namenode

另一个属性是

1
dfs.replication=1

这样HDFS就不会讲每个块都复制三遍了。当只有单个datanode的时候,HDFS无法复制三遍,所以会不停地警告,这个设置会解决这个问题。

基本操作

1
2
hadoop fs -copyFromLocal input/docs/quangle.txt \
hdfs://localhost/user/tom/quangle.txt

如果查找不到datanode的话

1
2
sudo rm -R /tmp/*
hdfs namenode -format

然后重启

hdfs client读文件过程

  • 客户端先打开一个FileSystem对象,对于HDFS文件系统来说是DistributedFileSystem。它会返回前几个block的地址。同时这些地址,也就是datanode的地址,会根据它们的拓扑情况排序。除此之外,还会返回一个FSDataInputStream,其中包含着一个DFSInputStream
  • 客户端通过read()来读取文件,在DFSInputStream中保存着datanode的地址,DFSInputStream会一块一块地读取文件,但是客户端只会觉得是从一个流里面读取数据。当这一批的block都读取完了,它会向namenode请求下一批block的地址。当结束的时候,它会调用call()
  • 如果DFSInputStream在和datanode通讯的时候遇到了错误,那么它会记录这个datanode是坏掉的,然后会尝试别的datanode

这个过程中namenode只是回复查询块位置的请求。

网络拓扑和Hadoop

通过计算两个节点到它们最近的共同祖先的距离。

同一个节点的距离 < 同一个机架的两个不同节点 < 同一个数据中心,不同机架的两个节点 < 不同数据中心的两个节点

hdfs client 写文件的过程

  • 客户端在DistributedFileSystem上调用create()
  • DistributedFileSystemnamenode调用并创建一个文件在命名空间里,但是并没有实际的blocks和它联系在一起。
  • namenode会运行多种检查来确保文件并不是已经存在的,并且用户有足够的权限去创建这个文件。如果检查通过了,那么namenode会为这个文件创建一个记录。如果失败了,则会抛出IOException
  • 成功之后,DistributedFileSystem会返回一个FSDataOutputStream,用于客户端写数据。正如读过程一样,FSDataOutputStream包着一个DFSOutputStream。它负责和datanodenamenode的通讯。
  • DFSOutputStream会把数据分成好几份,然后放在一个queue中,然后会有若干个datanode在等待,如果是将每个block复制三遍的话,则会想给第一datanode,然后第一个datanode再给第二个datanode,然后第二个datanode再给第三个datanode。
  • DFSOutputStream还会维护一个ack queue,只有当一个packet的所有datanode都表示回复了ack之后,才会从这个queue中移除。

hdfs是如何选择节点去存储一个block的

它优先选一个client在的节点,如果是外部请求,则随机一个。第二个拷贝会换一个rack,第三个会放在和第二个拷贝的相同机架上,但是在不同的节点。后面的拷贝则是在集群中随机选择。

FSDataOutputStream中的hflush强制让缓存中的数据写到datanodes中,并且让其是对外可见的,但是这个只是保证到达了datanode的内存中,如果掉电了,还是会存在数据丢失的情况。hsync()是一个更强的保证,保证数据已经写到文件中了。

关闭一个HDFS中的文件,就隐式地调用了hflush

hdfs的路径问题

在hdfs-site.xml中设置,否则会放在tmp文件夹下,但是如果设置了tmp文件夹的话也就没什么关系了。因为tmp会定时删除。

分享到