分布式文件系统是管理网络中跨多台计算机存储的文件系统。HDFS(Hadoop Distributed File System)以流式数据访问模式来存储超大文件,运行于商用硬件集群上。其中流式数据访问指的是一次写入、多次读取是最高效的访问模式。
HDFS具有以下几大特性:
- 高容错性
- 高吞吐量
- 超大数据集
- 流式数据访问
- 移动计算优于移动数据
- 轻便访问异构的软硬件平台
主从结构
HDFS采用主从结构,即1个namenode,多个datanode。
NameNode(管理节点)
NameNode Metadata
元数据存储方式NameNode(FileName, replicas, block-ids,id2host…)
/test/a.log, 3 ,{blk_1,blk_2}, [{blk_1:[h0,h1,h3]},{blk_2:[h0,h2,h4]}]
功能
NameNode的功能主要有以下几点:
- 维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表。
- 调节客户端访问文件的主服务器(提供名称查询服务、保存metadata、启动后加载metadata至内存)
同时它周期性地从集群中的每个Datanode接收心跳信号和块状态报告(Blockreport)。接收到心跳信号意味着该Datanode节点工作正常。块状态报告包含了一个该Datanode上所有数据块的列表。读取文件时NameNode尽量让用户先读取最近的副本,降低带块消耗和读取时延。
NameNode的工作特点
NameNode中元数据的持久化::
Fsimage:元数据镜像文件。在本地文件系统中:存储某一时段NameNode内存元数据信息。包括完整的文件系统命名空间、文件块的映射和文件系统的配置。
Edits:操作日志文件。(用于持久化每一个对文件系统的元数据的改变。
Fstime:保存最近一次checkpoint的时间。检查点发生在NameNode启动时。
以上这些文件是保存在linux的文件系统中。
Namenode始终在内存中保存metedata,用于处理“读请求”。有“写请求”到来时,namenode会首先写editlog到磁盘,即向edits文件中写日志,成功返回后,才会修改内存,并且向客户端返回
Hadoop会维护一个fsimage文件,也就是namenode中metedata的镜像,但是fsimage不会随时与namenode内存中的metedata保持一致,而是每隔一段时间通过合并edits文件来更新内容。Secondary namenode就是用来合并fsimage和edits文件来更新NameNode的metedata的。
Secondary NameNode
Secondary NameNode是HA(高可靠性)的一个解决方案。
执行过程:周期性从NameNode上下载元数据信息(fsimage, edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode(Namenode启动时加载最新的FSImage),替换旧的fsimage。
默认在安装在NameNode节点上,但这样不安全!
1. secondary namenode的工作流程
1、secondary通知namenode切换edits文件
2、secondary从namenode获得fsimage和edits(通过http)
3、secondary将fsimage载入内存,然后开始合并edits
4、secondary将新的fsimage发回给namenode
5、namenode用新的fsimage替换旧的fsimage
2. 什么时候checkpiont
复制触发的条件在core-site.xml中
fs.checkpoint.period指定两次checkpoint的最大时间间隔,默认3600秒。
fs.checkpoint.size 规定edits文件的最大值,一旦超过这个值则强制checkpoint,不管是否到达最大时间间隔。默认大小是64M。即当EditsLog>64MB时,触发两文件合并
DataNode
存储形式:块
文件块(block):最基本的存储单位。磁盘块一般为512字节,文件系统块一般为几千字节,为前者的整数倍。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。HDFS默认Block大小是64MB(可使寻道时间最小化),以一个256MB文件,共有256/64=4个Block.。一个HDFS文件最多切分为128块。
PS:若上传文件<64MB,仍占用一个Block的Namenode Metadata,但物理空间不占用64MB
Fsck:查看块信息
优点::简化存储子系统的设计;大于网络中任意一个磁盘的容量
存储内容
一个数据块在DataNode以文件存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳
心跳机制
DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令,如复制块数据到另一台机器,或删除某个数据块。
如果超过10分钟没有收到某个DataNode 的心跳,则认为该节点不可用。
~集群运行中可以安全加入和退出一些机
保证可靠性的措施
HDFS保证可靠性的措施主要有以下几种方式
一个名字节点和多个数据节点
数据复制(冗余机制)(保证容错)
1. 三复本存放策略
将数据复制三份分别保存在以下三个地方:
1.本地机器的HDFS目录下
2.不同机架的某个DataNode
3.同一机架的某台机器上
2. 备份机制
如下图所示,由DataNode1流式传至DataNode2,再流式传至DataNode3
3. 存放的位置(机架感知策略)
机架感知:非自适应,通常情况,Hadoop随机选择机器,若数据量大,会造成性能瓶颈
故障检测
- DataNode
DataNode主要有以下几种方式
心跳机制:心跳包检测是否宕机)——
安全模式下检测:块报告
数据完整性检测(校验和比较) - NameNode
NameNode使用Secondary NameNode机制来保证故障检测。
空间回收机制
元数据保护——HA机制(版本2的zookeeper)——高可用性
当集群不可用(宕机、软件或硬件升级)时,只有手动故障转移。故可以通过提供热备用的“主/备”两个冗余Namenode来预防故障。注意,这里两个Namenode与Secondary Namenode是不同概念!两个Namenode中只有1个namenode是Active;在之前的Namenode重新恢复之后,不能提供failback;数据一致性比failback更重要,所以Namenode——Datanode之间写不变时才生效;DataNode会同时向Namenode Active和Namenode standby 汇报块信息。
~~还可以使用Federation机制
Federation:使HDFS支持多个Namespace。(简单鲁棒的设计:对HDFS文件系统文件的隔离)
解决的问题:单个NameNode的HDFS架构局限性带来的单点故障(性能瓶颈、隔离问题、集群可用性)
Remote Procedure Call
RPC是远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
Hadoop RPC抽象包装了ClientProtocal(客户端和NameNode)、DataNodeProtocal(NameNode和DataNode)Haddoop RPC使用Java动态代理和放射实现对象调用的,大致过程如下:
- Dynamic proxy创建代理对象,会关联一个Invocation Handler,RPC由此捕捉用户的调用请求
- 将调用请求序列化成二进制数据流发送到服务端
- 服务端解析调用请求,调用接口真正的接口,返回结果
(1)Listener:监听RPC Server端口
(2)Reader:从客户端连接中读取数据流,转化成调用对象call,放在call queue
(3)Handler:真正做事的实体,从call queue中获取call,反射调用真正对象,得到结果并放在response queue
(4)Responder:检查response queue,将调用结果放回到客户端
具体对RPC的介绍以及源码分析请看另外一篇博文
HDFS读过程
- 初始化FileSystem,然后客户端(client)用FileSystem的open()函数打开文件
- FileSystem用RPC调用元数据节点,得到文件的数据块信息,对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。
- FileSystem返回FSDataInputStream给客户端,用来读取数据,客户端调用stream的read()函数开始读取数据。
- DFSInputStream连接保存此文件第一个数据块的最近的数据节点,data从数据节点读到客户端(client)
- 当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
- 当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。
- 在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。
- 失败的数据节点将被记录,以后不再连接。
HDFS写过程
- 初始化FileSystem,客户端调用create()来创建文件
- FileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件,元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
- FileSystem返回DFSOutputStream,客户端用于写数据,客户端开始写入数据。
- DFSOutputStream将数据分成块,写入data queue。data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
- DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
- 当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。
- 如果数据节点在写入的过程中失败,关闭pipeline,将ack queue中的数据块放入data queue的开始,当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。
HDFS的访问
安全模式(只读)
- 安全模式主要是为了系统启动的时候检查各个DataNode上数据块的有效性,同时根据策略必要的复制或者删除部分数据块。
- 当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结束。
- 系统启动的时候去修改和删除文件也会有安全模式不允许修改的出错提示,只需要等待一会儿即可。
- NameNode在启动的时候首先进入安全模式,如果datanode丢失的block达到一定的比例(1- dfs.safemode.threshold.pct),则系统会一直处于安全模式状态即只读状态。
~dfs.safemode.threshold.pct(缺省值0.999f)表示HDFS启动的时候,如果DataNode上报的block个数达到了元数据记录的block个数的0.999倍才可以离开安全模式,否则一直是这种只读模式。如果设为1则HDFS永远是处于SafeMode。
命令:hadoop dfsadmin -safemode enter | leave | get |wait(进入、离开、得到当前状态信息、挂起)
Shell命令 - hadoop fs –put/ -ls/-get/-text/-rm
- Hadoop secondarynamenode –checkpoint / -geteditsize (强制进入检查点、打印editlog大小)
JavaAPI接口
1. FSDataInputStream
继承至DataInputStream继承至FileInputStream继承至InputSream继承至Object
作用:
用dataInputStream包装一个输入流,并使用BufferedInputStream实现对输入的缓冲
实现:
DataInputStream抽象类和Closeable接口:具有流式搜索和流式定位读取
PositionedReadable接口:从指定位置读取
2. FSDataOutputStream
与FSDataInputStream类相似,可查询文件当前位置,但不可定位。
详细HDFS文件操作介绍: http://www.open-open.com/lib/view/open1398335331546.html