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会定时删除。