目录
HDFS概述
- 数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统 。
- 是一种允许文件通过网络在多台主机上分享的文件系统,可让多机器上的多用户分享文件和存储空间。
- 通透性。(可以理解为把底层的操作做了一个隐藏)让实际上是通过网络来访问文件的动作,由程序与用户看来,就像是访问本地的磁盘一般。
- 容错。即使系统中有某些节点宕机,整体来说系统仍然可以持续运作而不会有数据损失【通过副本机制实现】(Redis中有去中心化、主从结构)。
- 分布式文件管理系统很多,hdfs只是其中一种,不合适小文件
HDFS的架构分析
HDFS的作用
负责数据的分布式存储
主从结构
主节点(namenode)
主节点,可以有两个:namenode
是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表。接收用户的操作请求。
文件包括:(元数据存储在内存中,每一次关闭机器,再重新打开,发现数据还在,说明肯定做了一个存储,存到了硬盘中)
- fsimage:元数据镜像文件(备份)。存储某一时段NameNode内存元数据信息。
- edits:操作日志文件,namenode启动后一些新增元信息日志。(存的是hdfs的操作记录)
- fstime:保存最近一次checkpoint的时间
文件存储在:Linux的文件系统中
hdfs-site.xml的dfs.namenode.name.dir属性
主节点的作用
- 管理元数据(正常情况在内存中),元数据包含了许多信息:当前数据存储在哪个位置,当前数据有几个block块,block大小多大,在哪等等
- 接收用户的操作请求,是用户操作的入口
- 维护文件系统的目录结构,称作命名空间
主节点的位置
从节点(datanode)
从节点,有多个:datanode
主从结构中从节点挂了还可以正常运行,主节点挂了就没了
- 提供真实文件数据的存储服务。
- 文件块(block):最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。2.0以后HDFS默认Block大小是128MB,以一个256MB文件,共有256/128=2个Block.
hdfs-site.xml中dfs.blocksize属性 - 不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间
- Replication。多复本。默认是三个。
hdfs-site.xml的dfs.replication属性
从节点的作用
存储数据
从节点的位置
这里的ID都是对应的
打开从节点的数据查看一下
secondarynamenode
帮namenode来处理数据
secondarynamenode来对数据进行监控,监控时间到了之后,来通知namenode来进行处理(没有它,namenode也可以正常用)
合并(chickpiont)
这个合并的过程叫做checkpiont
为什么要进行合并edits:假设我们做了一个操作时上传一个文件,那么日志里面会存储这条记录,并且也会记得日志存储在哪,假设我们不对它进行合并(fsimage+edits),那么数据会发生丢失,所以进行合并产生新的fsimage
(这里的默认64MB指的是操作命令那一条指令的大小一共是64,才会进行合并,或者也可以重启,也会合并)
Client读取多副本文件过程
根据一个就近原则去读取
HDFS读写数据流程
HDFS读数据
简化描述
1、open,打开HDFS的文件存储系统
2、向下找某一个具体的数据;这就需要去找namenode了,namenode里面存储了它的元数据信息(包括位置在哪,大小是多少等等)
3、开始读数据了(多个block就按顺序读)
挂了就找副本
4、读完就关闭
原描述
1.首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例
2.DistributedFileSystem通过rpc获得文件的第一个block的locations(namenode查出来的),同一block按照副本数(一个block的文件有三个备份)会返回多个locations(返回给open方法),这些locations按照hadoop拓扑结构(远近)排序,距离客户端近的排在前面.
3.前两步会返回一个(io流对象,封装成)FSDataInputStream对象,该对象会被封装成DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode并连接。
4.数据从datanode源源不断的流向客户端。
5.如果第一块的数据读完了,就会关闭指向第一块的datanode连接,接着读取下一块。(有多个block就还继续按照上面的顺序接着读取)这些操作对客户端来说是透明的(也就是用户不需要知道下面都做了什么),客户端的角度看来只是读一个持续不断的流。
6.如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。
如果在读数据的时候,DFSInputStream和datanode的通讯发生异常,就会尝试正在读的block的排第二近的datanode,并且会记录哪个datanode发生错误,剩余的blocks读的时候就会直接跳过该datanode。DFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后DFSInputStream在其他的datanode上读该block的镜像
该设计的方向就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanode,namenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。
HDFS写数据
写数据的时候要注意副本问题,要么同时成功,要么同时失败,具有原子性;不存在一个副本写入成功,一个副本写入失败的问题
简化描述
1、create,打开了FileSystem
2、打开namenode;namenode要了解这个新的文件的信息(文件写在了哪,大小多少等等)
3、写数据
4、包的形式做数据传输,namenode告诉流,哪个地方存储比较合适
5、返回做验证,验证是否写成功,要是一个失败,那就全部失败(原子性),打开ack,监听是否成功
6、关闭流
7、将数据传给namenode做分配
原描述
1.客户端通过调用DistributedFileSystem的create方法创建新文件
2.DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件(这时候还没有决定存在哪个位置),创建前,namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,namenode就会记录下新文件,否则就会抛出IO异常.
3.前两步结束后会返回FSDataOutputStream的对象,像读文件的时候相似,FSDataOutputStream被封装成DFSOutputStream.DFSOutputStream可以协调namenode和datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列data quene(理解为缓存,将数据进行排列,有序的,方便切分,比如数据到了128MB,可以进行切分)。
4.DataStreamer会去处理接受data queue,他先问询namenode这个新的block最适合存储的在哪几个datanode里,比如副本数是3,那么就找到3个最适合的datanode(namenode告诉了数据流,存储到哪个地方比较合适),把他们排成一个pipeline(类似于队列中的出栈,出去就没了).DataStreamer把packet按队列输出到管道的第一个datanode中,第一个datanode又把packet输出到第二个datanode中,以此类推。
5.DFSOutputStream还有一个对列叫ack queue(一个队列是传输数据,一个队列是验证),也是由packet组成,等待datanode的收到响应,当pipeline中的所有datanode都表示已经收到的时候,这时ack queue才会把对应的packet包移除掉。(ack就是把数据搞成了两个队列,防止数据发生错误;一个队列是出栈的,存储到datanode,一个队列是验证的,当验证没有问题之后,ack才会把自己的数据丢掉,留着就是为了防止出现问题,找不到数据了)
如果在写的过程中某个datanode发生错误,会采取以下几步:1) pipeline被关闭掉;2)为了防止丢包ack queue里的packet会同步到data queue里;3)把产生错误的datanode上当前在写但未完成的block删掉;4)block剩下的部分被写到剩下的两个正常的datanode中;5)namenode找到另外的datanode去创建这个块的复制(也是三个的)。当然,这些操作对客户端来说是无感知的。
6.客户端完成写数据后调用close方法关闭写入流
7.DataStreamer把剩余得包都刷到pipeline里然后等待ack信息,收到最后一个ack后,通知namenode把文件标示为已完成
感谢阅读,我是啊帅和和,一位大数据专业大四学生,祝你快乐。