1. 从单机伪分布式到生产级高可用:这套集群到底在解决什么问题
很多人第一次接触大数据平台,都是从单机伪分布式开始的。一台机器上把存储、计算、调度全塞进去,跑个WordCount觉得"不过如此"。可一旦数据量上来、业务要求7×24小时不间断,单机伪分布式的短板就全暴露了:机器一挂,整个数据链路直接断掉;NameNode作为整个文件系统的"大脑",一旦宕机,所有读写全部停摆;ResourceManager管着全集群的资源分配,它一倒,所有计算任务排队等死。
这套"完全分布式+ZooKeeper集群+NameNode HA+YARN HA"的组合,本质上解决的就是单点故障和横向扩展两个核心问题。完全分布式意味着存储和计算真正分散到多台物理机或虚拟机上,每台机器各司其职;ZooKeeper集群充当"裁判员"和"协调员",负责监控主节点状态、在故障发生时自动完成主备切换;NameNode HA让文件系统元数据服务不再有单点;YARN HA则保证计算资源调度层同样具备容错能力。
适合谁来参考这套方案?如果你已经搭过伪分布式、能看懂core-site.xml和hdfs-site.xml的基本配置,现在需要把环境升级到能扛住节点故障的生产级架构,那这篇内容就是为你准备的。我会把每个组件的角色、配置的取舍逻辑、以及实际搭建中最容易翻车的地方,按我自己的实操顺序拆开讲。
先给一个全局视角:整套集群里,ZooKeeper是"地基中的地基"。NameNode HA和YARN HA都依赖ZooKeeper来做状态协调和故障选举。所以搭建顺序必须是先ZooKeeper集群,再HDFS HA,最后YARN HA。这个顺序不能乱,乱了就会出现各种"明明配置没错但就是起不来"的诡异问题。
2. 搭建前的规划:节点角色分配与基础环境决策
2.1 节点数量与角色分配的取舍逻辑
ZooKeeper集群有个硬性要求:节点数必须是奇数,且至少3个。原因在于ZooKeeper的选举算法采用"多数派"机制——3个节点允许挂1个,5个节点允许挂2个。偶数节点没有意义,因为4个节点和3个节点的容错能力一样(都只能挂1个),但多消耗一台机器。
我的规划是这样的(以5台机器为例,实际可以根据资源缩减到3台):
| 主机名 | NameNode | DataNode | ResourceManager | NodeManager | ZooKeeper | JournalNode |
|---|---|---|---|---|---|---|
| node01 | 是(Active) | 是 | 是(Active) | 是 | 是 | 是 |
| node02 | 是(Standby) | 是 | 是(Standby) | 是 | 是 | 是 |
| node03 | 否 | 是 | 否 | 是 | 是 | 是 |
| node04 | 否 | 是 | 否 | 是 | 否 | 否 |
| node05 | 否 | 是 | 否 | 是 | 否 | 否 |
这里有几个关键决策点需要解释"为什么":
为什么JournalNode至少3个?JournalNode是NameNode HA中用来同步元数据操作日志的组件。Active NameNode每执行一个元数据操作,都要把日志写到多数JournalNode上才算成功。3个JournalNode允许挂1个,2个的话挂1个就写不进去了,集群直接不可用。
为什么ZooKeeper和JournalNode要分开考虑?虽然它们都是"多数派"机制,但ZooKeeper负责的是"谁当Active"的选举,JournalNode负责的是"元数据日志的同步"。两者职责不同,但都要求奇数且至少3个。在小规模集群里可以让它们部署在同一批机器上,但要注意资源隔离。
为什么node01和node02同时承担这么多角色?这是资源受限下的常见做法。如果机器充足,最佳实践是把ZooKeeper和JournalNode独立部署到专用节点上,避免和DataNode、NodeManager抢资源。但在测试环境或中小规模生产环境中,合并部署是完全可以接受的,只要做好内存和磁盘的隔离规划。
2.2 基础环境准备中最容易忽略的细节
在开始配置之前,有几件事必须先做,否则后面会反复踩坑:
主机名与hosts解析。每台机器必须设置唯一的主机名,并且所有机器的/etc/hosts文件里都要有完整的映射关系。我见过太多人只在本机配了hosts,结果跨机器通信时解析失败,报"UnknownHostException"。正确做法是在每台机器上都写入所有节点的IP和主机名映射。
SSH免密登录。NameNode HA的故障切换、ZooKeeper的集群启动、以及后续的批量脚本执行,都依赖SSH免密。配置方式是:在每台机器上生成密钥对,然后把公钥追加到所有机器的authorized_keys文件中。注意要包括本机的免密(ssh localhost也要能通),否则某些脚本会卡住。
时间同步。ZooKeeper的选举、JournalNode的日志同步、以及YARN的任务调度,都强依赖各节点时间一致。如果时间偏差超过阈值,会出现"明明节点活着却被判定为死亡"的问题。建议所有节点配置NTP服务,确保时间偏差在毫秒级。
JDK版本选择。Hadoop 3.x推荐JDK 8或JDK 11。我实测下来JDK 8最稳,JDK 11在某些Hadoop版本上会有模块化相关的警告。安装完JDK后,务必在/etc/profile里配置JAVA_HOME,并且确保所有节点路径一致——Hadoop的启动脚本会读取这个环境变量。
防火墙与SELinux。测试环境建议直接关闭防火墙和SELinux,避免端口被拦截导致通信失败。生产环境则需要精确开放各组件所需端口,这个后面会列出端口清单。
提示:所有节点的JDK安装路径、Hadoop安装路径、数据目录路径必须保持一致。路径不一致是导致"配置看起来一样但就是起不来"的头号原因。
3. ZooKeeper集群:整套高可用架构的协调中枢
3.1 ZooKeeper到底在HA中扮演什么角色
很多人知道HA需要ZooKeeper,但说不清楚它具体干了什么。我用一个类比来解释:ZooKeeper就像一个公证处。NameNode和ResourceManager都想当"主",但它们不能同时当主,否则会出现"脑裂"(两个主同时写数据导致数据损坏)。ZooKeeper的作用就是提供一个可靠的"谁有资格当主"的仲裁机制。
具体来说,Active NameNode启动后会在ZooKeeper上创建一个临时节点(ephemeral node)。这个临时节点的生命周期和Active NameNode的会话绑定——一旦Active NameNode宕机或网络断开,会话超时,临时节点自动消失。Standby NameNode一直在监听这个节点,一旦发现节点消失,就触发选举流程,尝试抢占成为新的Active。
YARN HA的ResourceManager也是同样的机制。所以ZooKeeper的稳定性直接决定了整个集群的故障切换能力。如果ZooKeeper集群本身挂了,HA就变成了"摆设"——主节点挂了之后没人能接管。
3.2 ZooKeeper集群的配置与启动
ZooKeeper的配置文件是conf/zoo.cfg,核心配置项如下:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/data/zookeeper/data dataLogDir=/data/zookeeper/logs clientPort=2181 server.1=node01:2888:3888 server.2=node02:2888:3888 server.3=node03:2888:3888逐项解释这些参数背后的逻辑:
tickTime=2000:ZooKeeper的基本时间单元,单位毫秒。所有其他时间配置都是它的倍数。2000ms是社区默认值,一般不需要改。
initLimit=10:Follower节点与Leader节点建立连接时,允许的最大心跳数。10×2000ms=20秒。如果集群网络延迟大或数据量大,可以适当调大。
syncLimit=5:Follower与Leader之间同步数据时,允许的最大心跳数。5×2000ms=10秒。超过这个时间,Leader会认为Follower挂了。
dataDir和dataLogDir:强烈建议分开配置。dataDir存快照,dataLogDir存事务日志。事务日志的写入频率很高,分开存储可以避免I/O竞争。生产环境建议dataLogDir放在独立磁盘上。
server.X配置:X是节点的唯一ID,必须和dataDir下myid文件里的数字一致。2888是Leader和Follower之间的通信端口,3888是选举端口。这两个端口不能和clientPort冲突。
配置完成后,需要在每台机器的dataDir下创建myid文件,内容就是对应的server编号。比如node01上myid内容为"1",node02为"2",node03为"3"。
启动ZooKeeper集群时,要在每台机器上执行zkServer.sh start。启动后不要急着做别的,先用zkServer.sh status检查每台机器的角色。正常情况下,应该是一台Leader、两台Follower。如果出现多台Leader或者没有Leader,说明配置有问题,需要检查myid、hosts解析和端口占用。
注意:ZooKeeper启动后,如果发现某台机器一直选不出Leader,最常见的原因是myid文件内容与server.X不匹配,或者hosts解析有问题。先排查这两个,再去看日志。
3.3 ZooKeeper运维中最容易踩的坑
坑一:dataDir目录权限问题。ZooKeeper进程需要对dataDir有读写权限。如果目录属主是root而启动用户是普通用户,会报"Permission denied"。建议统一用启动用户创建目录。
坑二:事务日志占满磁盘。ZooKeeper的事务日志会持续增长,如果不做清理,磁盘会被占满。需要配置autopurge.snapRetainCount和autopurge.purgeInterval来自动清理。我一般设置保留3个快照、每24小时清理一次。
坑三:会话超时导致误切换。如果ZooKeeper集群网络抖动,Active NameNode的会话可能超时,导致Standby误以为Active挂了而触发切换。这种情况可以通过调大sessionTimeout来缓解,但根本方案是保证ZooKeeper集群的网络质量。
坑四:ZooKeeper集群和Hadoop集群混部时的资源竞争。ZooKeeper对延迟很敏感,如果和DataNode这种I/O密集型进程混部,可能出现选举超时。建议给ZooKeeper进程预留足够的内存和CPU,必要时用cgroup做隔离。
4. NameNode HA:让文件系统元数据服务不再有单点
4.1 NameNode HA的核心机制拆解
NameNode HA的核心思路是"主备热 standby":两台NameNode同时运行,一台是Active对外提供服务,一台是Standby实时同步Active的元数据操作。当Active故障时,Standby能在几十秒内接管,对外表现为短暂的服务中断而非永久不可用。
这里的关键问题是:Standby怎么保证自己的元数据和Active一致?答案是JournalNode集群。Active NameNode每执行一个元数据操作(比如创建文件、删除目录),都会把这条操作记录写入JournalNode集群。Standby NameNode持续从JournalNode读取这些操作记录,并在自己的内存中重放,从而保持元数据同步。
这个机制有个重要特性:写操作必须写入多数JournalNode才算成功。比如3个JournalNode,至少2个写入成功,Active才会向客户端返回成功。这保证了即使部分JournalNode故障,元数据也不会丢失。
另一个关键组件是ZKFC(ZooKeeper Failover Controller)。ZKFC运行在每台NameNode上,负责监控本机NameNode的健康状态,并在ZooKeeper上维护一个锁节点。当Active NameNode故障时,Standby上的ZKFC会抢占锁节点,然后触发Standby切换为Active。
4.2 核心配置文件的关键参数
core-site.xml中需要配置:
<property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property> <property> <name>ha.zookeeper.quorum</name> <value>node01:2181,node02:2181,node03:2181</value> </property>注意fs.defaultFS的值是"hdfs://mycluster",这里的mycluster是逻辑名称,不是具体的主机名。客户端通过这个逻辑名称访问集群,具体连哪台NameNode由配置决定。
hdfs-site.xml中需要配置:
<property> <name>dfs.nameservices</name> <value>mycluster</value> </property> <property> <name>dfs.ha.namenodes.mycluster</name> <value>nn1,nn2</value> </property> <property> <name>dfs.namenode.rpc-address.mycluster.nn1</name> <value>node01:8020</value> </property> <property> <name>dfs.namenode.rpc-address.mycluster.nn2</name> <value>node02:8020</value> </property> <property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://node01:8485;node02:8485;node03:8485/mycluster</value> </property> <property> <name>dfs.journalnode.edits.dir</name> <value>/data/journalnode</value> </property> <property> <name>dfs.ha.automatic-failover.enabled</name> <value>true</value> </property> <property> <name>dfs.client.failover.proxy.provider.mycluster</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property>这些配置的逻辑链条是:先定义nameservice名称(mycluster),再定义这个nameservice下有哪些NameNode(nn1、nn2),然后指定每个NameNode的RPC地址,最后指定JournalNode集群地址用于元数据同步。
dfs.ha.automatic-failover.enabled=true这个配置很关键。设为true时,ZKFC会自动完成故障切换;设为false则需要手动执行切换命令。生产环境建议设为true,但前提是ZooKeeper集群稳定。
还需要配置隔离机制(fencing),防止"脑裂":
<property> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/home/hadoop/.ssh/id_rsa</value> </property>sshfence的作用是:当需要切换时,先通过SSH登录到旧的Active节点,确认其NameNode进程已经停止。如果没停止,就强制杀掉。这是防止两个NameNode同时处于Active状态的最后一道防线。
4.3 NameNode HA的初始化与启动顺序
初始化顺序非常关键,错了就要重来:
先启动JournalNode集群。在node01、node02、node03上分别执行
hdfs --daemon start journalnode。启动后用jps检查是否有JournalNode进程。格式化其中一个NameNode。在node01上执行
hdfs namenode -format。注意只需要格式化一个,不要两个都格式化。启动已格式化的NameNode。在node01上执行
hdfs --daemon start namenode。同步元数据到另一个NameNode。在node02上执行
hdfs namenode -bootstrapStandby。这个命令会从Active NameNode(此时是node01)拉取元数据,并同步到本地。启动第二个NameNode。在node02上执行
hdfs --daemon start namenode。初始化ZKFC。在任意一台NameNode上执行
hdfs zkfc -formatZK。这个命令会在ZooKeeper上创建HA所需的znode。启动ZKFC。在两台NameNode上分别执行
hdfs --daemon start zkfc。启动所有DataNode。在每台DataNode上执行
hdfs --daemon start datanode。
启动完成后,用hdfs haadmin -getServiceState nn1和hdfs haadmin -getServiceState nn2检查状态,应该一个active一个standby。
注意:如果第4步bootstrapStandby失败,最常见的原因是JournalNode没有全部启动,或者防火墙拦截了8485端口。先检查JournalNode进程和端口连通性。
4.4 故障切换的实测与验证
配置完成后,一定要做故障切换测试。我一般用两种方式:
手动切换测试:执行hdfs haadmin -transitionToActive nn2 --forcemanual,观察nn2是否变成active,nn1是否变成standby。然后再切回来。
模拟故障测试:直接kill掉Active NameNode的进程,观察ZKFC是否在几十秒内自动完成切换。这个测试最能验证HA是否真正生效。
实测中我发现一个常见问题:自动切换不生效,但手动切换正常。这通常是ZKFC没有正常启动,或者ZooKeeper连接有问题。检查ZKFC日志,看是否有"Connection refused"或"Session expired"的错误。
另一个问题是切换后客户端连接不上。这是因为客户端缓存了旧的Active地址。Hadoop的客户端有failover机制,会自动重试另一个NameNode,但需要配置dfs.client.failover.proxy.provider。如果没配这个,客户端切换后会报错。
5. YARN HA:计算资源调度层的容错设计
5.1 ResourceManager HA与NameNode HA的异同
YARN HA的机制和NameNode HA非常相似:两台ResourceManager,一台Active一台Standby,通过ZooKeeper做选举和故障切换。但有一个重要区别:ResourceManager不需要JournalNode。
为什么?因为ResourceManager的状态主要是"当前有哪些应用在运行、资源分配情况如何",这些状态在故障切换后可以重建——Standby接管后,NodeManager会重新注册,应用可以重新提交。而NameNode的元数据是持久化的文件系统结构,丢了就真丢了,所以必须用JournalNode做实时同步。
这个差异决定了YARN HA的配置比NameNode HA简单得多,不需要考虑日志同步的问题。
5.2 YARN HA的核心配置
yarn-site.xml中需要配置:
<property> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <property> <name>yarn.resourcemanager.cluster-id</name> <value>yarn-cluster</value> </property> <property> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2</value> </property> <property> <name>yarn.resourcemanager.hostname.rm1</name> <value>node01</value> </property> <property> <name>yarn.resourcemanager.hostname.rm2</name> <value>node02</value> </property> <property> <name>yarn.resourcemanager.zk-address</name> <value>node01:2181,node02:2181,node03:2181</value> </property> <property> <name>yarn.resourcemanager.recovery.enabled</name> <value>true</value> </property> <property> <name>yarn.resourcemanager.store.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value> </property>关键参数解释:
yarn.resourcemanager.cluster-id:集群标识,用于在ZooKeeper上区分不同的YARN集群。如果多个YARN集群共用同一个ZooKeeper,这个ID必须不同。
yarn.resourcemanager.recovery.enabled:开启状态恢复。设为true后,ResourceManager会把应用状态存储到ZooKeeper中,故障切换后Standby可以从ZooKeeper恢复状态,避免所有应用重新提交。
yarn.resourcemanager.store.class:指定状态存储的实现类。ZKRMStateStore表示用ZooKeeper存储。也可以用FileSystemRMStateStore存到HDFS,但ZooKeeper方案更可靠。
还需要配置NodeManager和ResourceManager的通信地址,以及Web UI的地址。这些配置在HA模式下要用逻辑ID而不是具体主机名。
5.3 YARN HA的启动与状态检查
启动顺序:先启动两台ResourceManager,再启动所有NodeManager。
# 在node01和node02上分别执行 yarn --daemon start resourcemanager # 在所有节点上执行 yarn --daemon start nodemanager启动后用yarn rmadmin -getServiceState rm1和yarn rmadmin -getServiceState rm2检查状态。
实测中我发现一个容易忽略的点:YARN HA的切换不会自动重跑失败的应用。如果Active ResourceManager在应用运行期间挂了,Standby接管后,正在运行的应用会继续运行(因为NodeManager还在),但应用的AM(ApplicationMaster)需要重新连接新的ResourceManager。如果AM没有重试机制,应用可能会失败。这是YARN HA的固有局限,需要在应用层面做容错。
5.4 端口规划与防火墙配置清单
整套集群涉及的端口比较多,我整理了一份清单,方便排查连通性问题:
| 组件 | 端口 | 用途 |
|---|---|---|
| ZooKeeper | 2181 | 客户端连接 |
| ZooKeeper | 2888 | Leader-Follower通信 |
| ZooKeeper | 3888 | 选举通信 |
| NameNode | 8020 | RPC服务 |
| NameNode | 9870 | Web UI |
| JournalNode | 8485 | 元数据日志同步 |
| DataNode | 9866 | 数据传输 |
| DataNode | 9864 | Web UI |
| ResourceManager | 8032 | 调度器RPC |
| ResourceManager | 8088 | Web UI |
| NodeManager | 8041 | 容器管理 |
| NodeManager | 8042 | Web UI |
| ZKFC | 8019 | 健康检查 |
测试环境可以直接关防火墙。生产环境需要精确开放这些端口,并且注意源地址限制——比如JournalNode的8485只允许两台NameNode访问,不需要对所有节点开放。
6. 踩坑实录:那些配置文档不会告诉你的问题
6.1 格式化引发的"元数据不一致"灾难
这是我最开始搭HA时踩的最大的坑。当时我图省事,在两台NameNode上都执行了hdfs namenode -format。结果启动后,两台NameNode的clusterID不一致,ZKFC怎么都选不出Active。
原因在于:每次format都会生成一个新的clusterID,两台NameNode的clusterID不同,就无法组成HA对。正确做法是只format一台,另一台用bootstrapStandby同步。
如果已经格式化了两次怎么办?两个方案:一是删掉所有数据目录重新来一遍;二是手动修改VERSION文件里的clusterID,让两台一致。我建议直接重来,手动改容易出其他问题。
6.2 ZKFC启动失败的各种姿势
ZKFC启动失败的原因五花八门,我遇到过这几种:
权限问题:ZKFC需要读取SSH私钥文件来做fencing。如果私钥文件权限是644,SSH会拒绝使用。必须改成600。
ZooKeeper连接超时:ZKFC启动时会连接ZooKeeper。如果ZooKeeper集群没起来或者网络不通,ZKFC会一直重试。检查ha.zookeeper.quorum配置是否正确。
端口冲突:ZKFC默认使用8019端口做健康检查。如果这个端口被占用,ZKFC起不来。用netstat -tlnp | grep 8019检查。
acl权限问题:如果ZooKeeper配置了ACL,ZKFC可能没有权限创建znode。测试环境建议先不配ACL。
6.3 故障切换后DataNode"失联"
有一次测试故障切换,NameNode成功切换了,但DataNode全部显示"dead"。排查后发现:DataNode的心跳是发给Active NameNode的,切换后DataNode需要重新向新的Active注册。这个过程通常很快,但如果DataNode配置的NameNode地址是具体主机名而不是nameservice,切换后DataNode就找不到新的Active了。
正确做法是在DataNode的配置中,dfs.namenode.servicerpc-address和dfs.namenode.rpc-address都使用nameservice逻辑名称,而不是具体主机名。这样切换后DataNode能自动找到新的Active。
6.4 YARN应用在切换后"卡住"
前面提到过,YARN HA切换后正在运行的应用可能卡住。我实测发现,如果应用的AM没有配置重试,切换后AM会报"Connection refused"然后退出。解决方案是在yarn-site.xml中配置:
<property> <name>yarn.resourcemanager.connect.max-wait.ms</name> <value>900000</value> </property> <property> <name>yarn.resourcemanager.connect.retry-interval.ms</name> <value>30000</value> </property>这两个参数让AM在连接ResourceManager失败时,最多重试15分钟,每次间隔30秒。这样切换期间AM不会立即退出,而是等待新的Active就绪。
6.5 内存与GC导致的"假死"
HA集群对内存要求比伪分布式高得多。每台NameNode建议至少4GB堆内存,ResourceManager至少2GB,ZooKeeper至少1GB。如果内存不足,JVM频繁GC会导致心跳超时,进而触发不必要的故障切换。
我遇到过一次:NameNode堆内存只给了1GB,结果GC停顿超过10秒,ZKFC判定NameNode不健康,触发了切换。切换后旧NameNode GC完成又活过来了,但此时已经是Standby状态,造成了"双Standby"的短暂混乱。
解决方案:给足内存,并且配置GC日志监控。NameNode的堆内存建议按"每100万文件约1GB"来估算。
7. 集群验证:怎么确认这套架构真的在正常工作
7.1 分层验证的思路
搭建完成后,不要急着跑业务,先做分层验证。我的验证顺序是:ZooKeeper集群→HDFS HA→YARN HA→综合测试。
ZooKeeper验证:用zkCli.sh连接任意节点,创建、读取、删除znode。然后kill掉一个ZooKeeper节点,确认集群仍能正常工作。再kill掉第二个,确认集群停止服务(3节点只能挂1个)。
HDFS HA验证:先确认两台NameNode状态一active一standby。然后上传一个大文件,确认写入成功。接着kill掉Active NameNode,观察Standby是否在30秒内接管。接管后重新读取刚才上传的文件,确认数据完整。
YARN HA验证:提交一个WordCount任务,确认能正常运行。然后kill掉Active ResourceManager,观察Standby是否接管。接管后提交新任务,确认能正常调度。
7.2 综合压力测试的注意事项
分层验证通过后,可以做综合测试:同时kill掉一个ZooKeeper节点和一个DataNode,确认集群仍能正常读写和计算。这个测试模拟的是真实故障场景。
实测中要注意:故障切换期间,客户端会有短暂的服务不可用(通常10-30秒)。这是正常现象,HA不是"零中断",而是"快速恢复"。如果业务要求零中断,需要在客户端做重试和缓存。
7.3 日常运维的监控要点
集群跑起来之后,日常监控要关注这几个指标:
- ZooKeeper的Leader是否存在:如果Leader频繁切换,说明网络或负载有问题。
- NameNode的堆内存使用率:超过80%要警惕,可能触发GC导致的误切换。
- JournalNode的写入延迟:延迟过高会影响NameNode的写性能。
- YARN的可用资源:如果可用资源长期为0,说明集群需要扩容。
- 各节点的磁盘使用率:DataNode磁盘满了会导致数据无法写入。
我一般会配置一个简单的监控脚本,定期检查这些指标,异常时发告警。不需要复杂的监控系统,一个crontab加邮件通知就能覆盖大部分场景。
8. 从测试环境到生产环境:还需要补哪些课
8.1 安全认证的引入
测试环境通常不配安全认证,但生产环境必须考虑。Hadoop支持Kerberos认证,可以防止未授权访问。引入Kerberos后,ZooKeeper、HDFS、YARN都需要配置相应的principal和keytab。这个过程比较复杂,建议先在测试环境验证通过再上生产。
如果不想上Kerberos,至少要做网络隔离——把集群部署在内网,只允许特定IP访问。同时配置ZooKeeper的ACL,限制znode的访问权限。
8.2 高可用之外的性能优化
HA解决了可用性问题,但性能是另一个维度。几个常见的优化方向:
NameNode的堆内存调优:根据文件数量估算,每100万文件约1GB。同时配置G1GC,减少Full GC停顿。
DataNode的磁盘选择:建议使用SSD做元数据存储,HDD做数据存储。如果全用HDD,要配置多块磁盘并行读写。
YARN的调度器选择:Capacity Scheduler适合多租户场景,Fair Scheduler适合资源共享场景。根据业务特点选择。
网络优化:如果DataNode之间数据传输量大,建议使用万兆网卡,并且配置网络绑定(bonding)提高带宽和冗余。
8.3 备份与恢复策略
HA不是备份。如果误删了数据,HA帮不了你。生产环境必须配置备份策略:
NameNode元数据备份:定期用hdfs dfsadmin -fetchImage拉取fsimage,存到独立存储上。
ZooKeeper数据备份:定期备份dataDir和dataLogDir。
关键业务数据备份:用DistCp跨集群复制,或者用HDFS的快照功能。
我一般配置每天凌晨做一次全量备份,每小时做一次增量备份。备份文件保留最近7天。
8.4 扩容与缩容的操作要点
集群运行一段时间后,可能需要扩容。扩容DataNode比较简单:在新机器上配置好环境,启动DataNode,它会自动注册到NameNode。然后用hdfs balancer做数据均衡。
扩容NameNode或ResourceManager比较复杂,需要修改配置并重启相关服务。建议在业务低峰期操作,并且提前做好回滚预案。
缩容要更谨慎:先停掉要下线的节点,等待数据复制完成,再正式移除。直接关机可能导致数据块丢失。
这套架构搭下来,从规划到验证,我大概花了三天时间。其中大部分时间不是在配置,而是在排查各种"配置看起来没错但就是起不来"的问题。所以我的建议是:每配一个组件就验证一个组件,不要全部配完再一起启动。这样出问题时排查范围小,定位快。另外,所有配置文件建议用版本管理工具管理起来,改了什么、为什么改,都有记录可查。下次环境重建时,直接拉配置就能用,不用凭记忆重新配一遍。