hdfs简介
hdfs是hadoop中分布式的文件存储系统;具有高容错、可扩展;广泛的用于大数据项目中(不仅仅是hadoop)
优点
- 容错性高
- 数据自动保存多个副本(可设置)
- 副本丢失后,自动恢复
- 适合批处理
- 移动计算而非移动数据
- 数据位置暴露给计算框架
- 适合大数据处理
- GB、TB、甚至PB级数据
- 百万规模以上的文件数量
- 10K+节点
- 可以搭建在廉价的服务器上
- 通过副本提高可靠性
- 提高了容错和恢复机制
缺点
- 无法做到低延迟数据访问(比如毫秒级别的)
- 不适合处理小文件
- 占用namenode大量内存
- 寻道时间会比较长(可能占整个读时间的80-90%)
- 并发写入、文件随机修改
-一个文件只能有一个写者- 不支持文件的修改(2.X版本中增加了append功能,不过在生产环境中,绝对不会开启该功能,代价太大)
hdfs架构
这个是1.x版本的架构图
NameNode
namenode主要功能是接受客户端的读写请求,和管理metadata信息;
- NameNode保存metadata信息包括
- 文件权限(permissions)
- 文件包含哪些块
- Block保存在哪个DataNode(DataNode启动时上报)
- NameNode的metadata信息会在启动后加载到内存中
- metadata持久化后的文件名为 fsimage
- block的位置信息不回保存到fsimage(由DataNode上报)
- edits记录的是对metadata的操作日志
- NameNode启动时,会将fsimage文件加载到内存中,并将edits文件执行一遍。这样内存中的文件就是最新的了。(注意:此时会将内存中的信息持久化到fsimage文件中)
Secondary NameNode
首先需要明白一点,Secondary NameNode不是NameNode的副本(可以充当副本的作用);
主要作用是帮助Namenode合并fsimage、edits文件;在NameNode介绍中,提到NameNode启动时会将fsimage加载到内存中,并将edits文件执行一遍。这里会有个问题,如果系统运行的时间很长,那edits文件会非常巨大,那NameNode启动的时间就会非常长(简称安全模式,后面会说到)。
因此就出现了Secondary NameNode;工作原理如下:
- Secondary NameNode会将NameNode上的edits和fsimage文件通过http get的方式拉取过来,NameNode会生成edits.new文件记录接下来的操作
- SNN会将fsimage文件加载到内存中,并执行edits文件生成fsimage.ckpt文件
- SNN用http post方式将生成的fsimage.ckpt文件发送个NameNode文件
- NN会将fsimage文件更名为fsimage,edits.new更名为 edits
如何会触发这个合并操作?
有两个指标,一个是edits文件的大小,一个是时间
- dfs.namenode.checkpoint.period 默认是一个小时
- dfs.namenode.checkpoint.txns 默认是1 million,没有合并的transactions的次数
如果在这个过程中NN节点挂掉了,会不会造成数据丢失呢?
如果只是断电,服务器没有损坏,数据是不会丢失的,edits.new会持久化到磁盘中;如果服务器彻底坏了,那edits.new中的数据就会丢失。
这里有个问题需要注意下:NameNode中edits文件是实时更新的,相当于日志文件,而fsimage不是实时更新的,合并操作完之后,才会持久化到硬盘中。 也就是说只有两个时机才回持久化fsimage文件,一是启动hdfs时,NameNode在安全模式下合并fsimage文件,二是Secondary NameNode合并之后,post给NameNode时。
DataNode
- 存储数据(block)
- 启动DN线程的时候向NN汇报block信息
- 通过向NN发送心跳保持联系(3秒一次),如果NN10分钟没有收到DN的心跳,则认为DN已经lost,并copy其上的block到其他的DN节点
高容错性
这里单独讲一下,hdfs高容错性是如何实现的;后面很多知识都是和它相关的。高容错体现在hdfs会对数据有个备份,hdfs默认是>=3个副本数。
如果需要修改副本数,可以修改dfs.replication参数
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
hdfs会对文件进行拆分,按block进行拆分,1.x中每个block默认大小是64M,2.X中每个block默认大小是128M。也就是说一个文件是由多个block块组成。这里需要注意的是:block是一个逻辑的概念,一个129M的文件,会占用两个block(假设block是128M),但是这个文件占用的空间还是129M,不会占用256M的空间。
block放置的策略是:
- 首先会选择一台负载较轻,网络比较好的机器放置第一个副本
- 第二副本会放在和第一台不同的机架上
- 第三个副本一般来说会和第二个在同一个机架,不同服务器上。能减少网络的IO
- 后面的副本随机放置。
这个放置策略可以很好避免数据丢失的情况,如果某个节点挂了,hdfs会对该节点的上block都复制一份。如果该节点恢复了,hdfs不会对复制过block进行删除操作。
安全模式
安全模式是hdfs启动时,进行一些初始化的工作;这段时间;安全模式期间NN处于一个read-only状态,无法进行任何更新操作。
安全模式主要做的事是NN将fsimage文件加载内存,将edits文件执行一遍,进行合并,生成新的fsimage文件,并将其持久化到硬盘中;NN只有在启动的时候才会去合并fsimage和edits文件。NN还会等待DN上报它的block信息;当hdfs中的大部分block都是可用的时候;hdfs会自动退出安全模式;可以显示指定 dfsadmin -safemode进入安全模式。
恢复模式
如果metadata数据只有一份,并且已经损坏了;我们可以用Recovery mode启动NN,这可以恢复大部分数据。
命令是
namenode -recover
这里会有很多步,每步都会有一些选项;可以加上 -force参数;这样每次都会选择第一个。
注意:Recovery mode 可能会造成数据的丢失;所以建议进入Recovery模式之前,先备份fsimage和edits文件。
写流程
- 首先创建FileSystem,和hdfs打交道,基本上都是通过FileSystem;FileSystem调用create接口向NameNode发送请求,NameNode会进行权限的检查,以及文件目录是否已经存在,父目录是否存在等检查。
- 第一步NameNode会返回是否可以上传
- client先对文件进行切分,如果block是128M,200M的文件会切分成128和72M的两个block块。client会首先请求NameNode第一个block块应该存放到那个DataNode上。NameNode会返回一些DataNode
- client会选择一个负载较轻,网络较好的DataNode上传数据,RPC调用,会建立pipeline进行传输,第一个DataNode接收请求,会调用第二个DataNode,然后第二个调用第三个DataNode,这样整个pipeline就建立好了。然后写入数据(以packet为单位,每个packet为64kb)
- 第一台DataNode收到一个packet之后,就会发送给第二台DataNode,第二台发给第三台。然后第三台应答,报告收据接收完成。重复第五步直到block写入完成
- 然后client写另外的block(必须在之前的block写入完成之后,才能写下一个block,而且必须是按顺序的)
- 写入完成之后,告诉NameNode写入完毕,然后NameNode更新元数据信息
读流程
- 第一步还是通过FileSystem和NameNode进行交互。通过open方法(也会有文件是否存在的,是否有权限的一些验证),得到文件block的位置信息(在哪些DataNode节点上)
- client通过FSDataInputStream进行读取。
- client选择合适一台DataNode进行读取block。
- 上一个block读取完之后,再读下一个block(一定是上一个读取完了之后,才会读下一个,而且必须是按顺序来的),直到所有的block读取完毕