0 前言
0.1 一些概念
0.1.1 什么是分布式文件系统DFS(distributed filesystem)
管理网络中跨多台计算机存储的文件系统称为分布式文件系统
0.1.2 HDFS是什么
Hadoop自带的分布式文件系统 Hadoop Distributed Filesystem
1 HDFS的设计
1.1 HDFS的设计目标
- 存储大文件:可以存储MB、GB、TB、PB级别的数据
- 采用流式数据访问:
- 我的理解:文件存储时被拆分成多块,所以读取文件时无需获取整个后进行处理,而是分块分批次处理。
- HDFS的构建思路:一次写入,多次读取是最高效的访问模式,每次分析都基于数据集的大部分数据,读取整个数据集的时间延迟比读取第一条延迟重要(看中吞吐量)
- 运行于商业硬件上:节点故障率对系统影响小,因此对硬件要求不高
1.2 HDFS不适用场景
- 低延时的数据访问:HDFS不适用延时要求在毫秒级的应用。HDFS的目的是高吞吐。HBASE更适合低延时的数据访问。
- 大量的小文件:
- 前置知识:HDFS有两种节点,一个是管理节点(namenode),一个是工作节点(datanode),文件存储在工作节点,文件的元数据(如存储的位置信息)存储在管理节点。
- 管理节点少(1个或几个),文件系统数量收到管理节点内存大小限制,可能存储不下大量的小文件的元数据信息。
- 多方写入,修改文件的任意位置。写操作总以只添加的方式在文件末尾写数据。
2 HDFS的概念
2.1 数据块Blocks
磁盘的数据块是磁盘进行数据读写的最小单位,HDFS的数据块与之类似。
- 默认大小128MB
- 与磁盘的数据块不同,小于一个块大小的文件不会占据整个块空间
2.1.1 数据块的作用
- 文件可以被分块存储,因此文件可以被拆分,大于单个节点磁盘容量
- 容易备份,提高容错能力
- 以块为存储单元而不是文件为存储单元,简化存储系统的设计
2.1.2 数据块不能过小的原因
数据块过小时,单个节点磁盘里的数据块数量多。
- 寻找块时间变多
- namenode维护信息增多,消耗其内存
2.1.3 数据快不能过大的原因
MapReduce的map任务通常一次处理一个块中的数据
参考:https://blog.csdn.net/wjn19921104/article/details/80742655
待定:map、reduce数量、效率与谁有关
- map崩溃问题:系统重新启动,重新加载数据,数据快越大,加载时间越长,系统恢复时间越长。
- 约束map输出:map后的数据经过排序进行reduce,涉及归并排序,归并排序的算法思想便是“对小文件进行排序,然后将小文件归并成大文件”,因此“小文件”不宜过大。???你到最后不得对全部同key的map进行归并吗,最后一次也是大文件
- 问题分解:数据量越大,设计可能越苦难
- 监管时间问题:namenode管理datanode,每个datanode周期性与namenode通信,汇报节点信息。一般时间间隔的设置是根据数据块大小评估的,数据块越大,预估时间越长,并且也不好估算,监测的及时性以及准确性都不好。
- 块过大导致map任务的数量少,当其小于集群可运行map任务的数量时,效率受到影响。
2.1.4 设置成128MB的原因
HDFS的块比磁盘块大,其目的是为了最小化寻址开销。如果块设置得足够大,从磁盘传输数据的时间可以明显大于定位这个块开始位置所需的时间。这样,传输一个由多个块组成的文件的时间就取决于磁盘传输速率
我们做一个估计计算,如果寻址时间为10ms左右,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们需要设置块大小为100MB左右。而默认的块大小实际为64MB,但是很多情况下HDFS使用128MB的块设置。以后随着新一代磁盘驱动器传输速率的提升,块的大小将被设置得更大。
2.2 namenode和datanode
2.2.1 特点
- namenode管理节点
- 维护文件系统树及整棵树内所有的文件和目录
- 信息以两个文件形式永久保存在磁盘上
- 命名空间镜像文件 namespace image
- 编辑日志文件 edit log
- 也记录每个文件各个块所在的数据节点信息,但不永久保存块的位置信息,这些信息在系统启动时根据数据节点信息重建
- 失去namenode时文件系统所有文件丢失
- datanode工作节点
- 存储并简述数据块
- 定期向namenode发送所存储的块的列表
2.2.2 容错机制
namenode容错至关重要
- 备份组成文件系统元数据持久状态的文件
- 写入远程挂载的网络文件系统
- 本地备份
- 运行辅助namenode(secondary namenode)
- 定期合并编辑日志和命名空间镜像
- 避免编辑日志过大,通过创建检查点来合并
- 一般运行在另一台机器,合并操作消耗CPU和内存
- 状态之后于主节点,可能丢失部分数据,可通过热备份解决
2.3 块缓存Blocking Cache
datanode从磁盘读取块,访问频繁的块可能缓存在datanode的内存中,以堆外块缓存的形式存在。
一个块仅缓存在一个datanode的内存中。
通过缓存池中增加cache directive缓存指令器告诉namenode需要缓存哪些文件及时间。 缓存池的概念用于管理一组缓存的权限和资源
2.4 联邦HDFS(HDFS Federation)
一种横向扩展namenode的方式,每个namenode管理命名空间的一部分,之间相互独立,一个节点失败不糊导致其他不可用。
2.5 HDFS HA(High Availability高可用性)
在HDFS集群中,NameNode依然是单点故障
当NameNode故障时,常规的做法是使用元数据备份重新启动一个NameNode。元数据备份可能来源于:
- 多文件系统写入中的备份
- Second NameNode的检查点文件
启动新的Namenode之后,需要重新配置客户端和DataNode的NameNode信息。另外重启耗时一般比较久,稍具规模的集群重启经常需要几十分钟甚至数小时,造成重启耗时的原因大致有:
- 元数据镜像文件载入到内存耗时较长。
- 需要重放edit log
- 需要收到来自DataNode的状态报告并且满足条件后才能离开安全模式提供写服务。
2.6 Hadoop的HA方案
采用HA的HDFS集群配置两个NameNode,分别处于Active和Standby状态。当Active NameNode故障之后,Standby接过责任继续提供服务,用户没有明显的中断感觉。一般耗时在几十秒到数分钟。
HA涉及到的主要实现逻辑有
1) 主备需共享edit log存储。
主NameNode和待命的NameNode共享一份edit log,当主备切换时,Standby通过回放edit log同步数据。
共享存储通常有2种选择
- NFS:传统的网络文件系统
- QJM:quorum journal manager
QJM是专门为HDFS的HA实现而设计的,用来提供高可用的edit log。QJM运行一组journal node,edit log必须写到大部分的journal nodes。通常使用3个节点,因此允许一个节点失败,类似ZooKeeper。注意QJM没有使用ZK,虽然HDFS HA的确使用了ZK来选举主Namenode。一般推荐使用QJM。
2)DataNode需要同时往主备发送Block Report
因为Block映射数据存储在内存中(不是在磁盘上),为了在Active NameNode挂掉之后,新的NameNode能够快速启动,不需要等待来自Datanode的Block Report,DataNode需要同时向主备两个NameNode发送Block Report。
3)客户端需要配置failover模式(失效备援模式,对用户透明)
Namenode的切换对客户端来说是无感知的,通过客户端库来实现。客户端在配置文件中使用的HDFS URI是逻辑路径,映射到一对Namenode地址。客户端会不断尝试每一个Namenode地址直到成功。
4)Standby替代Secondary NameNode
如果没有启用HA,HDFS独立运行一个守护进程作为Secondary Namenode。定期checkpoint,合并镜像文件和edit日志。
如果当主Namenode失败时,备份Namenode正在关机(停止 Standby),运维人员依然可以从头启动备份Namenode,这样比没有HA的时候更省事,算是一种改进,因为重启整个过程已经标准化到Hadoop内部,无需运维进行复杂的切换操作。
NameNode的切换通过代failover controller来实现。failover controller有多种实现,默认实现使用ZooKeeper来保证只有一个Namenode处于active状态。
每个Namenode运行一个轻量级的failover controller进程,该进程使用简单的心跳机制来监控Namenode的存活状态并在Namenode失败时触发failover。Failover可以由运维手动触发,例如在日常维护中需要切换主Namenode,这种情况graceful(优雅的) failover,非手动触发的failover称为ungraceful failover。
在ungraceful failover的情况下,没有办法确定失败(被判定为失败)的节点是否停止运行,也就是说触发failover后,之前的主Namenode可能还在运行。QJM一次只允许一个Namenode写edit log,但是之前的主Namenode仍然可以接受读请求。Hadoop使用fencing来杀掉之前的Namenode。Fencing通过收回之前Namenode对共享的edit log的访问权限、关闭其网络端口使得原有的Namenode不能再继续接受服务请求。使用STONITH技术也可以将之前的主Namenode关机。
最后,HA方案中Namenode的切换对客户端来说是不可见的,前面已经介绍过,主要通过客户端库来完成。