认识HDFS
HDFS的特点:
高容错性
高吞吐量
故障的检测和自动快速恢复
流式的数据访问
大数据集
一次写入,多次读写
HDFS不适用的场景
不支持大量小文件的存储
不适合随机读写
不适合随意修改
HDFS的组成
hdfs是一个主从结构的体系,一个HDFS的集群由以下部分组成:
NameNode(名字节点):一个用来管理文件的名字空间和调节客户端访问文件的主服务器
DataNode(数据节点):一个或多个,用来管理存储
HDFS的数据复制
HDFS能可靠的在大量集群中存储非常大量的文件,它以块序列的形式存储每一个文件,文件中除了最后一个块的其他块都是相同的大小.属于文件的块为了故障容错而被复制.块的大小和复制数可以为每个文件配置.HDFS中的文件都是严格地要求任何时候只有一个写操作.
名字节点(NameNode)来做所有的块复制,它周期性地接收来自集群中数据节点(DataNode)的心跳和块报告.一个心跳的收条表示这个数据节点是健康的,是渴望服务数据的.一个块报告包括该数据节点上的所有块列表.复制块放置位置的选择严重影响HDFS的可靠性和性能,因此机架的复制布局目的就是提高数据的可靠性、可用性和网络带宽的利用率
默认复制数为3的情况下,HDFS放置方式是将第一个放在本地节点,将第二个复制放到本地机架上的另一个节点上,而将第三个复制到不同机架上的节点。这种方式减少了机架内的写流量,提高了写的性能.机架的失效机会远小于机器失效的机会
在复制数为3的情况下,是备份在不同的机架上,而不是三个机架.文件的复制不是均匀地分布在机架上.1/3在同一个节点上,第二个1/3复制在同一个机架上,另外1/3是均匀地分布在其他机架上.
可在hdfs-site.xml中修改dfs.replication的个数即修改复制个数,这种方案参数其实只在文件被写入dfs时起作用,虽然更改了配置文件,但是不会改变之前写入的文件的备份数,而且需要重启HDFS系统才能生效
hadoop fs -setrep -R 1 /:这种方式可以改变整个HDFS里面的备份数,不需要重启HDFS系统
数据块的复制是以pipeline的方式进行的
HDFS复制的选择
HDFS尝试满足一个读操作来自离它最近的复制。如果在读节点的同一个机架上有这个复制,则直接读.如果HDFS集群是跨越多个数据的中心,那么本地数据中心的复制优先于远程的复制
HDFS的安全模式
在启动的时候,NameNode会进入一个特殊的状态叫做安全模式。
安全模式是不发生文件块的复制的
NameNode接受DataNode的心跳和数据块报告,一个块报告包括数据节点向名字节点报告数据块的列表
每一个块有一个特定的最小复制数,当NameNode检查这个块已经大于最小的复制数,就被认为是安全的复制了.当达到配置的块安全复制比例时,NameNode就退出安全模式.它将检测数据块的列表,将小于特定的复制数的块复制到其他的数据节点
HDFS的元数据持久化
HDFS的名字空间是由NameNode来存储的。
NameNode用事务日志(EditsLog)来持久化每一个对文件系统的元数据的改变,即对元数据的每一步操作都会被记录到EditsLog中.NameNode在本地文件系统中用一个文件来存储这个EditsLog
完整的文件系统名字空间、文件块的映射和文件系统的配置都存在一个叫Fsimage的文件中,Fsimage也是在NameNode的本地文件系统中
CheckPoint(检查点):当NameNode启动的时候,它会从磁盘中读取Fsimage和EditsLog文件,然后将新的元数据刷新到本地磁盘中,生成一个新的Fsimage文件,至此EditsLog文件已经被处理并持久化的Fsimage中
任何对Fsimage和EditsLog的更新都会同步地更新每一个副本
HDFS架构
HDFS架构是一个典型的主从架构,包括一个NameNode(主节点)和多个DataNode(从节点)
架构图如下图所示:
NameNode是整个文件系统的管理节点,它负责文件系统名字空间(NameSpace)的管理与维护,同时负责客户端文件操作的控制以及具体存储任务的管理与分配
DataNode提供了真实文件数据的存储服务
数据块
Hadoop1.X默认的数据块大小是64MB
Hadoop2.X默认的数据块大小是128MB
HDFS上的文件系统也被划分为块大小的多个分块(Chunk)作为独立的存储单元.但与其他文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块的空间
为什么HDFS默认的Block为128MB(64MB)?
HDFS的块之所以这么大,主要是为了把寻道(Seek)时间最小化.如果一个块足够大,从硬盘传输数据的时间将远远大于寻找块的起始位置的时间,这样就使HDFS的数据传输速度和硬盘的传输速度更加接近.
分布式文件系统中的块进行抽象带来的好处:
一个文件系统的大小可以大于网络中任意一个磁盘的容量
使用块抽象而非整个文件作为存储单元,大大简化了存储子系统的设计.
NameNode
NameNode是管理者,一个Hadoop集群有一个NameNode节点,是一个通常在HDFS实例中的单独机器上运行的软件.它负责管理文件系统名字空间和控制外部客户机的访问
NameNode决定是否将文件映射到DataNode的复制块上.
实际的I/O事务并没有经过NameNode,只有表示DataNode和块的文件映射的元数据经过NameNode。当外部客户机发送请求要求创建文件时,NameNode会以块标识和该块的第一个副本的DataNode IP地址作为响应.这个NameNode还会通知其他将要接收该块的副本的DataNode
NameNode主要功能如下:
1:NameNode提供名称查询服务,它是一个Jetty服务器
2:NameNode保存metadata信息.具体包括:文件owership和permissons;文件包含哪些块,Block保存在哪个DataNode(由DataNode启动时上报)
3:NameNode的metadata信息在启动后会加载在内存
DataNode
Hadoop集群中包含一个NameNode和大量的DataNode,DataNode通常以机架的形式组织,机架通过一个交换机将所有系统连接起来
DataNode响应来自HDFS客户机的读写请求,它们还响应来自NameNode的创建、删除和复制块的命令
DataNode的功能如下:
1:保存Block,每一个块对应一个元数据信息文件。这个文件主要描述这个块属于哪个文件,第几个块等信息
2:启动DataNode线程的时候会向NameNode汇报Block信息
3:通过向NameNode发送心跳保持其联系(3秒一次),如果NameNode10分钟没有收到DataNode的心跳,则认为其已经lost,并将其上的Block复制到其他DataNode
SecondaryNameNode
SecondaryNameNode(辅助元数据节点),会周期性地将EditsLog文件中记录对HDFS的操作合并到一个Fsimage中文件中,然后清空EditsLog文件.NameNode的重启会加载最新的一个Fsimage文件,并重新创建一个EditsLog文件来记录HDFS操作,由于EditsLog中记录的是从上一次Fsimage以后到现在的操作列表,所以会比较小
如果没有SecondaryNameNode这个周期性的合并过程,当每次重启NameNode的时候,就会花费很长的时间,而这样周期性地合并就能减少重启的时间,同时也能保证HDFS系统的完整性
SecondaryNameNode合并Fsimage和EditsLog文件过程如下:
1:文件系统客户端进行写操作时,首先会把它记录在EditsLog中
2:NameNode在内存中保存了文件系统的元数据信息.在记录修改日志后,NameNode修改内存中的数据结构
3:每次的写操作成功之前,修改日志都会同步(Sync)到文件系统中
4:Fsimage文件即名字空间映像文件,是内存中的元数据在硬盘上的CheckPoint,它是一种序列化的格式,并不能够在硬盘上直接修改
5:当NameNode失败时,最新CheckPoint的元数据信息从Fsimage加载到内存中,然后逐一重新执行修改日志后的操作
6:SecondaryNameNode就是用来帮助NameNode将内存中的元数据信息CheckPoint到硬盘上的.
CheckPoint过程如下:
1:SecondaryNameNode通知NameNode生成新的EditsLog,以后的日志都写到新的日志文件中
2:SecondaryNameNode用Http Get从NameNode获得Fsimage文件以及旧的日志文件
3:SecondaryNameNode将Fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的Fsimage文件
4:SecondaryNameNode将新的Fsimage文件用Http Post传回NameNode
5:NameNode可以将旧的Fsimage以及旧的EditLog,换成新的Fsimage文件和新的EditLog(第一步生成的),然后更新fstime文件,写入此次CheckPoint的时间
6:这样NameNode中的Fsimage文件保存了最新的CheckPoint的元数据信息,日志文件也重新开始,不会变得很大了.
SecondaryNameNode会周期性地将EditsLog文件进行合并,合并前提条件如下:
EditsLog文件到达某一阀值时对其进行合并(默认为64MB,当文件大小超过64MB,就会触发EditsLog与Fsimage文件的合并,修改core-site.xml配置文件中的fs.checkpoint.period选项)
每隔一段时间对其合并(默认为1小时合并一次,修改core-site.xml配置文件中的fs.checkpoint.size)
机架感知
默认情况下,Hadoop的机架感知是没有启用的.所以,通常情况下,Hadoop集群的HDFS在选择机器的时候是随机选择的.
启用Hadoop机架感知功能,配置非常简单,在NameNode所在机器 的hadoop-site.xml文件中配置一个选项
<property>
<name>topology.script.file.name</name>
<value>/path/to/script</value>
</property>
HDFS的RPC机制
一般我们所了解的RPC(Remote Procedure Call,远程过程调用)机制都要面对两个问题:
1对象调用方式;
2序列/反序列化机制
但Hadoop实现了自己简单的RPC组件,依赖Hadoop Writable类型的支持
Hadoop Writable接口要求每个实现类都要确保将本类的对象正确序列化(writeObject)与反序列化(readObject)。因此,Hadoop RPC使用java动态代理与反射实现对象调用方式
RPC的实现流程
简单的说,Hadoop RPC = 动态代理+定制的二进制流
实现流程如下:
远程的对象拥有固定的接口,这个接口用户也是可见的,只是真正的实现(Object)只在服务端.用户如果想使用哪个实现,调用过程是:
先根据那个接口动态代理生成一个代理对象,调用这个代理对象的时候,用户的调用请求被RPC捕捉到,然后包装成调用请求,序列化成数据流发送到服务端;服务端从数据流中解析出调用请求,然后根据用户所希望调用的接口,调用真正的实现对象,再把调用结果返回给客户端
RPC的实体模型
注意:用户在调用代理对象时RPC是怎样拦截这次调用请求的?
创建代理对象时需要为它关联一个InvocationHandler,对代理对象的每次调用都会进入绑定的InvocationHandler中,RPC就从这里获取用户的请求
Listener:监听RPC Server的端口,如果客户端有连接请求到达,它就接收连接,然后把连接转发到某个Reader,让Reader读取那个连接的数据。如果有多个Reader,当有新连接过来时,就在这些Reader间顺序分发。注意Hadoop0.21版本在支持多Reader时有个bug(JIRA),如果有Reader在Server运行期间没有被使用,Server进程不能正常关闭
Reader:从某个客户端连接中读取数据流,把它转化成调用对象(Call),然后放到调用队列(call queue)里
Handler:真正做事的实体,它从调用队列中获取调用信息,然后反射调用真正的对象,得到结果,再把此次调用放到响应队列(response queue)里
>Responder:不断地检查响应队列中是否有调用信息,如果有,就把调用的结果返回给客户端
HDFS的文件读取
文件读取的流程如下:
1:使用HDFS提供的客户度开发库Client,向远程的NameNode发起RPC请求
2:NameNode会根据情况返回文件的部分或者全部Block列表,对于每个Block,NameNode都会返回有该Block副本的DataNode地址
3:客户端开发库Client会选取离客户端最接近的DataNode来读取Block,如果客户端本身就是DataNode,将从本地直接获取数据
4:读取完当前Block的数据后,关闭与当前的DataNode连接,并为读取下一个Block寻找最佳的DataNode
5:读取完列表的Block后,且文件读取还没有结束,客户端开发库会继续向NameNode获取下一批Block列表
6:读取完一个Block都会进行CheckSum验证,如果读取DataNode时会出现错误,客户端会通知NameNode,然后从下一个拥有该Block复制的DataNode继续读
HDFS的文件写入
写入文件的过程比读取复杂,步骤如下:
1:使用HDFS提供的客户端开发库Client,向远程的NameNode发起RPC请求
2:NameNode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功后会为文件创建一个记录,否则会让客户端抛出异常
3:当客户端开始写入文件的时候,开发库会将文件切分多个packet,并在内部以数据队列(data queue)的形式管理这些packet,并向NameNode申请新的Block,获取用来存储replicas的合适的DataNode列表,列表的大小根据在NameNode中对replication的设置而定
4:开始以管道(pipeline)的形式将Packet写入所有的replicas中。开发库把packet以流的方式写入第一个DataNode,该DataNode把packet存储之后,再把器传递给在此管道中的下一个DataNode,直到最后一个DataNode,这种写数据的方式呈流水线的形式
5:最后一个DataNode成功存储之后会返回一个ack packet,在管道里传递给客户端,在客户端的开发库内部维护着ack queue,成功收到DataNode返回的ack packet后会从ack queue移除相应的packet
6: 如果传输过程中,有某个DataNode出现了故障,当前的管道会被关闭,出现故障的DataNode会从当前的管道中移除,剩余的Block会继续剩下的DataNode中继续以管道的形式传输,同时NameNode会分配一个新的DataNode,保持replicas设定的数量
HDFS的HA(High Availability,高可用性)机制
Hadoop2.X版本之前,NameNode是HDFS集群的单点故障点(SPOF)
影响HDFS集群不可用主要包括以下两种情况:
1:类似机器宕机这样的意外情况将导致集群不可用,只有重启NameNode之后才可使用
2:计划内的软件或硬件升级(NameNode节点),将导致集群在短时间范围内不可用
一个典型的HA集群,两个单独的机器配置为NameNode,在任何时候,一个NameNode处于活动状态,另一个处于待机状态,活动NameNode负责处理集群中所有客户端的操作,待机时仅仅作为一个Slave,保持足够的状态,如果有必要提供一个快速的故障转移
为了提供快速的故障转移,必须保证备用节点有最新的集群中块的位置信息,为了达到这一点,DataNode节点需要配置两个NameNode的位置,同时发送块的位置信息和心跳信息到两个NameNode
为了防止"脑裂场景"的出现,必须为共享存储配置至少一个fencing方法。在宕机期间,如果不能确定之间的活动节点已经放弃活动状态,fencing进程负责中断以前的活动节点编辑存储的共享访问,这可以防止任何进一步的修改名字空间.允许新的活动节点安全地进行故障转移
HA架构解释如下:
只有一个NameNode是Active,并且只有这个ActiveNameNode能提供服务,改变NameSpace。以后可以考虑让StandbyNameNode提供读服务
提供手动Failover,在升级过程中,Failover在NameNode-DataNode之间写不变的情况下才能生效
在之前的NameNode重新恢复之后,不能提供failback
数据一致性比Failover更重要
HA的设置和Failover都应该保证在两者操作错误或者配置错误的时候,不得导致数据损坏
NameNode的短期垃圾回收不应该触发Failover
DataNode会同时向NameNode Active和NameNode Standary汇报块的信息。NameNode Active和NameNode Standby 通过NFS备份MetaData信息到一个磁盘上面
HDFS的federation机制
简单的说,HDFS Federation就是使得HDFS支持多个名字空间,并且允许在HDFS中同时存在多个NameNode
引入Federation的最主要原因是对HDFS系统中文件的隔离,Federation能够快速解决大部分单NameNode HDFS的问题
HDFS Federation使用了多个独立的NameNode/NameSpace使得HDFS的命名服务能够水平扩展
HDFS Federation中的NameNode之间是联盟关系,它们之间相互独立且不需要相互协调。HDFS Federation中的NameNode提供了名字空间和块关联功能.HDFS Federation中的DataNode被所有的NameNode用作公共存储块的地方.每一个DataNode都会向所在集群中所有的NameNode注册,并周期性的发送心跳和块信息报告,同时处理来自NameNode的指令
块池(Block Pool)就是属于单个名字空间的一组Block
Federation HDFS中有多组独立的块,同一个DataNode中可以存储属于多个块池的多个块。
块池允许一个名字空间在不通知其他名字空间的情况下,为一个新的Block创建Block ID.同时,一个NameNode失效不会影响其下的DataNode为其他NameNode的服务
在HDFS中,所有的更新、回滚都是以NameNode和BlockPool为单元发生的.即同HDFS Federation中不同的NameNode/BlockPool之间没有什么关系
多个名字空间的管理问题
在一个集群中需要唯一的名字空间还是多个名字空间,核心问题是名字空间中数据的共享和访问问题。
使用全局唯一的名字空间是解决数据共享和访问的一种方法
在多个名字空间下,还可以使用Client Side Mount Table方式做到数据共享和访问
HDFS Federation中名字空间管理的基本原理:
将各个名字空间挂载到全局mount-table中,就可以将数据到全局共享;
同样,名字空间挂载到个人的mount-table中,就成为应用程序可见的名字空间视图
维护HDFS
追加数据
1.Client调用fs的append操作
2.向流对象写数据
3.关闭流对象
并行复制
distcp(分布式复制)是用于大规模集群内部和集群之间复制的工具。它使用MapReduce实现文件分发、错误处理和恢复,以及报告生成。它把文件和目录的列表作为Map任务的输入,每个任务会完成源列表中部分文件的复制
操作命令:
hadoop distcp -overwrite -delete -i dir1 dir2
参数如下:
-delete:删除已经存在的目标文件,不会删除源文件。这个删除是通过FS Shell实现的。所以如果垃圾回收机制启动,删除的目标文件会进入trash
-i:忽略失败.这个选项会比默认情况提供关于复制的更精确的统计,同时它还将保留失败复制操作的日志。这些日志信息可以用于调试
-overwrite:覆盖目标。如果一个Map失败并且没有使用-i选项,那些复制失败的文件,以及这个分块任务中的所有文件都会被重新复制
升级与回滚
Hadoop升级分为两种:
一种是集群布局不发生任何变化的,这种升级非常简单,类似安装一次新的Hadoop程序。
另外一种是集群布局发送变化的
两种升级升级都简单分为以下几步:
1.在执行新一轮的升级前,要确保前一次升级已经完成
hadoop dfsadmin -upgradeProgress status
2.进行数据的备份,以方便升级后对照,如果有问题可发现然后回滚版本
hadoop fs -lsr / > ~/namenode.log
hadoop fsck / >> ~/namenode.log
cp -r ${dfs.name.dir} ~/namenode_backup
3.使用stop-all.sh关闭hadoop集群
4.把${dfs.name.dir}目录下的所有内容复制到新配置的路径下,这是集群布局有变化的操作,如果没有新配置布局就不用这个操作了,单独启动新的主节点NameNode的hdfs进行更新操作
${NEW_HADOOP}/bin/start-dfs.sh -upgrade
使用如下命令进行监控,查看是否升级完成
${NEW_HADOOP}/bin/hadoop dfsadmin -upgradeProgress status
5.把新版本的Hadoop程序和配置文件一起分发给集群里所有的机器,根据情况看是不是需要进行个别修改,没有特别的就不用改了。修改/etc/profile中的Hadoop环境变量,改成新版本Hadoop的指向。现在使用启动集群的start-all.sh命令来启动集群就行了
6.使用fs -lsr 和fsck与namenode.log文件进行核对前后信息变化,如果没有问题,数据块体验也通过,就顺利完成升级,这时需要执行如下命令来最终确定升级完成和清理前版本数据
hadoop dfsadmin -finalizeUpgrade
rm -r ~/namenode_backup ~/namenode.log
至此升级完成,不能再进行回滚操作,如果升级后发现数据不符,可以使用如下命令回滚版本
stop-all.sh
start-dfs.sh -rollback
添加节点
1.修改host。和普通的DataNode一样,添加NameNode的IP
2.修改NameNode的配置文件conf/slaves。添加新增节点的Ip或主机名
3.在新节点的机器上启动服务
bin/hadoop-daemon.sh start datanode
bin/hadoop-daemon.sh start tasktracker
4.均衡Block
bin/start-balancer.sh
为什么要执行start-balancer.sh操作呢?
如果不执行start-balancer.sh操作.cluster会把新的数据都存放在新的节点上,这样会降低MapReduce的工作效率
执行start-balancer.sh操作的优化如下
1.设置平衡阀值,默认是10%,值越低各节点越平衡,但消耗时间也更长
bin/start-balancer.sh -threshold 5
2.设置balancer的带宽,默认只有1M/s.编辑hdfs-site.xml文件
<property>
<name>dfs.balance.bandwidthPerSec</name>
<value>10485760</value>
</property>
删除节点
1.集群配置
修改conf/hdfs-site.xml文件
<property>
<name>dfs.hosts.exclude</name>
<value>/data/soft/hadoop/conf/excludes</value>
</property>
2.确定要下架的机器
dfs.hosts.exclude定义的文件内容为每个需要下线的机器,一行一个。这将阻止它们连接NameNode.
例如/data/soft/hadoop/conf/excludes的内容如下:
ubuntu4
这样就把ubuntu4这台设备从hadoop集群中删除了。还有一种方法可以实现ubuntu4设备从hadoop集群中删除,配置如下:
<property>
<name>dfs.hosts.exclude</name>
<value>ubuntu4</value>
</property>
3.强制重新加载配置
bin/hadoop dfsadmin -refreshNode
它会在后台进行Block块的移动
4.关闭节点
bin/hadoop dfsadmin -report
可以查看到现有集群上连接的节点信息
5.再次编辑excludes文件
一旦完成机器下架,下架的设备就可以从excludes文件移除了。登录要下架的机器,会发现DataNode进程没有了,但是TaskTracker依然存在,需要手动关闭
HDFS权限管理
hadoop分布式文件系统实现了一个和POSIX系统类似的文件和目录的权限模型。每个文件和目录有一个所有者(owner)和一个组(group)
总的来说,文件或目录的权限就是它的模式。HDFS采用了UNIX表示和显示模式的习惯,包括使用八进制数来表示权限。当新建一个文件或目录,所有者即客户进程的用户,它的所属组是父目录的组
HDFS并不提供创建用户身份、创建组或用户凭证等功能