共计 7013 个字符,预计需要花费 18 分钟才能阅读完成。
在配置 hbase 集群将 hdfs 挂接到其它镜像盘时,有不少困惑的地方,结合以前的资料再次学习; 大数据底层技术的三大基石起源于 Google 在 2006 年之前的三篇论文 GFS、Map-Reduce、Bigtable,其中 GFS、Map-Reduce 技术直接支持了 Apache Hadoop 项目的诞生,Bigtable 催生了 NoSQL 这个崭新的数据库领域,由于 map-Reduce 处理框架高延时的缺陷,Google 在 2009 年后推出的 Dremel 促使了实时计算系统的兴起,以此引发大数据第二波技术浪潮,一些大数据公司纷纷推出自己的大数据查询分析产品,如:Cloudera开源了大数据查询分析引擎 Impala、Hortonworks 开源了 Stinger、Fackbook 开源了 Presto、UC Berkeley AMPLAB 实验室开发了Spark 计算框架,所有这些技术的数据来源均基于 hdsf, 对于 hdsf 最基本的不外乎就是其读写操作
目录:
- hdfs 名词解释
- hdsf 架构
- NameNode(NN)
- Secondary NN
- hdfs 写文件
- hdfs 读文件
- block 持续化结构
HDFS 名词解释:
- Block: 在 HDFS 中,每个文件都是采用的分块的方式存储,每个 block 放在不同的 datanode 上,每个 block 的标识是一个三元组(block id,numBytes,generationStamp),其中 block id 是具有唯一性,具体分配是由 namenode 节点设置,然后再由 datanode 上建立 block 文件,同时建立对应 block meta 文件
- Packet:在 DFSclient 与 DataNode 之间通信的过程中,发送和接受数据过程都是以 一个 packet 为基础 的方式进行
- Chunk:中文名字也可以称为块,但是为了与 block 区分,还是称之为 chunk。在 DFSClient 与 DataNode 之间通信的过程中,由于文件采用的是基于块的方式来进行的,但是在发送数据的过程中是以 packet 的方式来进行的,每个 packet 包含了多个 chunk,同时对于每个 chunk 进行 checksum 计算,生成 checksum bytes
- 小结:
- 一个文件被拆成多个 block 持续化存储(block size 由配置文件参数决定)思考:修改 block size 对以前持续化的数据有何影响?
- 数据通讯过程中一个 block 被拆成 多个 packet
- 一个 packet 包含多个 chunk
- Packet 结构与定义:Packet 分为两类,一类是实际数据包,另一类是 heatbeat 包。一个 Packet 数据包的组成结构,如图所示
- 上图中,一个 Packet 是由 Header 和 Data 两部分组成,其中 Header 部分包含了一个 Packet 的概要属性信息,如下表所示:
- Data 部分是一个 Packet 的实际数据部分,主要包括一个 4 字节校验和(Checksum)与一个 Chunk 部分,Chunk 部分最大为 512 字节
- 在构建一个 Packet 的过程中,首先将字节流数据写入一个 buffer 缓冲区中,也就是从偏移量为 25 的位置(checksumStart)开始写 Packet 数据 Chunk 的 Checksum 部分,从偏移量为 533 的位置(dataStart)开始写 Packet 数据的 Chunk Data 部分,直到一个 Packet 创建完成为止。
- 当写一个文件的最后一个 Block 的最后一个 Packet 时,如果一个 Packet 的大小未能达到最大长度,也就是上图对应的缓冲区中,Checksum 与 Chunk Data 之间还保留了一段未被写过的缓冲区位置,在发送这个 Packet 之前,会检查 Chunksum 与 Chunk Data 之间的缓冲区是否为空白缓冲区(gap),如果有则将 Chunk Data 部分向前移动,使得 Chunk Data 1 与 Chunk Checksum N 相邻,然后才会被发送到 DataNode 节点
hdsf 架构:
- hdfs 的构架图网上一堆,抓了一张表述比较清楚的图如下, 主要包含因类角色:Client、NameNode、SecondayNameNode、DataNode
- HDFS Client: 系统使用者,调用 HDFS API 操作文件; 与 NN 交互获取文件元数据; 与DN 交互进行数据读写, 注意:写数据时文件 切分由 Client 完成
- Namenode:Master 节点(也称元数据节点),是系统唯一的管理者。负责元数据的管理 ( 名称空间和数据块映射信息 ); 配置 副本策略;处理客户端请求
- Datanode:数据存储节点 (也称 Slave 节点), 存储实际的数据;执行 数据块的读写;汇报存储信息给 NN
- Secondary NameNode:小弟角色,分担大哥 namenode 的工作量;是 NameNode 的冷备份;合并 fsimage 和 fsedits 然后再发给 namenode, 注意:在 hadoop 2.x 版本,当启用 hdfs ha 时,将没有这一角色。(详见第二单)
- 解释说明:
- 热备份: b 是 a 的热备份,如果 a 坏掉。那么 b 马上运行代替 a 的工作
- 冷备份: b 是 a 的冷备份,如果 a 坏掉。那么 b 不能马上代替 a 工作。但是 b 上存储 a 的一些信息,减少 a 坏掉之后的损失
- hdfs 构架原则:
- 元数据与数据分离:文件本身的属性(即元数据)与文件所持有的数据分离
- 主 / 从架构:一个 HDFS 集群是由一个 NameNode 和一定数目的 DataNode 组成
- 一次写入多次读取:HDFS 中的文件在任何时间只能有一个 Writer。当文件被创建,接着写入数据,最后,一旦文件被关闭,就不能再修改。
- 移动计算比移动数据更划算:数据运算,越靠近数据,执行运算的性能就越好,由于 hdfs 数据分布在不同机器上,要让网络的消耗最低,并提高系统的吞吐量,最佳方式是将运算的执行移到离它要处理的数据更近的地方,而不是移动数据
NameNode:
- NameNode 是整个文件系统的管理节点,也是 HDFS 中最复杂的一个实体,它维护着 HDFS 文件系统中最重要的两个关系:
- HDFS 文件系统中的文件目录树,以及文件的数据块索引,即 每个文件对应的数据块列表
- 数据块和数据节点的对应关系,即某一块 数据块保存在哪些数据节点 的信息
- 第一个关系即目录树、元数据和数据块的索引信息会 持久化到物理存储 中,实现是保存在命名空间的镜像 fsimage 和编辑 日志 edits中,注意:在 fsimage 中,并没有记录每一个 block 对应到哪几个 Datanodes 的对应表信息
- 第二个关系是在 NameNode 启动后,每个 Datanode 对本地磁盘进行扫描,将 本 Datanode 上保存的 block 信息汇报给 Namenode,Namenode 在接收到每个 Datanode 的块信息汇报后,将接收到的块信息,以及其所在的 Datanode 信息等保存在内存中。HDFS 就是通过这种块信息汇报的方式来 完成 block -> Datanodes list 的对应表 构建
- fsimage记录了自最后一次检查点之前 HDFS 文件系统中所有目录和文件的序列化信息;
- edits是元数据操作日志(记录每次保存 fsimage 之后到下次保存之间的所有 hdfs 操作)
- 在 NameNode 启动时候,会先将 fsimage 中的文件系统元数据信息 加载到内存 ,然后根据 eidts 中的记录将内存中的元数据 同步至最新状态,将这个新版本的 FsImage 从内存中保存到本地磁盘上,然后删除 旧的 Editlog,这个过程称为一个 检查 点 (checkpoint), 多长时间做一次 checkpoint?(见第四章 参数配置) checkpoint 能手工触发吗?验证重启 hdfs 服务后 editlog 没删除呢?
- 类似于数据库中的检查点,为了避免 edits 日志过大,在 Hadoop1.X 中,SecondaryNameNode 会按照时间阈值(比如 24 小时)或者 edits 大小阈值(比如 1G),周期性的将 fsimage 和 edits 的合并,然后将最新的 fsimage 推送给 NameNode。而在 Hadoop2.X 中,这个动作是由 Standby NameNode 来完成.
- 由此可看出,这两个文件一旦损坏或丢失,将导致整个 HDFS 文件系统不可用,在 HDP2.4 安装(五):集群及组件安装 集 群安装过程中,hdfs 默认的只能选择一个 NN,是否意味着 NN 存在单点呢?( 见第二单 hdfs HA)
- 在 hadoop1.X 为了保证这两种元数据文件的高可用性,一般的做法,将dfs.namenode.name.dir 设置成以逗号分隔的多个目录,这多个目录至少不要在一块磁盘上,最好放在不同的机器上,比如:挂载一个共享文件系统
- fsimage\edits 是序列化后的文件,想要查看或编辑里面的内容,可通过 hdfs 提供的 oiv\oev 命令,如下:
- 命令: hdfs oiv(offline image viewer)用于将 fsimage 文件的内容转储到指定文件中以便于阅读,,如文本文件、XML 文件,该命令需要以下参数:
- -i (必填参数) –inputFile <arg> 输入 FSImage 文件
- -o (必填参数) –outputFile <arg> 输出转换后的文件,如果存在,则会覆盖
- -p (可选参数)–processor <arg> 将 FSImage 文件转换成哪种格式:(Ls|XML|FileDistribution). 默认为 Ls
- 示例:hdfs oiv -i /data1/hadoop/dfs/name/current/fsimage_0000000000019372521 -o /home/hadoop/fsimage.txt
- 命令:hdfs oev (offline edits viewer 离线 edits 查看器)的缩写,该工具只操作文件因而并不需要 hadoop 集群处于运行状态。
- 示例: hdfs oev -i edits_0000000000000042778-0000000000000042779 -o edits.xml
- 支持的输出格式有binary(hadoop 使用的二进制格式)、xml(在不使用参数 p 时的默认输出格式)和stats(输出 edits 文件的统计信息)
- 小结:
- NameNode 管理着 DataNode,接收 DataNode 的注册、心跳、数据块提交等信息的上报,并且在心跳中发送数据块复制、删除、恢复等指令;同时,NameNode 还为客户端对文件系统目录树的操作和对文件数据读写、对 HDFS 系统进行管理提供支持
- Namenode 启动后会进入一个称为 安全模式 的特殊状态。处于安全模式 的 Namenode 是不会进行数据块的复制的。Namenode 从所有的 Datanode 接收心跳信号和块状态报告。块状态报告包括了某个 Datanode 所有的数据 块列表。每个数据块都有一个指定的最小副本数。当 Namenode 检测确认某 个数据块的副本数目达到这个最小值,那么该数据块就会被认为是副本安全 (safely replicated) 的;在一定百分比(这个参数可配置)的数据块被 Namenode 检测确认是安全之后(加上一个额外的 30 秒等待时间),Namenode 将退出安全模式状态。接下来它会确定还有哪些数据块的副本没 有达到指定数目,并将这些数据块复制到其他 Datanode 上。
Secondary NameNode:在 HA cluster 中又称为 standby node
- 定期合并 fsimage 和 edits 日志,将 edits 日志文件大小控制在一个限度下
- namenode 响应 Secondary namenode 请求,将 edit log 推送给 Secondary namenode,开始重新写一个新的 edit log
- Secondary namenode 收到来自 namenode 的 fsimage 文件和 edit log
- Secondary namenode 将 fsimage 加载到内存,应用 edit log,并生成一 个新的 fsimage 文件
- Secondary namenode 将新的 fsimage 推送给 Namenode
- Namenode 用新的 fsimage 取代旧的 fsimage,在 fstime 文件中记下检查 点发生的时
HDFS 写文件:
- 写文件部分参考 blog 地址(http://www.linuxidc.com/Linux/2016-09/134882.htm),2.X 版本默认 block 的大小是 128M(见第四章参数配置)
- Client 将 FileA 按 64M 分块。分成两块,block1 和 Block2;
- Client 向 nameNode 发送写数据请求,如图蓝色虚线①——>
- NameNode 节点,记录 block 信息。并返回可用的 DataNode (NameNode 按什么规则返回 DataNode? 参见第三单 hadoop 机架感知),如粉色虚线②———>
- Block1: host2,host1,host3
- Block2: host7,host8,host4
- client 向 DataNode 发送 block1;发送过程是以流式写入,流式写入过程如下:
- 将 64M 的 block1 按 64k 的 packet 划分
- 然后将第一个 packet 发送给 host2
- host2 接收完后,将第一个 packet 发送给 host1,同时 client 想 host2 发送第二个 packet
- host1 接收完第一个 packet 后,发送给 host3,同时接收 host2 发来的第二个 packet
- 以此类推,如图红线实线所示,直到将 block1 发送完毕
- host2,host1,host3 向 NameNode,host2 向 Client 发送通知,说“消息发送完了”。如图粉红颜色实线所示
- client 收到 host2 发来的消息后,向 namenode 发送消息,说我写完了。这样就真完成了。如图黄色粗实线
- 发送完 block1 后,再向 host7,host8,host4 发送 block2,如图蓝色实线所示
- 说明:
- 当客户端向 HDFS 文件写入数据的时候,一开始是写到本地临时文件中。假设该文件的副 本系数设置为 3,当本地临时文件累积到一个数据块的大小时,客户端会从 Namenode 获取一个 Datanode 列表用于存放副本。然后客户端开始向第一个 Datanode 传输数据,第一个 Datanode 一小部分一小部分 (4 KB) 地接收数据,将每一部分写入本地仓库,并同时传输该部分到列表中 第二个 Datanode 节点。第二个 Datanode 也是这样,一小部分一小部分地接收数据,写入本地 仓库,并同时传给第三个 Datanode。最后,第三个 Datanode 接收数据并存储在本地。因此,Datanode 能流水线式地从前一个节点接收数据,并在同时转发给下一个节点,数据以流水线的 方式从前一个 Datanode 复制到下一个
- 时序图如下:
- 小结:
- 写入的过程,按 hdsf 默认设置,1T 文件,我们需要 3T 的存储,3T 的网络流量
- 在执行读或写的过程中,NameNode 和 DataNode 通过 HeartBeat 进行保存通信,确定 DataNode 活着。如果发现 DataNode 死掉了,就将死掉的 DataNode 上的数据,放到其他节点去。读取时,要读其他节点去
- 挂掉一个节点,没关系,还有其他节点可以备份;甚至,挂掉某一个机架,也没关系;其他机架上,也有备份
hdfs 读文件:
- 读到文件示意图如下:
- 客户端通过调用 FileSystem 对象的 open()方法来打开希望读取的文件,对于 HDFS 来说,这个对象时分布文件系统的一个实例;
- DistributedFileSystem 通过使用 RPC 来调用 NameNode 以确定文件起始块的位置,同一 Block 按照重复数会返回多个位置,这些位置按照 Hadoop 集群拓扑结构排序,距离客户端近的排在前 面 (详见第三章)
- 前两步会返回一个 FSDataInputStream 对象,该对象会被封装成 DFSInputStream 对象,DFSInputStream 可以方便的管理 datanode 和 namenode 数据流,客户端对这个输入流调用 read()方法
- 存储着文件起始块的 DataNode 地址的 DFSInputStream 随即连接距离最近的 DataNode,通过对数据流反复调用 read()方法,将数据从 DataNode 传输到客户端
- 到达块的末端时,DFSInputStream 会关闭与该 DataNode 的连接,然后寻找下一个块的最佳 DataNode,这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流
- 一旦客户端完成读取,就对 FSDataInputStream 调用 close()方法关闭文件读取
block 持续化结构:
- DataNode 节点上一个 Block 持久化到磁盘上的物理存储结构,如下图所示:
- 每个 Block 文件(如上图中 blk_1084013198 文件)都对应一个 meta 文件(如上图中 blk_1084013198_10273532.meta 文件),Block 文件是一个一个 Chunk 的二进制数据 (每个 Chunk 的大小是 512 字节),而 meta 文件是与 每一个 Chunk 对应的 Checksum 数据,是序列化形式存储
更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/134881.htm