namenode存储的数据:

主控服务器主要有三类数据:文件系统的目录结构数据,各个文件的分块信息,数据块的位置信息(就数据块放置在哪些数据服务器上...)。在GFS和HDFS的架构中,只有文件的目录结构和分块信息才会被持久化到本地磁盘上,而数据块的位置信息则是通过动态汇总过来的,仅仅存活在内存数据结构中,机器挂了,就灰飞烟灭了。每一个数据服务器启动后,都会向主控服务器发送注册消息,将其上数据块的状况都告知于主控服务器。俗话说,简单就是美,根据DRY原则,保存的冗余信息越少,出现不一致的可能性越低,付出一点点时间的代价,换取了一大把逻辑上的简单性,绝对应该是一个包赚不赔的买卖。。。

Hdfs支持的写操作

在HDFS中仅仅支持追加写,这大大降低了复杂性.

数据读写操作

有的操作本质上还是涉及到了数据服务器,比如文件创建和删除操作。但是,之前提到,主控服务器只于数据服务器是一个等待拉取的地位,它们不会主动联系数据服务器,将指令传输给它们,而是放到相应的数据结构中,等待数据服务器来取。这样的设计,可以减少通信的次数,加快操作的执行速度。。。

在Hadoop中,读写操作是不走RPC机制的,而是另立门户,独立搭了一套通信框架。在数据服务器一端,DataNode类中有一个DataXceiverServer类的实例,它在一个单独的线程等待请求,一旦接到,就启动一个DataXceiver的线程,处理此次请求。一个请求一个线程,对于数据服务器来说,逻辑上很简单。

读操作

文件的读取实在是一个简单的过程。在客户端DFSClient中,有一个

DFSClient.DFSInputStream类。当需要读取一个文件的时候,会生成一个DFSInputStream的实例。它会先调用ClientProtocol定义getBlockLocations接口,提供给NameNode文件路径读取位置读取长度信息,从中取得一个LocatedBlocks类的对象,这个对象包含一组LocatedBlock,那里面有所规定位置中包含的所有数据块信息,以及数据块对应的所有数据服务器的位置信息。当读取开始后,DFSInputStream会先尝试从某个数据块对应的一组数据服务器中选出一个,进行连接。这个选取算法,在当下的实现中,非常简单,就是选出第一个未挂的数据服务器,并没有加入客户端与数据服务器相对位置的考量。读取的请求,发送到数据服务器后,自然会有DataXceiver来处理,数据被一个包一个包发送回客户端,等到整个数据块的数据都被读取完了,就会断开此链接,尝试连接下一个数据块对应的数据服务器,整个流程,依次如此反复,直到所有想读的都读取完了为止。。。

写入的时序控制

在HDFS中,并发写入的次序控制,是由主控服务器来把握的。当创建、续写一个文件的时候,该文件的节点类,由INodeFile升级成为INodeFileUnderConstruction,INodeFileUnderConstruction是INodeFile的子类,它起到一个锁的作用。如果当一个客户端想创建或续写的文件是INodeFileUnderConstruction,会引发异常,因为这说明这个此处有爷,请另寻高就,从而保持了并发写入的次序性。同时,INodeFileUnderConstruction有包含了此时正在操作它的客户端的信息以及最后一个数据块的数据服务器信息,当追加写的时候可以更快速的响应。。。

文件写入的流水线
文件写入,就是在这一组数据服务器上构造成数据流的双向流水线。DFSOutputStream,会与序列的第一个数据服务器建立Socket连接,发送请求头,然后等待回应。DataNode同样是建立DataXceiver来处理写消息,DataXceiver会依照包中传过来的其他服务器的信息,建立与下一个服务器的连接,并生成类似的头,发送给它,并等待回包。此流程依次延续,直到最后一级,它发送回包,反向着逐级传递,再次回到客户端。如果一切顺利,那么此时,流水线建立成功,开始正式发送数据。数据是分成一个个数据包发送的,所有写入的内容,被缓存在客户端,当写满64K,会被封装成DFSOutputStream.Packet类实例,放入DFSOutputStream的dataQueue队列。DFSOutputStream.DataStreamer会时刻监听这个队列,一旦不为空,则开始发送,将位于dataQueue队首的包移动到ackQueue队列的队尾,表示已发送但尚未接受回复的包队列。同时启动ResponseProcessor线程监听回包,直到收到相应回包,才将发送包从ackQueue中移除,表示成功。每一个数据服务器的DataXceiver收到了数据包,一边写入到本地文件中去,一边转发给下一级的数据服务器,等待回包,同前面建立流水线的流程。。。

客户端错误回复

作为客户端,大部分时候,牺牲了就牺牲了,没人哀悼,无人同情,只有在在辛勤写入的时候,不幸辞世(机器挂了,或者网络断了,诸如此类...),才会引起些恐慌。因为,此时此刻,在主控服务器上对应的文件,正作为INodeFileUnderConstruction活着,仅仅为占有它的那个客户端服务者,做为一个专一的文件,它不允许别的客户端染指。这样的话,一旦占有它的客户端服务者牺牲了,此客户端会依然占着茅坑不拉屎,让如花似玉INodeFileUnderConstruction孤孤单单守寡终身。这种事情当然无法容忍,因此,必须有办法解决这个问题,办法就是:租约。。。、、

租约,顾名思义,就是当客户端需要占用某文件的时候,与主控服务器签订的一个短期合同。这个合同有一个期限,在这个期限内,客户端可以延长合同期限,一旦超过期限,主控服务器会强行终止此租约,将这个文件的享用权,分配给他人。。。
在打开或创建一个文件,准备追加写之前,会调用LeaseManageraddLease方法,在指定的路径下与此客户端签订一份租约。客户端会启动DFSClient.LeaseChecker线程,定时轮询调用ClientProtocolrenewLease方法,续签租约。在主控服务器一端,有一个LeaseManager.Monitor线程,始终在轮询检查所有租约,查看是否有到期未续的租约。如果一切正常,该客户端完成写操作,会关闭文件,停止租约,一旦有所意外,比如文件被删除了,客户端牺牲了,主控服务器都会剥夺此租约,如此,来避免由于客户端停机带来的资源被长期霸占的问题。。。
datanode心跳机制
为了整个系统的稳定,数据服务器必须时刻向主控服务器汇报,保持主控服务器对其的完全了解,这个机制,就是心跳消息。在HDFS中,主控服务器NameNode实现了DatanodeProtocol接口,数据服务器DataNode会在主循环中,不停的调用该协议中的sendHeartbeat方法,向NameNode汇报状况。在此调用中,DataNode会将其整体运行状况告知NameNode,比如:有多少可用空间、用了多大的空间,等等之类。NameNode会记住此DataNode的运行状况,作为新的数据块分配或是负载均衡的依据。当NameNode处理完成此消息后,会将相关的指令封装成一个DatanodeCommand对象,交还给DataNode,告诉数据服务器什么数据块要删除什么数据块要新增等等之类,数据服务器以此为自己的行动依据。。。

但是,sendHeartbeat并没有提供本地的数据块信息给NameNode,那么主控服务器就无法知道此数据服务器应该分配什么数据块应该删除什么数据块,那么它是如何决定的呢?答案就是DatanodeProtocol定义的另一个方法,blockReport。DataNode也是在主循环中定时调用此方法,只是,其周期通常比调用sendHeartbeat的更长。它会提交本地的所有数据块状况给NameNode,NameNode会和本地保存的数据块信息比较,决定什么该删除什么该新增,并将相关结果缓存在本地对应的数据结构中,等待此服务器再发送sendHeartbeat消息过来的时候,依照这些数据结构中的内容,做出相应的DatanodeCommand指令。
 
namenode容灾
在HDFS中,运行着一个SecondaryNameNode服务器,它做为主控服务器的替补,隐忍厚积薄发为篡位做好准备,其中,核心内容就是:定期下载并处理日志和镜像。SecondaryNameNode看上去像客户端一样,与NameNode之间,走着NamenodeProtocol协议。它会不停的查看主控服务器上面累计日志的大小,当达到阈值后,调用doCheckpoint函数,此函数的主要步骤包括:

  • 首先是调用startCheckpoint做一些本地的初始化工作;
  • 然后调用rollEditLog,将NameNode上此时操作的日志文件从edit切到edit.new上来,这个操作瞬间完成,上层写日志的函数完全感觉不到差别;
  • 接着,调用downloadCheckpointFiles,将主控服务器上的镜像文件和日志文件都下载到此候补主控服务器上来;
  • 并调用doMerge,打开镜像和日志,将日志生成新的镜像,保存覆盖;
  • 下一步,调用putFSImage把新的镜像上传回NameNode;
  • 再调用rollFsImage,将镜像换成新的,在日志从edit.new改名为edit;
  • 最后,调用endCheckpoint做收尾工作。
整个算法涉及到NameNode和SecondaryNameNode两个服务器,最终结果是NameNode和SecondaryNameNode都依照算法进行前的日志生成了镜像。而两个服务器上日志文件的内容,前者是整个算法进行期间所写的日志,后者始终不会有任何日志。当主控服务器牺牲的时候,运行SecondaryNameNode的服务器立刻被扶正,在其上启动主控服务,利用其日志和镜像,恢复文件目录,并逐步接受各数据服务器的注册,最终向外提供稳定的文件服务。。。
 
 
 

数据的正确性保证(不太理解,后续再拜读)

在复杂纷繁的分布式环境中,我们坚定的相信,万事皆有可能。哪怕各个服务器都舒舒服服的活着,也可能有各种各样的情况导致网络传输中的数据丢失或者错误。并且在分布式文件系统中,同一份文件的数据,是存在大量冗余备份的,系统必须要维护所有的数据块内容完全同步,否则,一人一言,不同客户端读同一个文件读出不同数据,用户非得疯了不可。。。
在HDFS中,为了保证数据的正确性和同一份数据的一致性,做了大量的工作。首先,每一个数据块,都有一个版本标识,在Block类中,用一个长整型的数generationStamp来表示版本信息(Block类是所有表示数据块的数据结构的基类),一旦数据块上的数据有所变化,此版本号将向前增加。在主控服务器上,保存有此时每个数据块的版本,一旦出现数据服务器上相关数据块版本与其不一致,将会触发相关的恢复流程。这样的机制保证了各个数据服务器器上的数据块,在基本大方向上都是一致的。但是,由于网络的复杂性,简单的版本信息无法保证具体内容的一致性(因为此版本信息与内容无关,可能会出现版本相同,但内容不同的状况)。因此,为了保证数据内容上的一致,必须要依照内容,作出签名。。。
当客户端向数据服务器追加写入数据包时,每一个数据包的数据,都会切分成512字节大小的段,作为签名验证的基本单位,在HDFS中,把这个数据段称为Chunk,即传输块(注意,在GFS中,Chunk表达的是数据块...)。在每一个数据包中,都包含若干个传输块以及每一个传输块的签名,当下,这个签名是根据Java SDK提供的CRC算法算得的,其实就是一个奇偶校验。当数据包传输到流水线的最后一级,数据服务器会对其进行验证(想一想,为什么只在最后一级做验证,而不是每级都做...),一旦发现当前的传输块签名与在客户端中的签名不一致,整个数据包的写入被视为无效,Lease Recover(租约恢复)算法被触发。。。
从基本原理上看,这个算法很简单,就是取所有数据服务器上此数据块的最小长度当作正确内容的长度,将其他数据服务器上此数据块超出此长度的部分切除。从正确性上看,此算法无疑是正确的,因为至少有一个数据服务器会发现此错误,并拒绝写入,那么,如果写入了的,都是正确的;从效率上看,此算法也是高效的,因为它避免了重复的传输和复杂的验证,仅仅是各自删除尾部的一些内容即可。但从具体实现上来看,此算法稍微有些绕,因为,为了降低本已不堪重负的主控服务器的负担,此算法不是由主控服务器这个大脑发起的,而是通过选举一个数据服务器作为Primary,由Primary发起,通过调用与其他各数据服务器间的InterDatanodeProtocol协议,最终完成的。具体的算法流程,参见LeaseManager类上面的注释。需要说明的是此算法的触发时机和发起者。此算法可以由客户端或者是主控服务器发起,当客户端在写入一个数据包失败后,会发起租约恢复。因为,一次写入失败,不论是何种原因,很有可能就会导致流水线上有的服务器写了,有的没写,从而造成不统一。而主控服务器发起的时机,则是在占有租约的客户端超出一定时限没有续签,这说明客户端可能挂了,在临死前可能干过不利于数据块统一的事情,作为监督者,主控服务器需要发起一场恢复运动,确保一切正确。。。

HDFS要点的更多相关文章

  1. HDFS要点剖析

    谈到大数据,不得不提的一个名词是"HDFS".它是一种分布式文件存储系统,其系统架构图如下图所示: 从图中可以了解到的几个关键概念 元数据(MetaData) 机架(Rock) 块 ...

  2. Hadoop HDFS分布式文件系统设计要点与架构

      Hadoop HDFS分布式文件系统设计要点与架构     Hadoop简介:一个分布式系统基础架构,由Apache基金会开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群 ...

  3. HDFS的架构和设计要点

    HDFS的架构和设计要点 转 大数据之路 发布于 2012/10/11 23:00 字数 4487 阅读 495 收藏 1 点赞 0 评论 0 撸了今年阿里.头条和美团的面试,我有一个重要发现.... ...

  4. Hadoop HDFS分布式文件系统设计要点与架构(转摘)

    Hadoop简介:一个分布式系统基础架构,由Apache基金会开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力高速运算和存储.Hadoop实现了一个分布式文件系统(Ha ...

  5. hadoop权威指南(第四版)要点翻译(4)——Chapter 3. The HDFS(1-4)

    Filesystems that manage the storage across a network of machines are called distributed filesystems. ...

  6. hadoop权威指南(第四版)要点翻译(5)——Chapter 3. The HDFS(5)

    5) The Java Interface a) Reading Data from a Hadoop URL. 使用hadoop URL来读取数据 b) Although we focus main ...

  7. HDFS 与 GFS 的设计差异

    后端分布式系列」前面关于 HDFS 的一些文章介绍了它的整体架构和一些关键部件的设计实现要点. 我们知道 HDFS 最早是根据 GFS(Google File System)的论文概念模型来设计实现的 ...

  8. HDFS 异常处理与恢复

    在前面的文章 <HDFS DataNode 设计实现解析>中我们对文件操作进行了描述,但并未展开讲述其中涉及的异常错误处理与恢复机制.本文将深入探讨 HDFS 文件操作涉及的错误处理与恢复 ...

  9. HDFS Client 设计实现解析

    前面对 HDFS NameNode 和 DataNode 的架构设计实现要点做了介绍,本文对 HDFS 最后一个主要构成组件 Client 做进一步解析. 流式读取 HDFS Client 为客户端应 ...

随机推荐

  1. shell基础学习

    1. #! /bin/bash #设置只读变量,只读变量不可修改myUrl="http://www.baidu.com"readonly myUrl #删除变量,unset不能删除 ...

  2. (九)Linux查看用户登录的命令

    用户登录查看命令 w 含义:就这么简单,一个字母w就是一个命令.查看登录用户信息. 输出的结果的含义: USER       登录的用户名 TTY        登录终端 FROM      从哪个I ...

  3. 「bzoj 4180: 字符串计数」

    题目 真是一道好题 首先根据一个非常显然的贪心,如果给出了一个串\(S\),我们如何算最小操作次数呢 非常简单,我们直接把\(S\)拉到\(T\)的\(SAM\)上去跑,如果跑不动了就停下来,重新回到 ...

  4. Web项目打成war包部署到tomcat时报MySQL Access denied for user 'root'@'localhost' (using password: YES)错误解决方案

    Web项目使用使用root账号root密码进行部署,通过Eclipse加载到Tomcat服务器可以发布成功,打成war包放到tomcat的webapps目录无法发布成功,报错: jdbc.proper ...

  5. WEB安全 ACCESS 注入、盲注脚本

    http://www.xxx.cn/cp.asp?classid=3http://www.xxx.cn/cp.asp?classid=3 and //有拦截关键字http://www.xxx.cn/c ...

  6. leetcode 121. Best Time to Buy and Sell Stock 、122.Best Time to Buy and Sell Stock II 、309. Best Time to Buy and Sell Stock with Cooldown

    121. Best Time to Buy and Sell Stock 题目的要求是只买卖一次,买的价格越低,卖的价格越高,肯定收益就越大 遍历整个数组,维护一个当前位置之前最低的买入价格,然后每次 ...

  7. Shell笔记-01

    打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了. 输入一些代码: #!/bin/bash ...

  8. 【题解】洛谷P1073 [NOIP2009TG] 最优贸易(SPFA+分层图)

    次元传送门:洛谷P1073 思路 一开始看题目嗅出了强连通分量的气息 但是嫌长没打 听机房做过的dalao说可以用分层图 从来没用过 就参考题解了解一下 因为每个城市可以走好几次 所以说我们可以在图上 ...

  9. Reading SketchVisor Robust Network Measurement for Sofeware Packet Processing

    SIGCOMM17 摘要 在现有的网络测量任务中包括流量监测.数据收集和一系列网络攻击的预防.现有的基于sketch的测量算法存在严重性能损失.大量计算开销以及测量的精确性不足,而基于硬件的优化方法并 ...

  10. Linux Shell常用技巧(十二)

    二十三. Bash Shell编程:  1.  读取用户变量:    read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入.在read命令后面,如果 ...