分布式存储—HDFS详解
### 分布式存储—HDFS详解
HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。它所具有的高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集(Large Data Set)的应用处理带来了很多便利
—————————————————————————————————————————
设计思想分而治之(安全性):将大文件、大批量文件,分布式的存放在大量服务器上
存储方式存放数据的单位是块。2.0以后,块的默认大小:128M
主从架构
1.client 客户端
- 文件切分,文件上传HDFS的时候,client将文件切分成一个一个的block
- 与NameNode交互,获取文件的位置信息
- 与DataNode交互,读取或写入数据
- Client提供一些命令来管理HDFS,比如启动或关闭HDFS
- Client可以通过一些命令来访问HDFS
2.NameNode就是master,是一个主管、管理者。管理HDFS的名词空间。主节点仅存放元数据信息(元数据:管理数据的数据,数据结构的描述。文件大小、位置、块索引)。配置副本策略,处理客户端读写请求,分配client去访问哪个从节点
3.DataNode就是slave,从节点存放真实文件(实际文件)即实际的数据块,执行数据块的读写操作。namenode下达命令,datanode执行实际的操作。client客户端发起读取数据的请求,namenode接到请求后会通过元数据信息得到数据的位置,最后由datanode将数据最后输出给client客户端
架构内容1.数据块:默认128M,datanode通过数据块存储。存放在hadoopdata目录下2.心跳机制:主从节点间通过心跳机制确定互相之间的关系每3秒发送一次3.元数据管理4.负载均衡:存储数据时,由namenode进行分配存在位置5.副本存放策略:每个块都有两个副本6.机架感知:datanode机架感知互相联系
优点
1.高容错性:数据自动保存多个副本(默认有三个)当某一个副本丢失后,它可以自动恢复,这是HDFS的内部机制
2.适合处理超大文件可以批量处理,是通过移动计算而不是移动数据处理数据GB、TB设置PB级数据百万规模以上的文件数量
缺点
1.低延迟数据访问2.小文件存取3.并发写入、文件随机修改
相关特性
- 高容错、可扩展性及可配置性强
- 跨平台
- Shell命令接口
- 机架感知功能
- 负载均衡
- web界面
设计目标 - 可以检测和快速回复硬件故障,故障的检测和快速自动恢复是HDFS的一个核心目标
- 流式数据访问
- 大规模数据集
- 移动计算代价比移动数据代价低
- 可移植性
————————————————————————————————————————————
核心设计
1.心跳机制2.安全模式3.副本存放策略4.负载均衡
——————————————————-数据块
HDFS上最基本的存储单位,默认大小128M,小于一个块大小的文件不会占据整个块的空间,块非常适合用于数据备份进而提供数据容错能力和可用性。
数据复制
HDFS为了做到可靠性reliability创建了多分数据块data blocks的复制replicas,并将它们放置在服务器群的计算节点compute nodes中,MapResource就可以在它们所在的节点上处理这些数据了HDFS将每个文件存储成块序列每个文件的block大小和复制因子replication都是可配置的
————————————————————————
心跳机制
1.master中有NameNode和ResourceManager ,slave中有DataNode和NodeManager
- Master启动时会启动一个IPC Server服务,等待slave的连接;
- Slave启动时,会自动连接Master的IPC Server 服务,并且每隔3秒链接一次Master,这个间隔时间是可以调整的,参数为 dfs.heartbeat.interval,这个每隔一段时间去链接一次的机制,我们形象的成为心跳机制。
- Slave 通过心跳汇报自己的信息给Master ,Master也通过心跳给Slave下达命令
2.NameNode 通过心跳得知DataNode的状态,ResourceManager通过心跳得知NodeManager的状态; 如果Master长时间没有收到Slave的心跳。就认为该Slave挂掉了。
3.死亡时间计算;NameNode 感知 DataNode掉线死亡的时长计算:HDFS 默认的超时时间为10分钟+30秒,这里暂且定义超时时间为timeout计算公式为:
timeout = 2 heartbeat.recheck.interval + 10 dfs.heartbeat.interval - 默认的 heartbeat.recheck.interval 大小为 5 分钟,dfs.heartbeat.interval 默认的大小为 3 秒。需 要 注 意 的 是 hdfs-site.xml 配 置 文 件 中 的 heartbeat.recheck.interval 的 单位 为 毫 秒,dfs.heartbeat.interval 的单位为秒。
- 如果 heartbeat.recheck.interval 设置为 5000(毫秒), dfs.heartbeat.interval设置为 3(秒,默认),则总的超时时间为 40 秒。
heartbeat.recheck.interval 5000 dfs.heartbeat.interval 3
安全模式
集群启动后,可以查看目录,但是上传文件时报错,打开web页面可看到namenode正处于safemode状态。1.safemode 是 NameNode 的一种状态(active/standby/safemode 安全模式)
2.NameNode 进入安全模式的原理:
NameNode 发现集群中的 block 丢失率达到一定比例时(0.1%), NameNode 就会进入安全模式,在安全模式下,不允许客户端进行任何修改文件的操作,包括上传文件、删除文件、重命名等操作,只能查看元数据信息(比如 ls)。这个丢失率是可以手动配置的,默认是在配置文件hdfs-default.xml 中定义了最小的副本率为dfs.safemode.threshold.pct=0.999f 。
3.进入安全模式的原因:块的丢失;增加新节点时;刚启动时文件还没有加载完成
4.能做的:等待
5.如何退出安全模式?
- 找到问题所在进行修复
比如修复宕机的datanode
- 手动强行退出安全模式
(没有解决真正的问题)<br />hdfs dfsadmin -safemode leave
在 HDFS 集群正常冷启动时, NameNode 也会在 safemode 状态下维持相当长的一段时间,此时你不需要去理会,等待它自动退出安全模式即可 。在刚运行命令start-dfs.sh时,50070页面显示的信息:3.安全模式常用的操作命令hdfs dfsadmin -safemode leave //强制 NameNode 退出安全模式hdfs dfsadmin -safemode enter //进入安全模式hdfs dfsadmin -safemode get //查看安全模式状态hdfs dfsadmin -safemode wait //等待,一直到安全模式结束
副本存放策略
- 作用:数据分块存储和副本的存放,是保证可靠性和高性能的关键
- 存放说明:在大多数情况下,HDFS默认的副本系数是3
- 存放策略:
将每个文件的数据进行分块存储,每一个数据块又保存有多个副本,这些数据块副本分布在不同的机器节点Hadoop默认对3个副本的存放策略
1)第一个block副本放在和client所在的node里(如果client不在集群范围内,则这第一个node是随机选取的,系统会尝试不选择哪些太满或者太忙的node)2)第二个副本放置在第一个节点相同的机架中的不同node中(随机选择)3)第三个副本和第一个在不同机架中,随机放在不同的node中4)更多副本随机节点存放
(1.客户端的node里 2.和第一个节点相同机架不同的随机node中 3.和第一个节点不同机架的随机node中)
- 修改副本数(将副本数修改为1)
第一种方式修改集群文件 hdfs-site.xml
//修改项开始 //修改项结束dfs.replication 1
第二种方式命令设置hadoop fs -setrep -R 1 /
负载均衡
1.数据不平衡原因机器与机器之间磁盘利用率不平衡,HDFS集群非常容易出现情况情况一;在DataNode 节点出现故障情况二;在现有的集群上增添新的DataNode 的时候
2.HDFS数据自动平衡方法影响Balancer的几个参数:
- threshold
默认设置:10,参数取值范围:0-100 参数含义:判断集群是否平衡的阈值。理论上,该参数设置的越小,集群就越平衡。
- dfs.balance.bandwidthPerSec
默认设置:1048576(1M/s) 参数含义;Balancer运行时允许占用的带宽<br />命令:<br />启动数据均衡,默认阈值10%sbin/start-balancer.sh<br />启动数据均衡,阈值5%sbin/start-balancer.sh –threshold 5<br /> 停止数据均衡sbin/stop-balancer.sh <br />自动进行均衡非常慢,一天能够移动的数据量在10G-10T的级别,很难满足超大集群的需求。原因:HDFS集群默认不允许blance操作占用很大的网络带宽,这个带宽是可以调整的。<br />调整带宽:<br />(1)命令hdfs dfsadmin -setBalanacerBandwidth 10485760<br />该数值的单位是字节,上面的配置是10 M/秒,默认是1M/s<br />(2)在hdfs-site.xml中设置:<property> <name>dfs.balance.bandwidthPerSec</name><value>10485760</value></property>
————————————————————————————————————————————————————— HDFS工作机制
—————————————-
1.HDFS写数据
1.客户端根据文件的大小,为它分配需要的block数,然后向NN发出写的请求,看看文件是否存在,如果不存在就创建-客户端通过调用 DistributedFileSystem 的create方法,创建一个新的文件。-DistributedFileSystem 通过 RPC(远程过程调用)调用 NameNode,去创建一个没有blocks关联的新文件。创建前,NameNode 会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode 就会记录下新文件,否则就会抛出IO异常
2.NN为文件分配每个块写的位置,然后向client返回文件list,即元数据信息给client-第一步结束后会返回 FSDataOutputStream 的对象,和读文件的时候相似,FSDataOutputStream 被封装成 DFSOutputStream,DFSOutputStream 可以协调 NameNode和 DataNode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列 data queue。
3.client根据文件list在相应的DN上写,每写完一个DN都向client返回一个ack信息。DFSOutputStream 还有一个队列叫 ack queue,也是由 packet 组成,等待DataNode的收到响应,当pipeline中的所有DataNode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。-如果有DN坏了,NN会重新分配,client再重新写
4.客户端写完最后一块后,client关闭数据流-客户端完成写数据后,调用close方法关闭写入流。-DataStreamer 把剩余的包都刷到 pipeline 里,然后等待 ack 信息,收到最后一个 ack 后,通知 DataNode 把文件标示为已完成。
5.当第一块block完成时,它所在的那个节点的后台会启动一个进程进行复制,分别把副本写到其它DN上(管道复制)-DataStreamer 会去处理接受 data queue,它先问询 NameNode 这个新的 block 最适合存储的在哪几个DataNode里,比如重复数是3,那么就找到3个最适合的 DataNode,把它们排成一个 pipeline。DataStreamer 把 packet 按队列输出到管道的第一个 DataNode 中,第一个 DataNode又把 packet 输出到第二个 DataNode 中,以此类推。比如要写一个文件a.txt,300M,那么它会占用3个块,默认保存3个副本
- 步骤
1)Client向NameNode发起RPC请求2) NameNode检查创建的文件是否存在3) 数据队列(data queue)管理packet并向NN申请blocks,4) 以pipeline将packet写入所有的replicas中。以流的方式写入第一个DN,再传递给下一个DN,直到最后一个DN5) 最后一个DN成功存储之后会返回一个ack packet,成功收到DN返回的 ack packet 后会移除packet;某个DN出现了故障,pipeline会被关闭,出现故障的DN会移除,剩余的block会继续传输,同时NN会分配一个新的DN,保持设定的数量。6)完成写入后,关闭数据流7)告知NN,写数据完成
步骤简述:(客户端根据文件大小,分配需要的块数,然后向NN发送写请求,NN为文件分配写的地址,并返回文件列表信息,客户端根据文件列表信息在相应的DN上写,每写完一个DN都会向客户端返回一个ack信息,当第一个块写完后,所在节点会启动一个进程进行复制,分别把副本写到其他管道上,客户端写完最后一个块,关闭数据流。告知NN,写数据完成)
2.HDFS读数据
1.客户端向NN发出请求,与NN发生交互调用FileSystem对象的open方法,其实获取的是一个DistributedFileSystem的实例
2.NN把文件的列表信息发送给client,列表信息即文件的位置索引DistributedFileSystem通过RPC(远程过程调用)获得文件的第一批block的locations,同一block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面
3.client根据列表信息去DN上读取block块信息(客户端会找离它比较近的去读,就近原则)前两步会返回一个FSDataInputStream对象,该对象会被封装成 DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream就会找出离客户端最近的datanode并连接datanode数据从datanode源源不断的流向客户端
4.一直读,直到所有块读完如果第一个block块的数据读完了,就会关闭指向第一个block块的datanode连接,接着读取下一个block块如果只有第一行有信息,也会把整个块读完
5.关闭读操作如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的block块都读完,这时就会关闭掉所有的流
比如要读一个文件a.txt,300M,那么它会占用3个块,默认保存3个副本,所以存在三个DN上
- 步骤
1)Client向NameNode发起RPC请求2)NN返回有block拷贝的DN地址3)Client 会选取DN读取block(就近原则)4)读取完当前block的数据后,关闭当前的DN链接,寻找下一个最佳的DN5)当读完列表后,且没有结束,会继续向NN获取下一批block列表6)读取完一个block都会进行checksum验证,如都没有错误,则关闭资源
步骤简述:(客户端向NN发送读请求,与NN发生交互,NN把文件的列表信息发送给客户端,客户端根据列表信息去DN上读取block块信息[就近原则],并进行验证,一直读,直到第一批所有的块读完,DFSInputStream就会去namenode拿下一批block的location,然后继续读,如果所有的block块都读完,这时就会关闭所有的流 ,即关闭读操作)
——————————————————————————————————————————-
NameNode工作机制
——————————————
1.NameDode对数据的管理
- 内存元数据metadata
1)从形式上讲,元数据可分为内存元数据和元数据文件两种。其中NameNode在内存中维护整个文件系统的元数据镜像,用于HDFS的管理;元数据文件则用于持久化存储。
2)从类型上讲,元数据有三类重要信息:-第一类是文件和目录自身的属性信息,例如文件名、目录名、父目录信息、文件大小、创建时间、修改时间等。-第二类记录文件内容存储相关信息,例如文件块情况、副本个数、每个副本所在的Data Node 信息等。-第三类用来记录HDFS中所有Data Node信息,用于Data Node管理。
3)内存元数据结构INode文件和目录是文件系统的基本元素,HDFS将这些元素抽象成INode,每一个文件或目录都对应一个唯一的INode。它由FSNamesystem的成员变量dir实现对整个HDFS中INode的组织和操作,它是一个FSDirectory类。
INode信息完全位于内存,因此有效的提高元数据的服务性能,然而一旦掉电将不再存在,故需要将INode信息保存到磁盘,这个功能是由FSImage完成的,它是架构在内存元数据与磁盘元数据文件之间的桥梁。
由于所有的元数据位于内存,其大小随文件系统的规模增大而增大,如果每次都将整个内存元数据导出磁盘,将会带来很大的系统开销,所以HDFS在实现时,没有采用定期导出元数据的方法,而是采用元数据镜像文件(FSImage)+日志文件(edits)的备份机制,其中镜像文件是某一时刻内存元数据的真实组织情况,而日志文件则记录了该时刻以后所有的元数据操作 。
BlockBlock是对于文件内容组织而言的,按照固定大小,顺序对文件进行划分并编号,划分好的每一个块就称之为一个Block,HDFS默认的Block大小为128MB。
当一个客户端访问某一个文件特定偏移量的内容时,HDFS首先根据路径信息找到该文件对应的INode ,根据偏移计算出Block位置,然后找出相应的BlockInfo,再找到副本所在Data Node 的信息,选择其中一个Data Node进行连接,获取相应的内容。
4)磁盘元数据文件磁盘元数据文件包括以下四个:
- fsimage:元数据镜像文件
- edits:日志文件
- fstime:保存最近一次Checkpoint的时间。
- VERSION:标志性文件,最后被创建,它的存在表明前三个元数据文件的创建成功。
- 磁盘数据镜像文件fsimage
镜像文件实际是存放目录结构、文件属性等相关信息。fsimage文件是NameNode中关于元数据的镜像,一般称为检查点,它是在NameNode启动时对整个文件系统的快照。fsimage文件是hadoop文件系统元数据的一个永久性的检查点,其中包含hadoop文件系统中的所有目录和文件idnode的序列化信息。 - 数据操作日志文件edits
记录着对集群的每一个操作。编辑日志是记录对文件或者目录的修改信息,比如删除目录,修改文件等信息。编辑日志一般命名规则是“edits_*”,它在NameNode启动后,记录对文件系统的改动序列。edits文件存放的是hadoop文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。
2.存储机制
内存中有一份完整的元数据(内存metadata)磁盘有一个”准完整“的元数据镜像文件(在NN的工作目录中)用于衔接内存metadata和持久化元数据镜像fsimage之间的操作日志(edits文件)
———————————————————————————————————————————-
DataNode工作机制
————————————-
工作职责
- 存储管理用户的文件块数据
- 定期向NameNode汇报自身所持有的bock块信息(通过心跳信息上报)
————————————————————————————————————————————
SecondaryNamenode工作机制
——————————————————
edits文件会在集群运行的过程中不断增多,占用更多的存储空间,虽然有合并,但是只有在namenode重启时才会进行。并且在实际工作环境很少重启namenode,这就带来了一下问题:(1)edits文件不断增大,如何存储和管理?(2)因为需要合并大量的edits文件生成fsimage,导致namenode重启时间过长。(3)一旦namenode宕机,用于恢复的fsiamge数据很旧,会造成大量数据的丢失。
1.SNN通知NN切换edits文件SecondaryNameNode通知NameNode准备提交edits文件,此时主节点将新的写操作数据记录到一个新的文件edits.new中。
2.SNN从NN获得fsimage和editsSecondaryNameNode通过HTTP GET方式获取NameNodFailed to locate the winutils binary in the hadoop binary path java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.e的fsimage与edits文件(在SecondaryNameNode的current同级目录下可见到 temp.check-point或者previous-checkpoint目录,这些目录中存储着从namenode拷贝来的镜像文件)。
3.SNN将fsimage载入内存,然后开始合并editsSecondaryNameNode开始合并获取的上述两个文件,产生一个新的fsimage文件fsimage.ckpt。
4.SNN将新的fsimage发回给NNSecondaryNameNode用HTTP POST方式发送fsimage.ckpt至NameNode。
5.NN用新的fsimage替换旧的fsimageNameNode将fsimage.ckpt与edits.new文件分别重命名为fsimage与edits,然后更新fstime,整个checkpoint过程到此结束。
从工作过程可以看出,SecondaryNameNode的重要作用是定期通过编辑日志文件合并命名空间镜像,以防止编辑日志文件过大。SecondaryNameNode一般要在另一台机器上运行,因为它需要占用大量的CPU时间与namenode相同容量的内存才可以进行合并操作。它会保存合并后的命名空间镜像的副本,并在namenode发生故障时启用。
———————————————————————————————————————————————————
HDFS的HA(高可用)运行机制
————————————————-
- Active NameNode 和 Standby NameNod
两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务。<br />
- 主备切换控制器 ZKFailoverController
ZKFailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。 ZKFailoverController 能及时检测到 NameNode 的健康状况,在主 NameNode 故障时借 助 Zookeeper 实现自动的主备选举和切换,当然 NameNode 目前也支持不依赖于 Zookeeper 的手动主备切换。<br />
- Zookeeper 集群
为主备切换控制器提供主备选举支持。<br />
- 共享存储系统:
共享存储系统是实现 NameNode 的高可用最为关键的部分,共享存储系统保存了 NameNode 在运行过程中所产生的 HDFS 的元数据。<br />
- NameNode
通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主 NameNode 在确认元 数据完全同步之后才能继续对外提供服务。<br />
- DataNode 节点
除了通过共享存储系统共享 HDFS 的元数据信息之外,主 NameNode 和备 NameNode 还 需要共享 HDFS 的数据块和 DataNode 之间的映射关系。DataNode 会同时向主 NameNode 和备 NameNode 上报数据块的位置信息。
流程:
1.HealthMonitor 初始化完成之后会启动内部的线程来定时调用对应 NameNode 的HAServiceProtocol RPC 接口的方法,对 NameNode 的健康状态进行检测。
2.HealthMonitor 如果检测到 NameNode 的健康状态发生变化,会回调 ZKFailoverController 注册的相应方法进行处理。
3.如果 ZKFailoverController 判断需要进行主备切换,会首先使用 ActiveStandbyElector 来进行自动的主备选举。
4.ActiveStandbyElector 与 Zookeeper 进行交互完成自动的主备选举。
5.ActiveStandbyElector 在主备选举完成后,会回调 ZKFailoverController 的相应方法来通知当前的 NameNode 成为主 NameNode 或备 NameNode。
6.ZKFailoverController 调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法将 NameNode 转换为 Active 状态或 Standby 状态。