一、HDFS节点角色:
(1)namenode:1、用来存储HDFS的元数据信息,这里的元数据信息指的是文件系统的命名空间。启动时,将这些信息加载到namenode内存。
2、元数据信息也会在磁盘上保存成fsimage和edit log 文件。
3、namenode的内存中也会保存文件的具体信息,如:一个文件包含哪些数据块,分布在哪些节点上。这些信息在系统启动时从datenode上进行收集。
(2)secondary namenode:用于周期性的合并namenode中的fsimage文件和edit log文件。文件合并之后,会返回给namenode,同时secondary 里也会保存一份,用于namenode故障恢复。
(3)datenode:存储文件数据块数据。定时向namenode汇报存储的数据块信息。
补充:
数据块:HDFS将文件分块存储,文件块默认大小为128M,可以设置。mapreduce的maptask数量和文件块的数量对应。其中,文件块不宜太小,增加寻址时间;
同时文件也不宜过大,过大导致maptask太少,少于集群节点数量,没有充分利用集群资源,导致作业运行速度慢。
文件分块的优势:a、存储文件大小可以大于任何一个集群中磁盘容量;
b、不使用整个文件进行存储,简化存储子系统设计,这点比较虚
c、利于数据备份,有利于集群高可用。
二、HDFS读写机制:
1、HDFS的读机制:客户端读hdfs文件
1、初始化 DistributedFileSystem 对象 ,clinet客户端调用 DistributedFileSystem中的 open() 方法打开文件。
2、DistributedFileSystem对象调用远程RPC服务,获取namenode上的文件的数据块信息,每个数据块 namenode 返回数据块的节点地址。
3、DistributedFileSystem 创建一个 FSDataIputStream 给 client 客户端,client 客户端调用 FSDataIputStream 中的 read() 方法开始读取数据。
4、FSDataIputStream 连接保存此文件的第一个数据块的 DataNode,读取数据。
5、数据读取完毕,关闭流连接,连接文件的下一个数据块的 DataNode。
6、client 客户端将文件读取完毕后,调用 FSDataInputStream 的 close() 方法关闭文件输入流连接。
注意:若在读数据的过程中,客户端和DataNode的通信出现错误,则会尝试连接下一个 包含次文件块的 DataNode。同时记录失败的 DataNode,此后不再被连接。
2、HDFS写机制:客户端向hdfs中写数据
1、client客户端调用DistributedFileSystem对象 分布式文件系统对象 的create()方法,创建一个文件输出流FSDataOutputStream对象。
2、DistributedFileSystem对象和Hadoop中的namenode进行一次远程RPC调用,在namenode中创建一个文件条目Entry,该条目没有任何的block。
3、client通过 FSDataOutputStream 文件输出流向datanode中写数据,数据首先被写入 FSDataOutputStream 内部的 buffer 中,然后被分成一个个的 packet 数据包。
4、以 packet 数据包为最小单位,向集群中的一个 DataNode 发送数据,在这组 DataNode 组成的Pipeline线管上依次传输 packet 数据包。
5、在Pipeline线管的反向上依次发送ack,最终由第一个DataNode发送ack给client客户端。
6、文件传输结束,客户端调用 FSDataOutputStream 的 close 方法关闭流。
7、客户端调用 DistributedFileSystem 的 complete() 方法,通知 namenode 文件写入成功。
3、客户端从hdfs读写数据出错:
(1)Hdfs读数据出错:
若在读数据的过程中,客户端和DataNode的通信出现错误,则会尝试连接下一个 包含次文件块的DataNode。同时记录失败的DataNode,此后不再被连接。
(2)Hdfs在写某一个副本数据的时候出错:
1)首先会关闭dataNode联通的线管。
2)将已发送至线管内,还没有收到确认消息的数据包重新写回到数据队列中,保证数据不丢失。
3)将当前正常工作的dataNode赋予新的版本号,这样保证即使故障dataNode节点恢复了,由于版本号不对,故障dataNode也将会被剔除。这个新的版本号是利用nameNode的租约信息获取。
4)在当前正常的dataNode中选择一个主dataNode,并与其他的dataNode进行通信,来获取每个dataNode的当前数据块的大小,然后选择出一个最小的值,将当前的所有dataNode都同步到该大小。再重新建立线管。
5)在线管中删除故障节点,将数据写入线管中正常的dataNode,即新管道。
6)当文件关闭后,若nameNode发现副本数不足,会在其他的dataNode上创建新的副本。
三、HDFS的HA高可用机制:
1、Hdfs的HA高可用:
保证Hdfs高可用,其实就是保证namenode的高可用,保证namenode的高可用的机制有两个,edit log共享机制+ZKFC。ZKFC就是ZookeeperFailOverController,即zookeeper故障转移控制器。
2、nameNode的高可用机制:
(1)nameNode想要实现高可用,意味着集群中要存在多个nameNode,在nameNode出现故障的时候,能够进行快速切换。集群中平时只有一个nameNode在工作,这个nameNode就是active的,而其他nameNode是standby的。
(2)为了保证nameNode出现故障的时候,nameNode的切换速度。active nameNode将信息写入共享编辑日志文件,standby nameNode则读取共享文件,从而保持与active nameNode的同步。
(3)此外,集群中的dataNode要向所有的nameNode发送数据块处理报告。
(4)故障切换这个动作就需要ZKFC来保证,每个nameNode中都运行着一个ZKFC故障转移控制器,用于监视nameNode进程。而这个ZKFC是基于Zookeeper实现的,在启动的时候,会创建HealthMonitor和ActiveStandbyElector这两个组件,创建的同时,ZKFC也会向这两个组件中注册相应的回调方法。
(5)HealthMonitor初始化完成后会启动内部线程来定时调用nameNode的HAServiceProtocol Rpc接口,对nameNode进行健康监测。
(6)HealthMonitor如果检查到nameNode的健康状态发生了变化,就会回调ZKFC注册的相应方法进行处理。
(7)如果ZKFC经过判断后,认为需要进行主备切换话,会首先使用ActiveStandbyElector来进行自动的主备选举。
(8)ActiveStandbyElector完成了自动的主备选举后,会回调ZKFC的相应方法,通知相应的nameNode成为主nameNode或者备nameNode。
(9)ZKFC调用相应nameNode的HAServiceProtocol Rpc接口方法,将相应的nameNode设置成active或者standby。
3、Fencing实现:
脑裂就是nameNode假死,Fencing就是防御脑裂。Hadoop公共库对外提供了两种Fencing实现,分别是sshfence和shellfence(缺省实现)。其中sshfence就是通过ssh登陆到目标nameNode节点上,用kill命令将其进程杀死;shellfence就是执行自定义的shell脚本。
4、如何判断是否发生了脑裂:
判断持久化节点是否存在,持久化节点存在就是脑裂。