Hadoop HDFS详解和常用指令
HDFS:
- 是Hadoop中用于数据的分布式存储的组件
- 根据Google论文《The Google File System》来设计的
常用指令
指令 | 说明 |
---|---|
hadoop fs -put | 向HDFS上传文件 |
hadoop fs -mkdir | 在HDFS上创建了目录(实际上只是一个路径标记) |
hadoop fs -get | 下载 |
hadoop fs -rm | 删除文件 |
hadoop fs -rmdir | 删除目录 |
hadoop fs -rmr | 递归删除 |
hadoop fs -ls | 查看指定路径下的子文件和子目录 |
hadoop fs -lsr | 递归查看 |
hadoop fs -cat | 查看指定文件中的内容 |
hadoop fs -tail | 查看指定文件的最后1000个字节的内容 |
hadoop fs -mv | 剪切文件 |
hadoop fs -cp | 复制文件 |
hadoop fs -touchz | 创建一个空文件 |
hadoop fsck /test/txt/a.txt -files -blocks -locations -racks |
一、基本结构
- 在HDFS中,对于文件是进行切块保存
- HDFS中有2类主要的节点:NameNode和DataNode
- NameNode负责管理DataNode
- DataNode负责存储数据
- HDFS会对文件块进行自动的备份,每一个备份称之为复本(Replication),HDFS默认是3个复本
- 如果某一个DataNode宕机,那么在HDFS中默认将这个DataNode所存储的复本再进行一次备份,保证指定的复本数量
二、Block
- 在HDFS中,会对文件进行切块,每一个块实际上就是一个Block
- Block是HDFS中存储的基本单位
- Block在Hadoop1.0中的大小是64M,在Hadoop2.0中的大小是128M
- 如果一个文件或者数据的大小不满足Block的大小,那么这个文件或者数据是多大那么对应的Block就是多大
- 切块的意义:
a. 便于存储超大文件
b. 便于进行快速的备份 - HDFS对每一个Block分配一个递增的编号
三、NameNode
- NameNode是HDFS中的核心节点,用于管理其他的DataNode
- NameNode本身会记录元数据(Meta Data)
- 元数据包含:
a. 文件的存储路径,例如/a.log,/test/b.txt
b. 复本数量
c. 文件所对应的文件块 — Block
d. 每一个Block的存储节点 - 每一条元数据一般是在150B大小左右
- 只有写请求会产生元数据,读请求不产生元数据
- 元数据在NameNode中存储在内存以及磁盘中
- 元数据存储在内存中的目的是为了快速查询
- 元数据存储在磁盘中是为了崩溃恢复
- 元数据存储在磁盘上的位置由core-site.xml中的属性hadoop.tmp.dir来决定,在指定的目录的子目录dfs/name/current下
- 元数据存储的文件:
a. edits:记录NameNode接收的每一次的写(上传、删除、追加)请求
b. fsimage:记录元数据,但是这个文件中的元数据不是实时的 - 当NameNode接收到一个新的写请求的时候,会先将这个请求写到edits文件中,当edits文件写成功之后,再去更改内存中的元数据,当内存中的元数据更改完毕之后,会个客户端返回一个成功信号
- edits和fsimage在触发合并条件的时候会进行合并:
a. 时间:由(core-site.xml)fs.checkpoint.period属性决定,默认数量是3600,默认时间单位是秒
b. 空间:由(core-site.xml)fs.checkpoint.size属性决定,默认是64M,表示当edits文件到达64M的时候会将其中的操作更新到fsimage中
c. 重启:NameNode重新启动的时候,自动触发edits和fsiamge的合并
d. 强制:指令 hadoop dfsadmin -rollEdits - 内存中元数据 = edits中的操作+fsimage中的元数据
- 在Hadoop1.0中,NameNode有且只有一个,也就意味着NameNode存在单点故障
- 在Hadoop2.0的伪分布式中,NameNode也只有一个;但是在Hadoop2.0的完全分布式中,可以通过舍弃SecondaryNameNode的方式来搭建2个NameNode避免NameNode的单点故障
- 在完全分布式中,如果存在NameNode和SecondaryNameNode,那么合并过程是发生在SecondaryNameNode上;如果舍弃了SecondaryNameNode,合并过程只能发生在NameNode上
- DataNode通过心跳机制(每隔固定时间)来给NameNode发送心跳信号
- 心跳信号包含:
a. 当前节点的状态
b. 当前DataNode存储的数据 - 在HDFS启动/重启的时候,自动的触发edits和fsimage的合并,合并完成之后,会将fsimage中的元数据加载到内存中,然后会进行一系列的校验(等待DataNode的心跳,校验数据的完整性),在这个过程中,HDFS不对外提供写服务只提供读服务,这种情况称之为安全模式
- HDFS当完成所有的校验之后会自动退出安全模式
- 如果在伪分布式下,设置的复本数量>1,那么就会无法退出安全模式
四、DataNode
- DataNode用于存储数据,数据是以Block形式存储
- DataNode通过心跳机制(RPC)来向NameNode发送心跳信号
- DataNode每隔3s向NameNode发送一次心跳
- 如果NameNode超过10min没有收到DataNode的心跳,那么NameNode认为这个DataNode已经lost(丢失)
- 当NameNode认为DataNode已经lost的时候,NameNode要将这个DataNode上的Block备份到其他的节点上
五、SecondaryNameNode
- SecondaryNameNode不是NameNode热备,只是辅助NameNode进行元数据的合并,SecondaryNameNode也能起到一定的备份作用
- 合并过程
- SecondaryNameNode设计的目的是为了提高HDFS的运行效率,但是实际开发过程中往往会舍弃SecondaryNameNode,而是采用双NameNode机制来实现NameNode的热备
六、多复本放置策略
- 第一个复本:如果是从集群内部上传,哪个节点上传第一个复本就放在哪个节点上;如果是从集群外部上传,那么NameNode会选择一个相对比较空闲的DataNode存储第一个复本
- 第二个复本:放在和第一个复本不同机架的节点上
- 第三个复本:放在和第二个复本相同机架的节点上
- 更多复本:选择相对空闲的节点来放置
七、机架感知策略
- 机架感知策略本质上是建立节点和机架的映射关系
- 机架指的不是物理机架而是逻辑机架
- 可以将不同物理机架上的节点映射到同一个逻辑机架上
- 一般是将同一个物理机架上的节点放到同一个逻辑机架上
dfs目录
- 用于存储HDFS中的数据的目录
- dfs目录在格式化的时候产生
- dfs下包含:data/name/namesecondary在完全分布式下应该是在不同的节点中
- 当HDFS第一次启动的时候,edits和fsimage在启动一分钟之后自动合并一次;后续就是按照指定时间间隔进行合并
- HDFS会对每一次的操作分配一个事务id – txid
a. edits_X-Y:X表示edits文件开始记录的事务id,Y表示结束记录的事务id
b. fsimage_X:对应的是edits中的起始id - 查看edits文件:hdfs oev -i edits_XXX -o XXX.xml
- 上传文件:
a. OP_ADD:先在HDFS上创建一个同名文件.COPYING
b. OP_ALLOCATE_BLOCK_ID:表示分配Blockid
c. OP_SET_GENSTAMP_V2:表示分配给当前时间戳一个编号
d. OP_ADD_BLOCK:利用流将数据写入到对应的Block上
e. OP_CLOSE:关闭文件
f. OP_RENAME_OLD:重命名 - 文件关闭之后不允许再次写入
- 查看fsimage文件:hdfs oiv -i fsimage_XXX -o XXXX.xml -p XML
- edits_X-Y表示已经合并过的文件;新的操作是写到edits_inprogress_X中
- fsimage_X.md5用于进行对fsimage_X的校验
- seen_txid记录最新的事务id
- NameNode每格式化一次,都会自动计算出一个clusterID,记录在VERSION文件中。NameNode会把自己的clusterID分发给每一个它管理的DataNode上,利用这个clusterID作为标记,确定NameNode所要管理的这些DataNode
- in_use.lock表示当前节点的NameNode/DataNode已经启动,不需要再二次启动
执行流程
一、读取流程
- 客户端发起RPC请求到NameNode
- NameNode收到请求之后,查询元数据,获取到文件所对应的切块地址;将地址放入一个队列中,然后将全部或者部分地址返回给客户端
- 客户端收到队列之后,从队列中将第一个Block的地址取出
- 客户端从地址中选取一个较近的节点来读取数据
- 读取完Block之后,会对读取完的数据进行一次checkSum的校验:如果校验成功,那么接着获取下一个Block的地址,选取节点进行读取;如果校验失败,客户端先发送信号给NameNode,得从当前Block所存储的其他节点中重新读取
- 读完这一批的Block之后,客户端会给NameNode发送信号获取下一批的Block的地址
- 当客户端读取完所有的Block之后,客户端会NameNode发送信号,NameNode会将文件关闭(关流)
二、写入流程
- 客户端发起RPC请求到NameNode
- NameNode收到请求之后,会请求进行校验:
a. 校验这个发起这个请求的用户是否有权限操作
b. 校验要上传的路径中是否有同名的文件 - 如果校验成功,则将该操作更新到edits中并且更新内存中的元数据 - 计算文件的大小,计算切块的数量,给每一个Block分配存储的节点
- NameNode将存储节点放入一个队列中返回给客户端
- 客户端在收到队列之后,从中取出第一个节点位置,然后将第一个文件块封装成Packets对象写到对应的节点上
- 当客户端写完第一个复本之后,当前DataNode会自动通过pipeline(管道,底层是基于Channel)将这个复本备份到其他的DataNode上
- 当将3个复本都写完之后,会客户端发送ack信号表示写入成功
- 客户端收到ack之后,就会继续写第二个Block
- 客户端在写完全部的Block之后,通知NameNode将文件关闭。文件关闭之后就不能改动
三、删除流程
- 客户端发起RPC请求到NameNode
- NameNode接收到请求之后,将操作记录到edits文件中,然后更新内存
- NameNode就会返回一个成功信号给客户端,表示文件删除成功;注意,此时文件并没有从HDFS上真正移除
- NameNode等待DataNode的下一次心跳,NameNode会对DataNode所发送的心跳信息进项校验
- NameNode发现DataNode中依然存储着之前的数据,NameNode就会给DataNode发送信号要求删除对应的数据
- DataNode收到NameNode的信号之后,才会真正删除这个文件所对应的数据块
特点
- 优点:
a. 支持存储超大文件 - 切块
b. 快速应对和检测节点故障 - 心跳机制
c. 流式数据访问,提高吞吐量
d. 高容错性 - 多复本
e. 便于进行横向扩展,并且横向扩展的成本较低 - 缺点:
a. 不建议存储大量的小文件
b. 不支持低延迟访问 - 简化的一致性模型:支持一次写入多次读取,但是不支持修改。从Hadoop2.0开始,支持追加写入,但是写完的数据依然不能更改
- 不支持事务