Hadoop——角色功能

  1. 不论集群有多少台机器,Namenode只有一台,由于要记录所有datanode上的文件元数据、目录结构等信息,且当client并发很高时,Namenode压力其实很大,所以Namenode必须响应很快,所有Namenode完全基于内存存储metadata、目录结构、block映射等信息
  2. 但是也正是因为其完全基于内存,所以受内存大小,机器断电丢失数据等客观因素限制,Namenode需要持久化方案保证数据可靠性 (下文具体阐述)
  3. Namenode提供副本放置策略 (下文具体阐述)
  4. Datanode基于当前操作系统的本地磁盘以文件形式存储block (所以由此可见,HDFS存数据,最终还是将数据存到了磁盘上,HDFS实际本质上就是管理block的存储位置映射)
  5. 除了block块本身,还会存每个block块的校验和(类似于MD5字符串的一个东西),以便未来client取走block时做校验,若校验成功,则代表block块没有被破坏,client将block块取走并还能拼回源文件,这保证了数据的可靠性
  6. 与Namenode保持心跳,汇报block列表状态

现如今解决数据持久化有两种方案:

  • 日志文件:记录实时发生的操作。完整性好但是占空间,且因文件大记录操作多的原因,恢复比较慢
  • 镜像(或快照,dump):内存全量数据在某一时间点向磁盘的溢写,一般隔一段时间做一次。优点恢复速度快,但因为有时间间隔,所以必然会丢失一部分数据(要注意不能设置太短的时间间隔,因为溢写涉及到IO,IO速度很慢)

HDFS结合以上两种方案:在HDFS中,日志文件叫做Editlog,镜像叫做FsImage。如果能做到日志体积小,记录少,就凸显了日志的优势;如果能做到间隔时间短,就凸显了镜像的优势。于是HDFS给出的Namenode持久化方案就是:最近时间的FsImage+增量的Editlog
比如现在10点Namenode关机,假如有一个9点的FsImage和一个9点到10点的Editlog,接下来重启Namenode后,先加载FsImage,再加载Editlog,就可以得到断电前的全量数据了。那么问题是:怎么做到恰好会有一个最近时间的FsImage和小体量的Editlog呢?
答案是:滚动地将Editlog更新到FsImage中,以保证最近时间的FsImage和小体量的Editlog。 那么问题是:怎么滚动更新FsImage呢?
有两种方法:

  • 直接设置较短时间间隔的FsImage
  • 假设现在8点Namenode刚开机,就做一次FsImage,到9点时,将8点到9点的Editlog更新到FsImage中,这样之前8点的FsImage就变成了9点的FsImage (这过程由SecondaryNamenode,也就是另一个机器,另一个进程完成)

Namenode每次启动时还会做一件事情,以刚搭载好Hadoop集群第一次启动为例。

  1. Hadoop集群刚搭载好会涉及到格式化过程,格式化操作会产生一个空的FsImage
  2. 当Namenode启动时,它从硬盘中读取Editlog和FsImage
  3. 将所有Editlog中的事务作用在内存中的FsImage上
  4. 并将这个新版本的FsImage从内存中保存到本地磁盘上
  5. 然后删除旧的Editlog,因为这个旧的Editlog的事务都已经作用在FsImage上了

同时Namenode在每次启动时,都会先进入一个称为安全模式的状态。
由于Namenode持久化只会持久化文件的metadata,而文件具体每个块的location信息是跟着文件数据存在各Datanode中的,所以Namenode刚启动时会丢失文件所有块的位置信息,也就无法满足client的关于block的请求。所以Namenode每次启动后,会先跟所有Datanode建立心跳,等Datanode汇报块的状态。每当Namenode检测确认某个block的副本数目达到某个最小值之后,那么该block就会被认为是副本安全的(safely replicated)。在一定百分比的block被Namenode检测确认是副本安全之后(加上一个额外的30秒等待时间),Namenode才会退出安全模式。接下来Namenode还会确认哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他Datanode上。

在非Ha(High Available 高可用)模式下,SecondaryNamenode一般是独立节点,SecondaryNamenode不与client产生任何交互,SNN的唯一工作就是将Editlog更新到FsImage中。在core-site.xml文件中有两个参数与这有关:fs.checkpoint.period表示多长时间记录一次FsImage,默认3600秒,fs.checkpoint.size表示一次记录多大的Editlog,也就是Editlog文件的最大值,默认64MB。若FsImage没有间隔1小时,但Editlog超过64MB了,也会触发更新。Hadoop——角色功能

最后谈一下副本的放置策略:假定当前block副本至少有3个

  1. 第一个副本:放置在上传文件的Datanode服务器,如果该服务器在集群外,则随机挑选集群内的一个磁盘不太满,CPU不太忙的节点
  2. 第二个副本:放置在与第一个副本不同的机架的节点上 (若放置在同一机架,若当前机架断电或者出现其他故障,则两个副本都会找不到)
  3. 第三个副本:放置在与第二个副本相同的机架的其他节点上 (之所以不再另选其他机架的原因是为了节约成本,跨机架通信是需要时间和其他操作的)
  4. 更多副本:随机节点
    注意在Hadoop1.x版本时,第一个副本和第二个副本放在同一机架,这就会造成上述所述问题,所以官方在Hadoop2.x版本时修正为上述设置
    Hadoop——角色功能