HDFS 学习
HDFS文件系统
具有高容错率,每个block的size为128MB,为的是减少寻址时间。整个hadoop集群中分为了Namenode
和Datanode
,其中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
。而这个standby
的namenode
也将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 | hadoop fs -copyFromLocal input/docs/quangle.txt \ |
如果查找不到datanode的话1
2sudo 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()
DistributedFileSystem
向namenode
调用并创建一个文件在命名空间里,但是并没有实际的blocks和它联系在一起。namenode
会运行多种检查来确保文件并不是已经存在的,并且用户有足够的权限去创建这个文件。如果检查通过了,那么namenode
会为这个文件创建一个记录。如果失败了,则会抛出IOException
。- 成功之后,
DistributedFileSystem
会返回一个FSDataOutputStream
,用于客户端写数据。正如读过程一样,FSDataOutputStream
包着一个DFSOutputStream
。它负责和datanode
和namenode
的通讯。 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会定时删除。