目标:建立对大数据生态的整体认知,理解HDFS和MapReduce的核心思想。
9:30-10:30:【概念学习】精读“HDFS”概念。搞懂块(Block)、副本(Replication)、NameNode和DataNode各自的作用。
目录
二、副本放置策略 (Replica Placement Policy)
模式一:无高可用 (Non-HA) 模式 - SecondaryNameNode
模式二:高可用 (HA) 模式 - StandbyNameNode & JournalNodes
1. JournalNodes (JN) - 共享元数据存储
2. ZooKeeper (ZK) - 分布式协调与故障转移
HDFS 概述
一、HDFS 简介
全称:Hadoop Distributed File System (Hadoop分布式文件系统)。
起源:是基于谷歌的GFS论文思想实现的开源项目。
地位:是Hadoop的核心三大组件(HDFS, MapReduce, YARN)之一,是整个Hadoop生态圈的基石。目前在大数据领域地位无可替代。
二、HDFS 核心原理与架构
重点:需要掌握其架构部分。
设计目标:存储和管理海量数据。
关键角色:
管理节点 (NameNode):负责管理文件系统的元数据(如文件名、文件目录结构、文件分块信息、块存储位置等)。这些元数据存储在内存中,因此其内存容量限制了集群处理小文件的能力。
数据节点 (DataNode):负责实际存储数据块。
三、HDFS 的优点
海量数据存储:能够存储PB级别的数据。
高容错性与可靠性:
数据通过多副本冗余机制存储(默认3份)。
即使某个DataNode宕机,数据也不会丢失,可以从其他副本恢复。
可以构建在廉价的商用服务器上,通过软件机制弥补硬件可靠性的不足,从而降低构建成本。
适合批处理:
遵循“移动计算而非移动数据”的原则。
能够将计算任务(MapReduce)调度到数据所在的节点上进行,极大减少了数据网络传输开销,非常适合大规模离线批处理场景。
高可扩展性:可以通过简单地增加机器来线性扩展集群的存储和计算能力。
四、HDFS 的缺点与局限性
高延迟访问:设计目标是高吞吐量,而非低延迟。不适合需要毫秒级响应的交互式查询或实时处理(如HBase更适合此场景)。
不支持并发写入:一个文件同一时间只能由一个写入者操作,写入是串行的。
不适合存储大量小文件:
根本原因:每个文件的元数据都会占用NameNode的固定内存。大量小文件会快速耗尽NameNode内存,导致集群无法管理更多文件。
性能影响:处理大量小文件时,计算框架(如MapReduce)会生成过多的任务,导致任务调度时间远大于数据处理时间,效率极低。
不支持文件随机修改:仅支持追加写入 (Append-only),不支持在文件任意位置进行修改。这符合其一次写入、多次读取的流式数据访问模型。
五、操作与运维
后续章节会介绍HDFS的常用操作命令和日常运维管理方法。
核心要点记忆:HDFS的核心是一个为海量数据、离线批处理而设计的分布式文件系统,其多副本机制保证了可靠性,但其元数据存储在NameNode内存的特点导致了它怕小文件和高延迟的主要缺点。
主从架构
数据写入流程
HDFS 系统架构与核心原理
一、核心架构:主从 (Master-Slave) 结构
HDFS采用典型的主从架构,由一个或多个主节点(NameNode)和多个从节点(DataNode)组成。
主节点 (NameNode - Active):
角色:集群的“大脑”和“管理者”。
核心职能:
管理元数据 (Metadata):存储和管理文件系统的命名空间(如文件名、目录结构、文件属性等)。
接收客户端请求:处理来自客户端的所有读写请求。
管理数据块映射:记录每个文件对应的数据块(Block)列表,以及每个数据块所在的DataNode信息(此部分信息由DataNode上报,NameNode在内存中动态维护)。
调度集群:通过心跳机制监控和管理所有DataNode。
从节点 (DataNode):
角色:集群的“劳动力”,负责实际的数据存储。
核心职能:
存储数据块 (Block):在本地文件系统中存储和管理真实的数据块。
执行数据读写:根据NameNode的指令或客户端的直接请求,进行数据的读写操作。
定期心跳上报 (Heartbeat):每隔3秒向NameNode发送一次心跳,汇报自身的健康状态和所存储的数据块列表。
执行指令:接收并执行来自NameNode的创建、删除、复制数据块等命令。
主节点 (NameNode - Standby):
角色:高可用 (HA) 架构中的备用主节点。
核心职能:
实时与Active NameNode同步元数据。
当Active NameNode发生故障时,自动切换为Active状态,接管集群管理职责,确保服务不中断。
二、数据存储机制
分块存储 (Block):
文件在上传时会被切分成固定大小的数据块 (Block)。
默认块大小为 128MB(可根据配置调整)。
最后一个块的大小可能小于128MB。
分块的好处:简化存储设计、支持大文件存储、便于备份和计算本地化。
多副本冗余 (Replication):
每个数据块会被复制为多个副本(默认3个)。
这些副本被分布存储在不同的DataNode上。
目的:提供极高的容错性和数据可靠性。即使某个DataNode宕机,数据也不会丢失,可以从其他副本恢复。
三、读写流程(以写入为例)
客户端发起文件上传请求(如10GB的
file1
)。客户端将文件按128MB切分成多个Block(如80个)。
客户端与NameNode通信,获取每个Block应存入哪些DataNode的地址。
客户端根据指令,将各个Block并行地写入到不同的DataNode上。
DataNode之间会自动完成副本的复制(Pipeline写入)。
写入完成后,NameNode在内存中更新元数据,记录
file1
由哪些Block组成。各个DataNode通过心跳,定期向NameNode汇报自己存储了哪些Block,从而让NameNode维护完整的“Block->DataNode”映射关系。
四、关键机制:心跳 (Heartbeat)
作用:DataNode与NameNode之间的通信纽带和健康检查机制。
内容:DataNode每隔3秒向NameNode发送心跳包,包涵:
自身状态(是否存活)。
所存储的所有数据块列表。
重要性:
判断节点存活:如果NameNode长时间(如10分钟) 未收到某个DataNode的心跳,则判定该节点宕机。
触发容错:一旦判定DataNode宕机,NameNode会启动数据恢复流程,将其上的数据块从其他副本重新复制到健康的DataNode上,始终维持预设的副本数(如3个)。
五、元数据 (Metadata) 管理
存储内容:
核心且持久化的:文件系统的目录树结构、文件名称、属性、文件对应的Block ID列表。
动态维护的:Block存储在哪些DataNode上(这部分信息由DataNode上报,存储在NameNode内存中,不会持久化到磁盘)。
存储位置:全部元数据(包括动态部分)都存储在NameNode的内存中,以保证极高的访问速度。
由此带来的限制:正是由于所有元数据都在内存中,大量小文件会快速耗尽NameNode内存,成为HDFS的主要瓶颈之一。
总结:HDFS通过主从架构、分块存储、多副本机制和心跳汇报,实现了海量数据的高可靠、高吞吐量存储。其设计核心是牺牲低延迟来换取高吞吐和容错能力,非常适合离线大数据处理场景。NameNode的内存是集群扩展性的关键限制因素。
HDFS 数据存储细节
一、数据块 (Block) - 核心存储单元
定义:Block是HDFS中最小的数据存储单元。
拆分规则:
文件在上传时会被按固定大小切分成多个Block。
默认大小为 128MB。
这是一个拆分标准,而非必须填满的固定容器。最后一个Block的大小就是剩余数据的大小(例如,一个129MB的文件会被拆分成一个128MB的Block和一个1MB的Block)。
块大小配置:
块大小是可配置的,但企业中通常不建议调整。
调小的弊端:会产生更多Block,导致NameNode元数据压力增大(小文件问题),计算任务调度开销增加。
调大的弊端:单个计算任务处理的数据量变大,任务运行时间变长,可能降低集群的整体并发处理能力。
二、副本放置策略 (Replica Placement Policy)
为了保证数据的可靠性和访问效率,每个Block默认会有3个副本,并按照以下策略分布在不同的DataNode上:
第一个副本:
优先存放在离客户端最近的DataNode上。
如果“距离”相同(例如客户端在集群外),则选择当前最空闲的DataNode。
第二个副本:
存放在与第一个副本不同机架 (Rack) 上的某一个DataNode上。
目的:防止整个机架出现故障(如交换机或电源故障)导致数据不可用,增强容错能力。
同样会选择该机架上最空闲的节点。
第三个副本:
存放在与第二个副本相同机架上的另一个DataNode上。
原因:跨两个机架已经提供了足够的容错能力。将第三个副本放在同一机架内,可以减少跨机架传输的网络开销,加快副本写入速度,同时也能保证数据安全。
总结:该策略完美平衡了可靠性(跨机架容灾)、写入带宽(减少跨机架传输)和读取性能(副本分布在不同位置)。
三、数据在磁盘上的存储格式
在DataNode服务器的本地文件系统上,Block被存储为物理文件。
存储目录:由HDFS配置文件(如
hdfs-site.xml
)中的dfs.datanode.data.dir
参数指定,可以配置多个目录以利用多块磁盘。文件结构:
每个Block对应两个物理文件:
blk_<id>
:这是存储实际文件内容的数据文件(如blk_1073742825
)。blk_<id>.meta
:这是对应数据文件的元信息文件(如blk_1073742825.meta
)。
Meta文件内容:
该文件与NameNode管理的全局元数据无关。
它存储的是针对这个Block数据本身的校验信息,包括:
版本信息
数据类型
每个数据块的校验和 (Checksum),用于检测数据是否损坏。
一些其他块属性。
核心要点:HDFS通过固定大小的块来简化管理和处理海量文件,通过智能的跨机架副本策略来保证数据的超高可靠性,并在磁盘上通过数据文件+校验文件的形式来确保存储数据的完整性。
hdfs-site.xml
文件路径:
hdfs-site.xml
文件位于 Hadoop 安装目录的etc/hadoop/
子目录下。
例如,如果你的 Hadoop 安装在
/usr/local/hadoop
,那么该文件的完整路径就是:/usr/local/hadoop/etc/hadoop/hdfs-site.xml
谁使用它:这个配置文件是 HDFS 守护进程的专用配置。
NameNode 和 DataNode 进程在启动时都会读取这个文件来获取配置信息。
你需要在集群中的所有节点(无论是NameNode还是DataNode)上都部署这个配置文件,并且通常保持内容一致,以确保所有节点对HDFS的行为有相同的理解。
每个DataNode节点上都必须有
hdfs-site.xml
配置文件,并且其中都定义了dfs.datanode.data.dir
这个参数。这是HDFS集群配置管理的基本要求。为什么每个DataNode都需要这个文件?
独立的本地配置:每个DataNode进程在启动时,需要读取本地的
hdfs-site.xml
文件来获取它自己应该如何工作的指令。其中最关键的一条指令就是:“我应该把数据块(Block)存到本机的哪个(些)目录里?” 这个答案对于集群中的每个DataNode来说通常是不同的,因为它取决于各自服务器的磁盘挂载情况。配置一致性:虽然
dfs.datanode.data.dir
的值可能因节点而异,但配置文件本身和其他大多数参数(如网络端口、RPC设置等)在集群范围内需要保持一致,以确保所有节点能够相互通信并遵循相同的规则。工作流程是怎样的?
准备配置:管理员会在其中一台机器上配置好
hdfs-site.xml
(以及core-site.xml
等)文件。分发配置:使用像 Ansible、Puppet、Chef 这样的自动化配置管理工具,或者直接用 scp/rsync 命令,将这些配置文件分发到集群中所有节点的相同目录(
$HADOOP_HOME/etc/hadoop/
)下。个性化配置:对于
dfs.datanode.data.dir
参数,如果需要为不同节点指定不同的目录(例如,某个节点有4块磁盘,另一个节点有6块),管理员可以通过上述工具模板化地生成每个节点特定的配置,或者确保所有节点磁盘挂载点规划一致后使用相同的配置值。启动服务:在每个节点上启动DataNode服务。每个DataNode进程都会读取本机上的
hdfs-site.xml
文件,找到dfs.datanode.data.dir
参数指定的路径,然后开始使用这些目录来存储和读取数据块。举个例子
假设你有一个3个节点的集群:
dn01
,dn02
,dn03
。
dn01 服务器有4块磁盘,挂载在
/disk1
,/disk2
,/disk3
,/disk4
。dn02 和 dn03 服务器有2块磁盘,挂载在
/data1
,/data2
。那么,每个节点本地的
hdfs-site.xml
中dfs.datanode.data.dir
的配置可能是:
在 dn01 上:
<property> <name>dfs.datanode.data.dir</name> <value>/disk1/hdfs/data,/disk2/hdfs/data,/disk3/hdfs/data,/disk4/hdfs/data</value> </property>
在 dn02 和 dn03 上:
<property> <name>dfs.datanode.data.dir</name> <value>/data1/hdfs/data,/data2/hdfs/data</value> </property>
总结
项目 说明 配置文件位置 每个节点的 $HADOOP_HOME/etc/hadoop/hdfs-site.xml
参数 dfs.datanode.data.dir
必要性 每个DataNode都必须有,因为它指示了该特定节点存储数据的本地路径。 值 通常因节点而异,取决于该服务器的磁盘数量和挂载点。 配置管理 通过自动化工具(Ansible、Puppet、Chef等)分发和管理,确保每个节点获得正确且一致的配置。 所以,每个DataNode节点上都有一份
hdfs-site.xml
文件,并且其中的dfs.datanode.data.dir
参数指导着该节点如何使用本地的存储空间。
HDFS 元数据 (Metadata) 存储与合并机制
一、元数据内容与存储挑战
存储内容:NameNode内存中存储两大核心元数据:
核心元数据:文件系统的目录树结构、文件属性、以及文件被拆分成了哪些Block(Block ID列表)。这部分信息至关重要,必须持久化。
动态映射信息:每个Block存储在哪些DataNode上。这部分信息由DataNode定期上报,NameNode在内存中动态维护,不需要持久化(丢失后可自动恢复)。
存储挑战:内存中的数据“断电易失”。必须将关键元数据(核心元数据)持久化到磁盘,否则NameNode重启后整个文件系统将无法恢复。
二、持久化方案:FsImage + Edits
为了解决既要持久化又要保证高性能的矛盾,HDFS采用了“镜像文件 + 操作日志” 的方案。
FsImage (镜像文件):
内容:某一时刻完整的HDFS文件系统元数据(核心元数据)的快照。
特点:是一个完整的检查点,不支持增量更新。直接修改FsImage效率极低(随机写)。
Edits (编辑日志):
内容:记录自最新FsImage之后,所有对元数据的更改操作(如创建文件、删除块等)。以日志形式顺序追加写入。
特点:只追加,不修改。顺序写的性能远高于随机写,极大减轻了NameNode的磁盘I/O压力。
恢复流程:
NameNode启动时,先将FsImage加载到内存,形成基础的元数据状态。
然后按顺序重放 (Replay) Edits日志中的所有操作,将内存中的元数据状态更新到最新。
最后,接收DataNode的心跳汇报,重建“Block->DataNode”的映射关系。
三、元数据合并的必要性与机制
问题:如果Edits日志无限增长,会导致:
磁盘空间被大量占用。
NameNode重启时间极长(需要重放巨量的Edits日志),服务不可用时间无法接受。
解决方案:必须定期将Edits日志中的操作合并到FsImage中,生成新的FsImage,并清空或截断旧的Edits日志。这个过程称为 Checkpoint(检查点)。
四、合并的执行者:两种模式
模式一:无高可用 (Non-HA) 模式 - SecondaryNameNode
角色:一个独立的、非备用的守护进程。它的唯一职责就是协助NameNode执行Checkpoint。
工作流程:
触发:定期(默认1小时)或Edits日志大小达到阈值(默认64MB)时触发。
下载:从NameNode下载当前的FsImage和Edits日志。
合并:在本地加载FsImage并重放Edits,生成新的合并后的FsImage(通常命名为
fsimage.ckpt
)。上传:将新的FsImage上传回NameNode。
切换:NameNode用新的FsImage替换旧的,并开始将新的元数据操作写入一个新的Edits日志(如
edits.new
->edits
)。
模式二:高可用 (HA) 模式 - StandbyNameNode & JournalNodes
角色:
Standby NameNode:Active NameNode的热备节点。除了准备接管服务,也承担了Checkpoint的工作。
JournalNodes (JN):一个由奇数台(通常为3或5台)节点组成的独立集群,用于共享存储Edits日志。
工作流程:
共享日志:Active NameNode将元数据更改操作(Edits)同时写入本地和大多数(半数以上)JournalNodes。
同步:Standby NameNode持续地从JN集群拉取Edits,并在自身内存中重放,从而保持与Active NameNode的元数据状态近乎实时同步。
合并:Standby NameNode定期执行Checkpoint,将累积的Edits合并到FsImage中,生成新的FsImage(此过程在Standby节点本地完成)。
持久化:Standby NameNode将新的FsImage持久化到本地磁盘(FsImage存储在本地是安全且高效的)。
为何Edits不能只存本地?
在HA模式下,如果Edits只存储在Active NameNode本地,当其宕机时,Standby NameNode无法获取最新的Edits日志,从而导致元数据不一致,无法正确接管服务。共享存储(JN)确保了Edits的高可用性。
五、磁盘上的文件表示
在NameNode配置的元数据目录(dfs.namenode.name.dir
)中,你会看到类似以下文件,它们体现了合并和滚动更新的过程:
fsimage_0000000000000000019
:合并后生成的FsImage文件,数字是事务ID(Transaction ID),表示已包含到此ID为止的所有更改。fsimage_0000000000000000019.md5
:对应FsImage的校验文件。edits_0000000000000000020-0000000000000000021
:已被合并的旧Edits段文件(可安全删除)。edits_inprogress_0000000000000000022
:当前正在被写入的最新Edits文件。
最新的元数据状态 = 最新的FsImage + 最新的edits_inprogress_...
文件。
核心结论:HDFS通过 FsImage(全量快照) 和 Edits(增量日志) 的组合,高效且可靠地管理元数据。通过定期合并(Checkpoint) 来控制日志大小,确保快速恢复。在非HA模式下,由SecondaryNameNode执行合并;在HA模式下,由StandbyNameNode执行合并,且Edits日志通过JournalNodes集群共享,以实现元数据的高可用和故障自动切换。
写操作
切分数据库是在客户端进行的
读文件
HDFS 文件读写流程总结
一、文件写入 (Write) 流程
客户端发起请求:
客户端向NameNode发起请求,请求上传一个文件(如300MB的
/tmp/file1
)。NameNode执行权限和目录检查。通过后,告知客户端允许上传。
客户端拆分文件:
在客户端本地,将文件按默认128MB的大小拆分成多个Block。
示例:300MB文件被拆分成Block1(128MB)、Block2(128MB)、Block3(44MB)。
优点:拆分工作在客户端进行,减轻了HDFS集群的压力。
上传单个Block(Pipeline写入):
客户端逐个上传Block。以上传Block1为例:
a. 请求分配DataNode:客户端向NameNode请求上传Block1。
b. 选择DataNode:NameNode根据副本放置策略,返回三个适合存储该Block的DataNode列表(如DN1, DN2, DN3)。
c. 建立Pipeline:客户端与这三个DataNode建立Pipeline(管道) 连接(Client -> DN1 -> DN2 -> DN3)。
d. 传输数据:客户端将Block1的数据以Packet(数据包) 为单位流入Pipeline。
e. 流水线复制:
DN1收到一个Packet后,会将其存到本地内存,同时立刻将其转发给DN2。
DN2做同样操作,收到后存内存并转发给DN3。
DN3将Packet存入本地内存。
f. 持久化与ACK:各个DataNode会异步地将内存中的Packet写入本地磁盘。
g. 成功确认:确认过程沿Pipeline反向进行。
DN3完成磁盘写入后,向DN2发送一个成功ACK。
DN2(在自身完成写入且收到DN3的ACK后) 向DN1发送ACK。
DN1(在自身完成写入且收到DN2的ACK后) 向客户端发送最终的ACK,宣告Block1写入成功。
循环上传:
客户端收到Block1的成功信号后,开始按相同流程上传Block2,然后是Block3。
最终确认:
所有Block都上传成功后,客户端通知NameNode。
NameNode才在内存中生成最终的元数据,记录文件
/tmp/file1
由哪些Block组成,以及每个Block的副本位置(由DataNode心跳上报补充)。
二、文件读取 (Read) 流程
客户端发起请求:
客户端向NameNode发起请求,请求下载文件(如
/tmp/file1
)。NameNode进行权限校验。通过后,准备返回元数据。
返回元数据:
NameNode从内存中查询到文件
/tmp/file1
的元数据,包括:文件由哪些Block构成(如Block1, Block2, Block3)。
每个Block的所有副本所在的DataNode列表(如Block1在DN5, DN8, DN1上)。
关键优化:NameNode会贴心地将每个Block的DataNode列表按照与客户端的网络拓扑距离进行排序(最近的在最前),以优化读取性能。
客户端直接读取数据:
客户端拿到元数据后,直接与存储Block的DataNode建立连接(不再通过NameNode中转)。
对于每个Block,客户端都默认选择排序列表中最靠前(即最近) 的DataNode进行读取。
示例:读取Block1时,优先连接距离最近的DN5。
并行读取与合并:
客户端可以并行地从多个DataNode下载不同的Block。
所有Block下载到客户端本地后,客户端将其合并成完整的原始文件(如
file1
),并返回给用户。
核心设计思想
减轻主节点压力:读写数据的核心流程(数据传输)都在客户端和DataNode之间直接进行,NameNode只负责元数据管理和调度,避免成为性能瓶颈。
数据本地化 (Data Locality):计算任务(如MapReduce)会优先被调度到存有相关数据的DataNode上执行,遵循“移动计算比移动数据更划算”的原则。
高吞吐量:通过大Block设计、Pipeline流水线传输和客户端并行读取,最大化数据传输的吞吐量,而非追求低延迟。
容错机制:读写过程中任何DataNode失败,客户端都会自动尝试列表中的下一个副本节点。
HDFS 安全模式 (Safe Mode) 总结
一、什么是安全模式?
定义:安全模式是HDFS的一种自我保护状态。在此状态下,HDFS是只读的。
行为:
允许:读取数据请求。
禁止:写入、删除、修改等所有变更命名空间的请求。
二、为什么需要安全模式?
目的:为了保证集群中数据块(Block)的安全性和可靠性。
机制:当HDFS检测到集群状态“不安全”(即可能存在数据丢失风险)时,会主动进入安全模式,冻结所有写操作,防止在状态不确定时进行修改导致更严重的问题。
三、进入/退出安全模式的条件(核心机制)
触发和退出安全模式的核心依据是数据块的上报率。
触发条件(进入安全模式):
当已上报的数据块数量 / 总数据块数量 < 阈值 时,系统自动进入安全模式。
默认阈值:
0.999
(即 99.9%)。举例:一个集群有1000个Block。
如果只有10个Block被上报,上报率为1%,远低于99.9%,触发安全模式。
如果有998个Block被上报,上报率为99.8%,仍低于99.9%,仍处于安全模式。
退出条件(离开安全模式):
当已上报的数据块数量 / 总数据块数量 >= 阈值 时,系统自动离开安全模式。
举例:接上例,当上报的Block数从998变成999时,上报率达到99.9%,满足条件,集群自动退出安全模式,恢复正常读写功能。
四、导致安全模式的常见原因
根本原因都是导致了Block上报率的缺失或不足。
NameNode重启(最常见):
原因:NameNode元数据存储在内存中,重启后内存清空,Block映射关系丢失。此时上报率为0%。
过程:NameNode启动后进入安全模式,等待所有DataNode通过心跳上报其存储的Block列表。随着上报的进行,上报率逐渐升高,达到阈值后自动退出。
结论:NameNode刚重启后处于安全模式是正常现象,需等待其自动恢复。
DataNode异常:
原因:部分DataNode进程宕机、网络故障导致无法连接,或DataNode刚启动还未完成上报。
影响:这些宕机节点上的Block无法被上报,导致总上报率下降,可能触发安全模式。
排查:这是生产环境中最需要关注的原因。需检查DataNode的日志和状态。
NameNode本地存储问题:
原因:NameNode所在的服务器磁盘空间不足,导致无法正常写入或读取FsImage和Edits日志文件。
影响:元数据管理功能出现异常,可能无法正常处理DataNode的心跳上报,从而触发安全模式。
排查:如果DataNode均正常,则应检查NameNode的磁盘空间和日志。
五、排查与处理建议
当集群意外地长时间处于安全模式时,应按照以下顺序进行排查:
首要排查DataNode:
使用
hdfs dfsadmin -report
命令查看所有DataNode的在线状态。检查是否有DataNode宕机或显示为异常状态。大部分情况是某个或某些DataNode挂掉导致。
重启异常的DataNode进程。
其次排查NameNode:
如果DataNode全部正常,则检查NameNode的磁盘空间,清理足够空间。
查看NameNode的日志(
hadoop-hdfs-namenode-<hostname>.log
),寻找错误信息。
(可选)手动操作:
在确认数据块确实没有丢失(例如只是临时故障)的情况下,有时可以手动强制退出安全模式(但不推荐首选):hdfs dfsadmin -safemode leave
获取安全模式状态:hdfs dfsadmin -safemode get
总结:安全模式是HDFS的“保险丝”。NameNode重启后短暂进入安全模式是正常的,只需等待其自动恢复。如果集群意外陷入安全模式,应优先检查DataNode的健康状态,这是最常见的故障点。
联邦机制——Federation(多台namenode)
HDFS 高可用 (High Availability)
一、单NameNode架构的缺陷
内存上限问题:单台NameNode服务器的内存容量限制了整个HDFS集群可管理的文件数量(因为所有元数据都存在内存中)。
单点故障 (SPOF) 问题:唯一的NameNode宕机将导致整个HDFS集群不可用,无法进行任何元数据操作。
二、解决内存上限:联邦 (Federation)
机制:引入多个独立的NameNode(或NameService),每个NameNode管理文件系统命名空间的一部分(例如,
/user
由一个NN管理,/data
由另一个NN管理)。优点:
水平扩展命名空间:通过添加NameNode来扩展整个集群的元数据处理能力,突破单机内存限制。
隔离性:各个NameNode管理的命名空间相互独立,互不影响。
注意:联邦解决的是扩展性问题,而非可用性问题。联邦中的每个NameNode仍然是一个潜在的单点故障。
三、解决单点故障:高可用 (HA)
HA通过主备NameNode机制来解决单点故障,确保服务不间断。
核心角色:
Active NameNode:处理所有客户端请求,管理集群。
Standby NameNode:Active NameNode的热备节点,时刻准备接管工作。生产环境中可以配置多个。
核心目标:当Active NameNode发生故障时,能自动、快速地将Standby NameNode切换为Active状态,对用户透明。
四、HA的实现:依赖两个关键组件
高可用架构需要两个外部组件协同工作来实现故障转移和数据同步。
1. JournalNodes (JN) - 共享元数据存储
角色:一个由奇数台(如3、5台)节点组成的轻量级集群,用于共享存储Edits日志。
工作流程:
Active NameNode将所有的元数据更改操作(Edits)同时写入(多副本) 大多数JournalNodes。
Standby NameNode持续地监听并从JN集群拉取最新的Edits。
Standby NameNode在自身内存中重放这些Edits,从而使其元数据状态与Active NameNode保持近乎实时同步。
为什么需要JN?:确保Active和Standby NameNode的元数据状态一致。如果Edits只写在Active本地,宕机后Standby将无法获取最新日志,无法正确接管。
2. ZooKeeper (ZK) - 分布式协调与故障转移
角色:一个可靠的分布式协调服务,负责监控NameNode状态和主导故障转移(Failover)。
工作流程:
每个NameNode上都运行一个ZKFailoverController (ZKFC) 轻量级进程。
ZKFC定期通过ZK与其它节点通信,监控其所监视的NameNode的健康状态。
如果Active NameNode宕机(或网络分区),其对应的ZKFC与ZK的会话将过期。
ZK会通知Standby节点上的ZKFC。
ZKFC会触发一个选举过程,选出一个新的Standby节点将其提升为Active状态。
为什么需要ZK?:提供了一个可靠、高效、公正的“裁判”机制,来自动化完成状态监控和主备切换,避免了人工干预的延迟和错误。
五、总结:HA如何工作
数据同步:通过JournalNodes,Standby NameNode实时同步Active NameNode的元数据更改。
状态监控:通过ZooKeeper和ZKFC进程,持续监控所有NameNode的健康状态。
自动故障转移:当检测到Active故障时,ZooKeeper自动触发选举,将健康的Standby NameNode提升为新的Active。
客户端透明:客户端通过一个逻辑的命名服务(而非物理地址)来访问HDFS,故障切换后自动连接到新的Active NameNode,感知不到后端变化。
最终结论:HDFS通过 联邦 (Federation) 解决规模扩展问题,通过 高可用 (HA) 解决服务可用性问题。HA的实现依赖于 JournalNodes 保证数据一致性,以及 ZooKeeper 实现自动化的故障转移,共同构成了一个健壮的生产级HDFS集群。
HDFS 操作命令
HDFS提供了多种方式来与其进行交互,主要分为Shell命令行和REST API两种,分别面向运维和开发人员。
一、Shell 命令行操作 (针对运维/用户)
Shell命令是与HDFS交互最直接、最常用的方式,其语法与Linux文件操作命令高度相似,易于上手。
命令前缀:
hadoop fs ...
(通用性强,可操作多种文件系统,如HDFS, Local FS, S3等)hdfs dfs ...
(专用于HDFS,但与hadoop fs
在HDFS上的功能完全一致)hadoop dfs ...
(已过时,不推荐使用)
总结:
hadoop fs
和hdfs dfs
可任意选用,没有功能区别。常用操作命令:
这些命令在两种前缀下通用,其参数与Linux命令几乎一致。命令 功能 示例 -ls <路径>
列出目录内容 hdfs dfs -ls /tmp
-mkdir <路径>
创建目录 hdfs dfs -mkdir /user/hadoop
-put <本地源> <HDFS目标>
从本地文件系统上传文件/目录到HDFS hdfs dfs -put data.txt /tmp/
-get <HDFS源> <本地目标>
从HDFS下载文件/目录到本地文件系统 hdfs dfs -get /tmp/data.txt .
-cp <源> <目标>
在HDFS内部复制文件/目录 hdfs dfs -cp /file1 /backups/
-mv <源> <目标>
在HDFS内部移动文件/目录 hdfs dfs -mv /olddir /newdir
-rm [-r] <路径>
删除文件(加 -r
选项删除目录)hdfs dfs -rm /tmp/file.txt
hdfs dfs -rm -r /tmp/logs
-cat <文件路径>
查看HDFS上文件的内容 hdfs dfs -cat /tmp/data.txt
-chmod
,-chown
修改文件权限和属主 hdfs dfs -chmod 755 /tmp/script.sh
路径格式:
简写格式:当你的客户端已经配置了默认的HDFS集群地址时,可以直接使用路径。这种方式操作的是默认集群。
示例:
hdfs dfs -ls /tmp
(操作默认集群的/tmp
目录)
全写格式(标准URI):当需要明确指定操作的HDFS集群时,使用完整的URI。格式为:
hdfs://<namenode_host>:<port>/<path>
<namenode_host>:<port>
:NameNode的主机名/IP和RPC端口(默认通常是8020或9000)。何时使用:需要操作非默认的HDFS集群时;在脚本中为了清晰明确。
示例:
hdfs dfs -ls hdfs://namenode01:8020/tmp
(明确操作namenode01
集群的/tmp
目录)
二、REST API 操作 (针对开发)
REST API提供了通过HTTP协议操作HDFS的方式,其最大优势是语言无关性,任何能发送HTTP请求的编程语言都可以调用,极大方便了应用开发。
核心价值:通用性。Java, Python, Go, JavaScript等语言都可以轻松集成HDFS操作,而不必依赖Hadoop的Java客户端。
如何调用:
使用HTTP方法(PUT, GET, POST, DELETE等)向特定的URL发起请求。
URL中需要包含HDFS集群地址和WebHDFS服务的端口(默认通常是9870)。
通常需要在URL中包含参数
op=
来指定要执行的操作。
操作示例:上传文件 (HTTP PUT)
curl -i -X PUT \
"http://<namenode_host>:9870/webhdfs/v1/<path>?op=CREATE&overwrite=true" \
-T <本地文件路径>
<namenode_host>:9870
: NameNode的HTTP地址和端口。/webhdfs/v1/
: WebHDFS服务的固定路径。op=CREATE
: 操作类型为“创建”(即上传)。overwrite=true
: 如果文件存在则覆盖。
总结与对比
特性 | Shell 命令 | REST API (WebHDFS) |
---|---|---|
主要用户 | 系统管理员、数据工程师(运维/交互) | 应用程序开发者(开发集成) |
使用方式 | 在终端命令行中执行 | 通过HTTP客户端、代码发送HTTP请求 |
优势 | 简单直观,与Linux命令类似,易于手动操作和调试 | 语言无关,便于将HDFS功能集成到各种应用中 |
适用场景 | 日常的文件管理、数据探查、运维任务 | 开发需要访问HDFS的应用程序或服务 |
待补充。。。