一、数据块(block)
HDFS原理白话讲就是将大文件分为若干个块,将这些块散落在不同的服务器上进行存储。
1.1 数据块大小如何设置
在hdfs配置文件hdfs-site.xml中,通过dfs.blocksize参数配置
1.2 为什么hdfs的数据块这么大
hadoop 1.x默认块大小为64M,hadoop 2.x默认块大小为128M,hadoop3.x默认块大小为256M
数据块大小设置部分原因是和磁盘平均输出速率有关。例如寻址时间是10ms,磁盘平均输出速率为125M/s,假如让寻址时间占总传输时间的1%,那么传输时间即为1s,以这个磁盘平均输出速率计算,大概可以传输125M的数据。所以数据块设置比较大是为了减少总寻址时间。
如果数据块设置太大,对于计算(例如mapreduce)的压力就会比较大,以mapreduce来说,一个map至少处理一个block,如果block设置特别大,就会影响处理的效率。
如果数据块设置太小,就意味着map处理的数据量就会特别小,而map在处理的时候会开java虚拟机,开虚拟机也需要时间消耗,就有可能开虚拟机的时间远远大于处理数据的时间,同样也会造成效率低的问题;另外,block的信息都在namenode中存储,同样一个大文件,数据块设置太小,就意味着分的数据块越多,那么对应的元数据信息也就越多,对于namenode来说压力也就越大。
1.3 block的一些操作
1.3.1 设置文件副本数,有什么用?
数据分块存储和副本的存放,是保证可靠性和高性能的关键
方式一:使用命令设置文件副本数;动态生效,不需要重启hadoop集群
用途一般在降低磁盘使用率的时候会用到,如果删除数据还解决不了磁盘使用率高的问题,那么就将一部分数据的副本数减少,从而临时解决磁盘使用率过高的问题。
hadoop fs -setrep -R 4 /path
方式二:修改配置文件hdfs-site.xml,需要重启hadoop集群才能生效
<property>
<name>dfs.replication</name>
<value>4</value>
</property>
1.3.2 HDFS提供了fsck命令
①用于检查HDFS上文件和目录的健康状态、获取文件的block信息和位置信息
hdfs fsck
②查看文件中损坏的块
hdfs fsck /test/test.txt -list-corruptfileblocks
③查看文件的块基本信息
④删除损坏的文件
hdfs fsck /test/test.txt -delete
二、DataNode
部署datanode守护进程的节点叫做datanode节点。
datanode节点用来存储block。
2.1 副本数默认是多少,如何设置
hadoop默认副本数为3,可在hdfs-site.xml中通过dfs.replication参数设置
2.2 多副本存放策略
1个datanode节点存放某个block的一个副本
第一个副本存储在同Client相同节点上;
第二个副本存储在不同机架的节点上;
第三个副本存储在第二个副本机架中的另外一个节点上;
其他副本选择随机存储。
三、NameNode & SecondaryNameNode
3.1 namenode的作用
NameNode负责:文件元数据信息的操作以及处理客户端的请求
NameNode管理:HDFS文件系统的命名空间NameSpace
NameNode维护:文件系统树(FileSystem)以及文件树中所有的文件和文件夹的元数据信息(matedata),维护文件到块的对应关系和块到节点的对应关系
NameNode文件:namespace镜像文件(fsimage),操作日志文件(edit log)。这些信息被Cache在RAM中,当然这两个文件也会被持久化存储在本地硬盘
NameNode记录:每个文件中各个块所在的数据节点的位置信息。但它并不永久保存块的位置信息,因为这些信息在系统启动时由数据节点重建
从数据节点重建:在nameNode启动时,DataNode向NameNode进行注册时发送给NameNode
【命名空间和元数据】
- 元数据
- 关于文件或目录的描述信息,如文件所在路径、文件名称、文件类型等等,这些信息称为文件的元数据metadata
- 命名空间
- 文件系统中,为了便于管理存储介质上的,给每个目录、目录中的文件、子目录都起了名字,这样形成的层级结构,称之为命名空间
- 同一个目录中,不能有同名的文件或目录
- 这样通过目录+文件名称的方式能够唯一的定位一个文件
edits.log的存放路径为hdfs-site.xml中属性dfs.namenode.edits.dir的值决定;
fsimage的存放路径为hdfs-site.xml中属性dfs.namenode.name.dir的值决定。
3.2 namenode的工作流程
第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,先加载Fsimage文件到内存中,然后加载Edits文件到内存中。并给Edits文件打标记,并生成一个空的edits_inprogress文件。此时NameNode内存就持有最新的元数据信息。
Client开始对NameNode发送元数据的增删改的请求,这些请求的操作首先会被记录到edits_inprogress中(查询元数据的操作不会被记录在Edits中,因为查询操作不会更改元数据信息 )
3.3 元数据信息存放在namenode的内存中还是磁盘中
内存中存有一份完整的元数据meta.data
磁盘中同样存在一份元数据镜像fsimage
edits保存内存meta.data和磁盘元数据镜像fsimage之间的操作日志
Fsimage:NameNode内存中元数据序列化后形成的文件,是HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统中所有的目录和文件inode的序列化信息。
Edits:记录客户端更新元数据信息的每一步操作 (可通过Edits运算出元数据),Edits文件,存放HDFS文件系统的所有更新操作的路径操作,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。seen_txid文件保存的是一个数字,是最后一个edits_的数字。
详细一点:
因为元数据信息需要进行随机访问,还有响应客户请求,所以元数据信息存储在内存中效率才会最大化,因此,元数据需要存放在内存中;
但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage,即持久化。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。
3.4 SecondaryNamenode工作流程
- SecondaryNameNode的作用就是帮助NameNode进行Edits和Fsimage的合并工作。
(1)namenode节点每隔一定时间或者edits.log达到指定大小(lfs.checkpoint.period 指定两次checkpoint的最大时间间隔,默认3600秒;lfs.checkpoint.size 规定edits文件的最大值,一旦超过这个值则强制checkpoint,不管是否到达最大时间间隔。默认大小是64M),请求secondaryNamenode合并操作
(2)secondaryNamenode请求namenode进行edits.log的滚动,这样新的编辑操作就能够进入新的文件edits.new中
(3)secondaryNamenode从namenode中下载fsImage和edits.log
(4)secondaryNamenode进行fsImage和edits.log的合并,成为fsImage.checkpoint文件
(5)namenode下载合并后的fsImage.checkpoin文件
(6)将fsImage.checkpoint和edits.new命名为原来的文件名(之后fsImage和日志文件edits.log重新恢复初始状态)
NN和SNN对内存的消耗几乎是一致的,因此NN和SNN分别部署在两个不同节点上。
SNN对NN属于冷备。
四、HDFS架构
HDFS也是主从架构Master|Slave或称为管理节点|工作节点
4.1 hdfs数据写流程
4.1.1详细流程
- 创建文件:
- HDFS客户端向HDFS写数据,先调用DistributedFileSystem.create()方法,在HDFS创建新的空文件
- RPC(ClientProtocol.create())远程过程调用NameNode(NameNodeRpcServer)的create(),首先在HDFS目录树指定路径添加新文件
- 然后将创建新文件的操作记录在editslog中
- NameNode.create方法执行完后,DistributedFileSystem.create()返回FSDataOutputStream,它本质是封装了一个DFSOutputStream对象
- 建立数据流管道:
- 客户端调用DFSOutputStream.write()写数据
- DFSOutputStream调用ClientProtocol.addBlock(),首先向NameNode申请一个空的数据块
- addBlock()返回LocatedBlock对象,对象包含当前数据块的所有datanode的位置信息
- 根据位置信息,建立数据流管道
- 向数据流管道pipeline中写当前块的数据:
- 客户端向流管道中写数据,先将数据写入一个检验块chunk中,大小512Byte,写满后,计算chunk的检验和checksum值(4Byte)
- 然后将chunk数据本身加上checksum,形成一个带checksum值的chunk(516Byte)
- 保存到一个更大一些的结构packet数据包中,packet为64kB大小
- packet写满后,先被写入一个dataQueue队列中0
- packet被从队列中取出,向pipeline中写入,先写入datanode1,再从datanoe1传到datanode2,再从datanode2传到datanode3中
- 一个packet数据取完后,后被放入到ackQueue中等待pipeline关于该packet的ack的反馈
- 每个packet都会有ack确认包,逆pipeline(dn3 -> dn2 -> dn1)传回输出流
- 若packet的ack是SUCCESS成功的,则从ackQueue中,将packet删除;否则,将packet从ackQueue中取出,重新放入dataQueue,重新发送
- 如果当前块写完后,文件还有其它块要写,那么再调用addBlock方法(流程同上)
- 文件最后一个block块数据写完后,会再发送一个空的packet,表示当前block写完了,然后关闭pipeline
- 所有块写完,close()关闭流
- ClientProtocol.complete()通知namenode当前文件所有块写完了
4.1.2容错
在写的过程中,pipeline中的datanode出现故障(如网络不通),输出流如何恢复
- 输出流中ackQueue缓存的所有packet会被重新加入dataQueue
- 输出流调用ClientProtocol.updateBlockForPipeline(),为block申请一个新的时间戳,namenode会记录新时间戳
- 确保故障datanode即使恢复,但由于其上的block时间戳与namenode记录的新的时间戳不一致,故障datanode上的block进而被删除
- 故障的datanode从pipeline中删除
- 输出流调用ClientProtocol.getAdditionalDatanode()通知namenode分配新的datanode到数据流pipeline中,并使用新的时间戳建立pipeline
- 新添加到pipeline中的datanode,目前还没有存储这个新的block,HDFS客户端通过DataTransferProtocol通知pipeline中的一个datanode复制这个block到新的datanode中
- pipeline重建后,输出流调用ClientProtocol.updatePipeline(),更新namenode中的元数据
- 故障恢复完毕,完成后续的写入流程
-----------------------------------------------------------------------------------------------------------------------------
1、首先client将文件缓存在本地临时文件中,当临时文件累计的大小为128M(设置的块大小)的block,然后调用客户端对象DistributedFileSystem的create方法,DistributedFileSystem跟NameNode通信请求创建一个文件。
2、NameNode收到请求后会进行各种各样的检查,确保要创建的文件不存在,并且客户端有创建文件的权限。如果检查通过,NameNode会在edits log中写入创建文件的操作。否则创建失败,客户端抛出异常。
3、DistributedFileSystem返回一个FSDataOutputStream对象给客户端用来写数据。FSDataOutputStream封装了一个DFSOoutputStream用来跟DataNode和NameNode通信。
4、FSDataOutputStream将block块切分成许多64k大小的小数据包,并将这些小数据包写入到内部队列中(数据队列中)。
5、DataStream会读取队列内容,并请求NameNode返回一个DataNode列表来存储当前的block副本。
6、列表中的DataNode会形成管线,DataStream将数据包发送给第一个DataNode,然后第一个发给第二个,第二个发给第三个。
7、DFSOoutputStream除了维护一个数据队列之外,还维护了一个确认队列(ack队列),ack队列中的数据包是管线中第一台DataNode收到数据包后会第一时间复制一份到ack队列。
8、当一个数据包在管线中所有DataNode写入完成,就从ack队列中移除该数据包,表示该数据包已经成功写入所有的管线的DataNode中。
9、如果在数据写入期间,管线中的DataNode发生故障,则执行如下操作:
a、关闭管线,将ack队列中的所有数据包都添加会数据队列的最前端,确保故障节点下游的DataNode不会丢失任何一个数据包。
b、将管线中正常的DataNode组成一个新的管线,为新管线指定一个新的标志并将该标志发送给NameNode,以便故障DataNode在恢复后可以删除存储的部分数据。
c、将数据队列中的数据包继续写入新管线中。
d、在有后续的数据包则正常处理。
10、当客户端完成数据的传输,调用数据流的close()方法。该方法将数据队列中剩余数据包写入到管线中,并等待确认。
11、客户端收到所有DataNode的确认后,通知NameNode文件写完了。
12、NameNode已经知道文件有哪些块组成,在等待数据块完成最小量复制后,返回成功。
4.2 hdfs数据读流程
4.2.1基本流程
- 1、client端读取HDFS文件,client调用文件系统对象DistributedFileSystem的open方法
- 2、返回FSDataInputStream对象(对DFSInputStream的包装)
- 3、构造DFSInputStream对象时,调用namenode的getBlockLocations方法,获得file的开始若干block(如blk1, blk2, blk3, blk4)的存储datanode(以下简称dn)列表;针对每个block的dn列表,会根据网络拓扑做排序,离client近的排在前;
- 4、调用DFSInputStream的read方法,先读取blk1的数据,与client最近的datanode建立连接,读取数据
- 5、读取完后,关闭与dn建立的流
- 6、读取下一个block,如blk2的数据(重复步骤4、5、6)
- 7、这一批block读取完后,再读取下一批block的数据(重复3、4、5、6、7)
- 8、完成文件数据读取后,调用FSDataInputStream的close方法
4.2.2容错
- 情况一:读取block过程中,client与datanode通信中断
- client与存储此block的第二个datandoe建立连接,读取数据
- 记录此有问题的datanode,不会再从它上读取数据
- 情况二:client读取block,发现block数据有问题
- client读取block数据时,同时会读取到block的校验和,若client针对读取过来的block数据,计算检验和,其值与读取过来的校验和不一样,说明block数据损坏
- client从存储此block副本的其它datanode上读取block数据(也会计算校验和)
- 同时,client会告知namenode此情况;
-----------------------------------------------------------------------------------------------------------------------------
1、首先客户端会通过自身的对象向NameNode发送通知,请求读取文件。
2、NameNode返回给客户端该文件的block副本存储在哪些DataNode上,并且这些DataNode根据他们与客户端的距离排序。
3、客户端的对象选择离自己最近的DataNode开始读取文件。
4、如果离自己最近的DataNode发生故障,则读第二近的。并记录发生故障的DataNode,下次再有要读该DataNode的时候,直接跳过。
5、读取完毕
这个设计一个重点是:namenode告知客户端每个block中最佳的datanode,并让客户端直接连到datanode检索数据。由于数据流分散在集群中的所有datanode,这样可以使HDFS可扩展到大量的并发客户端。同时,namenode只需要响应block位置的请求,无需响应数据请求,否则namenode会成为瓶颈
4.3 hdfs的HA和namenode主备切换
HA实现的两个核心要点:故障转移的实现和共享存储的实现
NameNode 主备切换主要由 ZKFailoverController(ZKFC)、HealthMonitor 和 ActiveStandbyElector 这 3 个组件来协同实现:
ZKFailoverController 作为 NameNode 机器上一个独立的进程启动 (在 hdfs 启动脚本之中的进程名为 zkfc),启动的时候会创建 HealthMonitor 和 ActiveStandbyElector 这两个主要的内部组件,ZKFC 在创建 HealthMonitor 和 ActiveStandbyElector 的同时,也会向 HealthMonitor 和 ActiveStandbyElector 注册相应的回调方法。
HealthMonitor 主要负责检测 NameNode 的健康状态,如果检测到 NameNode 的状态发生变化,会回调 ZKFC的相应方法进行自动的主备选举。
ActiveStandbyElector 主要负责完成自动的主备选举,内部封装了 Zookeeper 的处理逻辑,一旦 Zookeeper 主备选举完成,会回调 ZKFC 的相应方法来进行 NameNode 的主备状态切换。
NameNode 实现主备切换的流程如上图,有以下几步:
HealthMonitor 初始化完成之后会启动内部的线程来定时调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法,对 NameNode 的健康状态进行检测。
HealthMonitor 如果检测到 NameNode 的健康状态发生变化,会回调 ZKFC 注册的相应方法进行处理。
如果 ZKFC 判断需要进行主备切换,会首先使用 ActiveStandbyElector 来进行自动的主备选举。
ActiveStandbyElector 与 Zookeeper 进行交互完成自动的主备选举。
ActiveStandbyElector 在主备选举完成后,会回调 ZKFC 的相应方法来通知当前的 NameNode 成为主 NameNode 或备 NameNode。
ZKFC调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法将 NameNode 转换为 Active 状态或 Standby 状态。
------------------------------------------------------------------------------------------------------------------------------
- 对于HDFS ,NN存储元数据在内存中,并负责管理文件系统的命名空间和客户端对HDFS的读写请求。但是,如果只存在一个NN,一旦发生“单点故障”,会使整个系统失效。
- 虽然有个SNN,但是它并不是NN的热备份
- 因为SNN无法提供“热备份”功能,在NN故障时,无法立即切换到SNN对外提供服务,即HDFS处于停服状态。
- HDFS2.x采用了HA(High Availability高可用)架构。
- 在HA集群中,可设置两个NN,一个处于“活跃(Active)”状态,另一个处于“待命(Standby)”状态。
- 由zookeeper确保一主一备
- 处于Active状态的NN负责响应所有客户端的请求,处于Standby状态的NN作为热备份节点,保证与active的NN的元数据同步
- Active节点发生故障时,zookeeper集群会发现此情况,通知Standby节点立即切换到活跃状态对外提供服务
- 确保集群一直处于可用状态
- 如何热备份元数据:
- Standby NN是Active NN的“热备份”,因此Active NN的状态信息必须实时同步到StandbyNN。
- 可借助一个共享存储系统来实现状态同步,如NFS(NetworkFile System)、QJM(Quorum Journal Manager)或者Zookeeper。
- Active NN将更新数据写入到共享存储系统,Standby NN一直监听该系统,一旦发现有新的数据写入,就立即从公共存储系统中读取这些数据并加载到Standby NN自己内存中,从而保证元数据与Active NN状态一致。
- 块报告:
- NN保存了数据块到实际存储位置的映射信息,为了实现故障时的快速切换,必须保证StandbyNN中也包含最新的块映射信息
- 因此需要给所有DN配置Active和Standby两个NN的地址,把块的位置和心跳信息同时发送到两个NN上。
4.4 hdfs的federation(联邦)模式
4.4.1为什么需要联邦
虽然HDFS HA解决了“单点故障”问题,但HDFS在扩展性、整体性能和隔离性方面仍有问题
- 系统扩展性方面,元数据存储在NN内存中,受限于内存上限(每个文件、目录、block占用约150字节)
- 整体性能方面,吞吐量受单个NN的影响
- 隔离性方面,一个程序可能会影响其他程序的运行,如果一个程序消耗过多资源会导致其他程序无法顺利运行
- HDFS HA本质上还是单名称节点
4.4.2HDFS联邦可以解决以上三个问题
- HDFS联邦中,设计了多个命名空间;每个命名空间有一个NN或一主一备两个NN,使得HDFS的命名服务能够水平扩展
- 这些NN分别进行各自命名空间namespace和块的管理,相互独立,不需要彼此协调
- 每个DN要向集群中所有的NN注册,并周期性的向所有NN发送心跳信息和块信息,报告自己的状态
- HDFS联邦每个相互独立的NN对应一个独立的命名空间
- 每一个命名空间管理属于自己的一组块,这些属于同一命名空间的块对应一个“块池”的概念。
- 每个DN会为所有块池提供块的存储,块池中的各个块实际上是存储在不同DN中的
-------------------------------------------------------------------------------------------------------------------------------
namenode在内存中保存着文件系统中每个文件和每个数据块的引用关系,这意味着对于一个拥有大量文件的超大集群来说,内存将成为限制系统横向扩展的瓶颈。
2.x以后通过联邦模式允许系统通过添加namenode实现扩展,其中namenode管理文件系统命名空间的一部分,例如一个namenode可能管理/user目录下的所有文件,而另一个namenode可能管理/share目录下的所有文件。
该特性允许一个HDFS集群中存在多个NameNode同时对外提供服务,这些NameNode分管一部分目录(水平切分),彼此之间相互隔离,但共享底层的DataNode存储资源。
4.5 hdfs优缺点
优点:
- 适合存储大文件,能用来存储管理PB级的数据;不适合存储小文件(每个文件、目录、block占用大概150Byte字节的元数据;所以HDFS适合存储大文件,不适合存储小文件)
- 处理非结构化数据
- 流式的访问数据,一次写入、多次读写
- 运行于廉价的商用机器集群上,成本低
- 高容错:故障时能继续运行且不让用户察觉到明显的中断
- 可扩展
局限性:
- 不适合处理低延迟数据访问
- DFS是为了处理大型数据集分析任务的,主要是为达到高的数据吞吐量而设计的
- 对于低延时的访问需求,HBase是更好的选择
- 无法高效存储大量的小文件
- 小文件会给Hadoop的扩展性和性能带来严重问题
- 利用SequenceFile、MapFile等方式归档小文件
- 不支持多用户写入及任意修改文件
- 文件有一个写入者,只能执行追加操作
- 不支持多个用户对同一文件的写操作,以及在文件任意位置进行修改
4.6 心跳机制
工作原理:
- NameNode启动的时候,会开一个ipc server在那里
- DataNode启动后向NameNode注册,每隔3秒钟向NameNode发送一个“心跳heartbeat”
- 心跳返回结果带有NameNode给该DataNode的命令,如复制块数据到另一DataNode,或删除某个数据块
- 如果超过10分钟NameNode没有收到某个DataNode 的心跳,则认为该DataNode节点不可用
- DataNode周期性(6小时)的向NameNode上报当前DataNode上的块状态报告BlockReport;块状态报告包含了一个该 Datanode上所有数据块的列表
心跳的作用:
- 通过周期心跳,NameNode可以向DataNode返回指令
- 可以判断DataNode是否在线
- 通过BlockReport,NameNode能够知道各DataNode的存储情况,如磁盘利用率、块列表;跟负载均衡有关
- hadoop集群刚开始启动时,99.9%的block没有达到最小副本数(dfs.namenode.replication.min默认值为1),集群处于安全模式,涉及BlockReport;
心跳相关设置:
在配置文件hdfs-default.xml中
4.7 负载均衡
- 什么原因会有可能造成不均衡?
- 机器与机器之间磁盘利用率不平衡是HDFS集群非常容易出现的情况
- 尤其是在DataNode节点出现故障或在现有的集群上增添新的DataNode的时候
- 为什么需要均衡?
- 提升集群存储资源利用率
- 从存储与计算两方面提高集群性能
- 如何手动负载均衡?
$HADOOP_HOME/sbin/start-balancer.sh -t 5% # 磁盘利用率最高的节点若比最少的节点,大于5%,触发均衡
4.8 文件压缩
4.8.1压缩算法
- 文件压缩好处:
- 减少数据所占用的磁盘空间
- 加快数据在磁盘、网络上的IO
- 常用压缩格式
压缩格式 | UNIX工具 | 算 法 | 文件扩展名 | 可分割 | 压缩效率 | 压缩速度 |
DEFLATE | 无 | DEFLATE | .deflate | No | ||
gzip | gzip | DEFLATE | .gz | No | 中高 | 中 |
zip | zip | DEFLATE | .zip | YES | ||
bzip | bzip2 | bzip2 | .bz2 | YES | 高 | 慢 |
LZO | lzop | LZO | .lzo | Yes(if index) | 低 | 快 |
Snappy | 无 | Snappy | .snappy | No | 低 | 快 |
- Hadoop的压缩实现类;均实现CompressionCodec接口
压缩格式 | 对应的编码/解码器 |
DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
gzip | org.apache.hadoop.io.compress.GzipCodec |
bzip2 | org.apache.hadoop.io.compress.BZip2Codec |
LZO | com.hadoop.compression.lzo.LzopCodec |
Snappy | org.apache.hadoop.io.compress.SnappyCodec |
- 查看集群是否支持本地压缩(所有节点都要确认)
[hadoop@node01 ~]$ hadoop checknative
压缩比越高,压缩时间越长,压缩比:Snappy<LZ4<LZO<GZIP<BZIP2
hdfs压缩 https://blog.csdn.net/qq_38262266/article/details/79171524
4.9 小文件治理
4.9.1 HAR文件方案
本质启动mr程序,所以需要启动yarn
用法:archive -archiveName <NAME>.har -p <parent path> [-r <replication factor>]<src>* <dest>
# 创建archive文件;/testhar有两个子目录th1、th2;两个子目录中有若干文件,-r表示存档后设置3副本
hadoop archive -archiveName test.har -p /testhar -r 3 th1 th2 /outhar # 原文件还存在,需手动删除
# 查看archive文件
hdfs dfs -ls -R har:///outhar/test.har
# 解压archive文件
# 方式一
hdfs dfs -cp har:///outhar/test.har/th1 hdfs:/unarchivef # 顺序
hadoop fs -ls /unarchivef
# 方式二
hadoop distcp har:///outhar/test.har/th1 hdfs:/unarchivef2 # 并行,启动MR
创建存档文件的问题:
1、存档文件的源文件目录以及源文件都不会自动删除需要手动删除
2、存档的过程实际是一个mapreduce过程,所以需要hadoop的mapreduce的支持
3、存档文件本身不支持压缩
4、存档文件一旦创建便不可修改,要想从中删除或者增加文件,必须重新建立存档文件
5、创建存档文件会创建原始文件的副本,所以至少需要有与存档文件容量相同的磁盘空间
4.9.2 Sequence Files方案
- SequenceFile文件,主要由一条条record记录组成;每个record是键值对形式的
- SequenceFile文件可以作为小文件的存储容器;
- 每条record保存一个小文件的内容
- 小文件名作为当前record的键;
- 小文件的内容作为当前record的值;
- 如10000个100KB的小文件,可以编写程序将这些文件放到一个SequenceFile文件。
- 一个SequenceFile是可分割的,所以MapReduce可将文件切分成块,每一块独立操作。
- 具体结构(如下图):
- 一个SequenceFile首先有一个4字节的header(文件版本号)
- 接着是若干record记录
- 记录间会随机的插入一些同步点sync marker,用于方便定位到记录边界
- 不像HAR,SequenceFile支持压缩。记录的结构取决于是否启动压缩
- 支持两类压缩:
- 不压缩NONE,如下图
- 压缩RECORD,如下图
- 压缩BLOCK,①一次性压缩多条记录;②每一个新块Block开始处都需要插入同步点;如下图
- 在大多数情况下,以block(注意:指的是SequenceFile中的block)为单位进行压缩是最好的选择
- 因为一个block包含多条记录,利用record间的相似性进行压缩,压缩效率更高
- 把已有的数据转存为SequenceFile比较慢。比起先写小文件,再将小文件写入SequenceFile,一个更好的选择是直接将数据写入一个SequenceFile文件,省去小文件作为中间媒介.
创建sequence file的过程可以使用mapreduce工作方式完成
对于index,需要改进查找算法
对小文件的存取都比较自由,也不限制用户和文件的多少,但是该方法不能使用append方法,所以适合一次性写入大量小文件的场景
小文件治理:https://www.aboutyun.com/thread-14227-1-1.html
4.10 文件快照
4.10.1 什么是快照
- 快照比较常见的应用场景是数据备份,以防一些用户错误或灾难恢复
- 快照snapshots是HDFS文件系统的,只读的、某时间点的拷贝
- 可以针对某个目录,或者整个文件系统做快照
- 创建快照时,block块并不会被拷贝。快照文件中只是记录了block列表和文件大小,不会做任何数据拷贝
4.10.2 快照操作
允许快照
允许一个快照目录被创建。如果这个操作成功完成,这个目录就变成snapshottable
用法:hdfs dfsadmin -allowSnapshot <snapshotDir>
hdfs dfsadmin -allowSnapshot /wordcount
禁用快照
用法:hdfs dfsadmin -disallowSnapshot <snapshotDir>
hdfs dfsadmin -disallowSnapshot /wordcount
创建快照
用法:hdfs dfs -createSnapshot <snapshotDir> [<snapshotName>]
#注意:先将/wordcount目录变成允许快照的
hdfs dfs -createSnapshot /wordcount wcSnapshot
查看快照
hdfs dfs -ls /wordcount/.snapshot
重命名快照
这个操作需要拥有snapshottabl目录所有者权限
用法:hdfs dfs -renameSnapshot <snapshotDir> <oldName> <newName>
hdfs dfs -renameSnapshot /wordcount wcSnapshot newWCSnapshot
用快照恢复误删除数据
HFDS的/wordcount目录,文件列表如下
误删除/wordcount/edit.xml文件
hadoop fs -rm /wordcount/edit.xml
恢复数据
hadoop fs -cp /wordcount/.snapshot/newWCSnapshot/edit.xml /wordcount
删除快照
这个操作需要拥有snapshottabl目录所有者权限
用法:hdfs dfs -deleteSnapshot <snapshotDir> <snapshotName>
hdfs dfs -deleteSnapshot /wordcount newWCSnapshot
五、hdfs shell
5.1 hdfs与getconf结合使用
5.1.1 获取NameNode的节点名称(可能有多个)
hdfs getconf -namenodes
5.1.2 获取hdfs最小块信息
hdfs getconf -confKey dfs.namenode.fs-limits.min-block-size
5.1.3 查找hdfs的NameNode的RPC地址
hdfs getconf -nnRpcAddresses