阿里云ECS搭建Hadoop集群实战:配置、避坑与排查指南
先把话撂在前面这篇文章不是让你按着一篇官方文档从头敲到尾而是想告诉你面对阿里云ESC搭建hadoop集群这种需求时实际动手之前该想清楚什么、配置的时候每一步在干什么、出了问题往哪几个方向排查。标题里的ESC应该是ECS也就是弹性计算服务器玩云服务器的人一眼就能看懂但这不影响我们接下来要做的这件事——在云上把一套真正的多节点Hadoop集群从零跑起来。我默认你至少碰过Linux会解压压缩包、会用vim改文件但不需要你之前搭过分布式系统。如果你正准备用云服务器做实验、跑课程设计或者验证一套数据处理的Demo这篇内容基本可以照抄作业。文章里所有路径、配置、参数都以常见的Hadoop 3.x版本为例SDK和内核版本不同会有细枝末节的差异但搭建思路是共通的。1. 整体设计为什么选多节点ECS而不是一台物理机1.1 单机伪分布式和真实集群的差距在哪很多人一开始图省事在一台机器上把Hadoop的伪分布式模式跑通就觉得自己会了。实际情况是伪分布式只是把NameNode、DataNode、SecondaryNameNode都压在同一台进程里它确实能帮你理解HDFS的基本读写流程但完全暴露不出网络通信、节点间免密、端口开放、数据副本放置策略这些真正在生产环境才会遇到的问题。我见过不止一个人伪分布式玩得很溜一上真实集群就傻眼DataNode起不来、NameNode连不上、任务提交一个串一个报错。原因很简单伪分布式里不存在跨节点通信所有进程都监听在localhost上而真实集群里面最核心的问题就是节点之间怎么互相找到、怎么互相认证、怎么传输数据。如果你打算以后做离线计算相关的工作这一步迟早要迈过去。用三台ECS搭一个最小集群是我认为性价比最高的练习方式。三台机器的角色分配也很标准一台做NameNode和ResourceManager两台做DataNode和NodeManager。这个布局既覆盖了HDFS的元数据管理节点也覆盖了YARN的资源调度节点还保留了扩展空间以后要加第四、第五台机器只需要把新机器配置好然后启动DataNode就行。1.2 ECS选型和费用控制方案阿里云的ECS实例类型很多做Hadoop集群不需要追求高算力因为Hadoop本身吃的是磁盘I/O和网络带宽CPU在数据量小的实验场景下几乎不是瓶颈。我自己的习惯是选2核4G的入门型实例系统盘给40G数据盘可以暂时不挂等数据量大了再说。这里有个很多人容易忽略的地方按量付费的ECS在关机状态下如果是普通关机不是节省模式还是会计收一定的资源占用费。所以如果是放在那里跑课后作业或者夜间测试建议把实例设置为节省停机模式这样能省不少钱。但要注意节省停机模式在部分实例类型上不支持下单之前看一下页面提示。内网IP的安排也要提前规划。同一地域、同一VPC下的ECS实例之间走的是内网流量不占用公网带宽而且速度远快于公网。我们的Hadoop集群内部通信必须走内网IP否则不仅慢还会在安全组配置上麻烦很多。三台机器最好放在同一个安全组里这样内部端口互相访问可以设成白名单全放通而公网只保留一个22端口供你SSH登录管理。1.3 安全组规则怎么配才不踩坑安全组是ECS的第一道防火墙它控制谁可以访问你的机器。很多人集群搭不起来不是配置文件有问题而是安全组把端口挡了。在Hadoop集群场景下最需要关心的端口有这些22端口SSH登录必须对公网开放9870端口NameNode的Web管理界面Hadoop 3.x版本默认是这个端口老版本是500708088端口YARN的ResourceManager Web界面8020或9000端口NameNode RPC端口这个是集群内部通信用的9864端口DataNode的数据传输端口9866端口DataNode的RPC端口9868端口DataNode的Web端口8042端口NodeManager的Web端口内部通信的端口其实不用一条条去安全组里精确控制更好的做法是把这个集群的三台机器放在同一个安全组然后在安全组里加一条规则允许这个安全组内的所有IP互访所有端口。用安全组ID作为来源比一个个填IP省事得多而且以后扩容实例也不需要改规则。对外Web界面则可以单独放行比如只允许你的办公网IP访问9870和8088或者图省事直接对公网开放实验环境下可以接受生产环境不建议。端口映射搞明白之后集群搭建的拦路虎就先消掉了一个。2. 环境准备三台机器的基础配置2.1 主机名、hosts映射和免密登录我习惯把三台机器命名为hadoop01、hadoop02、hadoop03其中hadoop01承担NameNode角色。拿到机器后第一件事就是改主机名不然你会看到一系列ip-172-31-24-123这种毫无辨识度的名字排查问题的时候脑袋疼。改主机名的方式很简单以CentOS或Alibaba Cloud Linux为例hostnamectl set-hostname hadoop01然后编辑/etc/hosts把三台机器的内网IP和主机名对应关系写进去172.16.0.10 hadoop01 172.16.0.11 hadoop02 172.16.0.12 hadoop03这里有个关键点hosts文件里最好把本机的IP也写进去不要写127.0.0.1。因为Hadoop的节点启动后NameNode会根据hostname去解析DataNode的地址如果解析到127.0.0.1就会陷入DataNode明明活着NameNode却一直认不出它的尴尬情况。这个坑我亲眼见人踩过网上搜到的报错信息五花八门最后定位原因时居然只是hosts文件少写了一行本机IP。免密登录是启动集群的硬前提。NameNode启动的时候要通过SSH到各个DataNode去执行启动脚本如果你每次都要输密码脚本根本跑不起来。配置方式很简单在hadoop01上执行ssh-keygen -t rsa -b 4096 -N 然后把公钥分发到所有机器包括自己ssh-copy-id hadoop01 ssh-copy-id hadoop02 ssh-copy-id hadoop03分发完成后务必要做一个验证从hadoop01分别ssh到三台机器能直接进去不用输密码才算通过。我建议连本机的免密也做了因为部分命令会在NameNode本机执行不做的话后面格式化、启动时会多出很多密码输入非常耗耐心。2.2 JDK版本选择和安装位置约定Hadoop 3.3.x版本已经要求Java 8以上建议直接装Java 8也就是1.8版本因为它和Hadoop各个组件之间的兼容性被验证得最多。OpenJDK完全够用不需要装Oracle JDK没必要给自己增加许可方面的麻烦。JDK的安装路径要统一。我的习惯是放在/usr/local/java下然后通过/etc/profile配置环境变量export JAVA_HOME/usr/local/java export PATH$PATH:$JAVA_HOME/bin这里有个小细节不要只配置PATH而不配置JAVA_HOME因为Hadoop的hadoop-env.sh脚本在启动时会显式读取JAVA_HOME。你光把java命令加到PATH里启动Hadoop的时候它会报JAVA_HOME is not set。另外三台机器上的JDK版本必须保持一致。如果hadoop01是1.8.0_202hadoop02是1.8.0_312表面上看都是Java 8但二进制兼容性在分布式场景下偶尔会冒出一些诡异问题。最简单的办法是装好一台之后把JDK目录整个拷贝到其他机器性能没损失反而最省事。2.3 时钟同步为什么会影响分布式任务分布式系统对时间一致性有要求这个要求不是秒级而是毫秒级。如果节点之间的系统时间差得太多HDFS的租约管理、YARN的资源心跳都会出现异常。表现的症状往往是任务莫名其妙失败日志里全是超时但网络和磁盘都正常。同步方式很简单用chrony或者ntp都行。我在实验环境里直接选择让所有节点和阿里云的内网时间源同步配置好后执行chronyc sources -v确认状态是^*说明已经同步成功。这一步别跳过我见过有人的集群跑了两天突然出问题查了一晚上发现是其中一台机器系统时间偏了好几分钟。3. Hadoop核心配置拆解每个参数为什么这么写3.1 解压和目录规范到官网下载Hadoop二进制包后我一般统一解压到/opt/module下这是很多教程喜欢用的目录结构后续升级和换版本也比较方便。解压命令tar -zxvf hadoop-3.3.6.tar.gz -C /opt/module很多人喜欢把Hadoop解压到/root或者/usr/local也不是不行但建议权限规划要清晰。我习惯创建一个专门用户hadoop来跑集群而不是用root。用root跑Hadoop也不是完全不行但会带来一些权限过大的安全问题而且如果你以后进公司公司集群大概率也不允许你用root跑提前养成习惯比较好。创建用户并授权目录useradd hadoop passwd hadoop chown -R hadoop:hadoop /opt/module/hadoop-3.3.6之后所有跟Hadoop相关的操作都用hadoop用户执行配置文件也都在这个用户的目录下修改。3.2 核心配置文件逐个拆解Hadoop的配置集中在$HADOOP_HOME/etc/hadoop/目录下我们需要修改的主要是七个文件hadoop-env.sh、core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml、workers在旧版本里叫slaves、以及一个可选的log4j.properties。先看hadoop-env.sh里面最关键的就是JAVA_HOME。虽然前面设置了系统环境变量但Hadoop的启动脚本为了可控性会优先读取这个文件里的配置。我建议直接取消注释并写成绝对路径export JAVA_HOME/usr/local/java export HDFS_NAMENODE_USERhadoop export HDFS_DATANODE_USERhadoop export HDFS_SECONDARYNAMENODE_USERhadoop export YARN_RESOURCEMANAGER_USERhadoop export YARN_NODEMANAGER_USERhadoop后面几行用户配置是为了避免Hadoop 3.x版本在非root用户下启动时报Permission denied问题这是一开始踩坑最容易遇到的地方。然后是core-site.xml它是全局核心配置。我的配置如下configuration property namefs.defaultFS/name valuehdfs://hadoop01:8020/value /property property namehadoop.tmp.dir/name value/opt/module/hadoop-3.3.6/tmp/value /property property namehadoop.proxyuser.hadoop.hosts/name value*/value /property property namehadoop.proxyuser.hadoop.groups/name value*/value /property /configurationfs.defaultFS是客户端的默认文件系统地址如果用hdfs://前缀说明走的是HDFS协议客户端提交任务时不需要显式指定地址就能连上NameNode。hadoop.tmp.dir这个配置很容易被忽略它的默认值是/tmp这意味着如果你不改它NameNode的元数据、DataNode的数据块都会存在系统临时目录里系统一清理就全没了。这个坑非常经典改了它之后最好把三元组的格式记一下后面hdfs-site.xml里还会引用。hdfs-site.xml是分布式存储的核心配置configuration property namedfs.namenode.name.dir/name valuefile:///opt/module/hadoop-3.3.6/namenode/value /property property namedfs.datanode.data.dir/name valuefile:///opt/module/hadoop-3.3.6/datanode/value /property property namedfs.replication/name value2/value /property property namedfs.namenode.secondary.http-address/name valuehadoop03:9868/value /property /configurationdfs.replication设成2是因为我们三台机器里只有两台DataNode如果设成3会一直有副本缺失告警因为第三份根本放不下。实验环境设2合理生产环境一般至少3。SecondaryNameNode不是备用的NameNode不承担故障转移任务它只是定期合并NameNode的编辑日志。在Hadoop 3.x里它的Web端口变成了9868。让hadoop03来跑这个角色可以分担NameNode的I/O压力。然后是yarn-site.xml资源调度层的配置configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.resourcemanager.hostname/name valuehadoop01/value /property property nameyarn.nodemanager.env-whitelist/name valueJAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTRIBUTE/value /property /configurationyarn.nodemanager.aux-services这个配置必须写成mapreduce_shuffle否则MapReduce任务在shuffle阶段会直接报找不到服务。yarn.resourcemanager.hostname指定ResourceManager的位置剩下两台机器通过心跳自动感知并作为NodeManager注册。最后是mapred-site.xml指定MapReduce跑在YARN上configuration property namemapreduce.framework.name/name valueyarn/value /property /configuration不配置这个的话MapReduce任务默认在本地跑不会提交到YARN集群。配置文件改完之后有一个必须执行的步骤把配置同步到其他机器。不推荐用scp一个个文件拷贝比较费劲。更好的方式是用rsync写一行命令把hadoop-env.sh和所有xml文件一次性分发过去rsync -av /opt/module/hadoop-3.3.6/etc/hadoop/ hadoop02:/opt/module/hadoop-3.3.6/etc/hadoop/ rsync -av /opt/module/hadoop-3.3.6/etc/hadoop/ hadoop03:/opt/module/hadoop-3.3.6/etc/hadoop/分发完以后要到每台机器上检查一下环境变量是不是生效了。最容易出现的状况是你改了hadoop01的/etc/profile但hadoop02和hadoop03的/etc/profile根本没动导致那边找不到Java。3.3 workers文件、格式化NameNode与启动顺序workers文件旧版本叫slaves里列出了所有充当DataNode的主机名。它决定NameNode通过start-dfs.sh脚本去唤醒哪些节点的DataNode进程hadoop02 hadoop03注意不要在这里写hadoop01因为hadoop01是纯NameNode。如果你想让它自己当DataNode也可以但实验环境下我倾向于把角色分开方便观察各角色的资源占用情况。配置完成后的第一次启动有一个必须强调的细节格式化NameNode这个操作一辈子只做一次。hdfs namenode -format格式化会生成集群唯一的ID并把元数据写入dfs.namenode.name.dir指定的目录。如果你之后改了配置文件又重新格式化会导致NameNode和DataNode的集群ID不一致DataNode启动时会一直报错握手失败。这种情况在官方文档里讲得不多但实际遇到的人非常多。判断是否需要重新格式化的标准是你之前已经跑通过集群现在只想改配置那绝对不要格式化如果集群是全新的启动前格式化一次就行。启动顺序是先启HDFS再启YARNstart-dfs.sh start-yarn.sh启动完后可以用jps命令查看各节点的Java进程。hadoop01上应该有NameNode和ResourceManagerhadoop02和hadoop03上应该有DataNode和NodeManager。验证集群是否正常最直接的方法是打开Web界面http://hadoop01的IP:9870 看HDFS状态http://hadoop01的IP:8088 看YARN资源情况如果看到Datanodes列表里有两个节点都是Live状态ResourceManager的Active Nodes有2个基本就说明集群搭起来了。4. 常见问题排查和调优心得4.1 DataNode起不来或者一直在重试这是新手最容易碰到的状况。NameNode起来了DataNode却在很短时间内反复重启。最常见的两个原因一是hosts解析问题DataNode把自己的IP解析成了127.0.0.1向NameNode注册的时候地址不对二是集群ID不一致也就是前面说的重复格式化造成的问题。排查手段很简单先看DataNode日志tail -100 /opt/module/hadoop-3.3.6/logs/hadoop-hadoop-datanode-hadoop02.log如果看到类似Storage reported corrupt or missing block或者Incompatible clusterIDs的报错基本可以确定是集群ID不匹配。解决办法不是重新格式化NameNode而是把DataNode本地的VERSION文件删掉让DataNode重启后自动从NameNode获取集群ID。VERSION文件位置在dfs.datanode.data.dir对应的目录下的current目录里。如果看到的是连接NameNode超时那就是网络问题优先确认安全组规则、内网IP是不是配错、防火墙selinux是不是开着。4.2 端口通但Web界面打不开很多人遇到过这样一个现象安全组配了9870端口防火墙也关了但浏览器就是打不开NameNode的Web页面。这种问题多半出在ECS实例的安全组入口方向而不是操作系统防火墙。阿里云安全组的规则分为入方向和出方向。入方向如果只放行了22端口那就只允许SSH其他端口一律不通。你需要明确加一条入方向规则允许来源IP访问9870端口。来源IP可以写成你的本地公网IP也可以写成0.0.0.0/0前者更安全后者实验图省事也可以。还有一个小概率但曾经真实困扰过我的问题部分阿里云地域的ECS默认开启了防火墙服务但它的默认策略是拒绝所有外部访问。检查命令systemctl status firewalld如果开着建议直接关闭然后确认用iptables检查有没有额外规则。实验环境不需要那么较真关了省心。4.3 集群能启动但跑任务很慢资源分配不够集群起来之后跑一个WordCount测试任务发现耗时远超预期。别急着怀疑机器性能先看YARN的Web界面确认Capacity Scheduler给每个任务分配了多少资源。默认配置下2核4G的机器NodeManager可能只给容器分配了很小的内存任务跑得慢是完全正常的。可以调一下yarn-site.xml里的几个参数property nameyarn.nodemanager.resource.memory-mb/name value3072/value /property property nameyarn.scheduler.maximum-allocation-mb/name value2048/value /property property nameyarn.scheduler.minimum-allocation-mb/name value512/value /property注意预留一部分内存给操作系统和DataNode进程不要把4G全部分给YARN。否则极端情况下系统内存耗尽会触发OOM进而影响集群稳定性。调完后需要重启YARNstop-yarn.sh start-yarn.sh如果是跑MapReduce任务还可以在mapred-site.xml里调mapreduce.map.memory.mb和mapreduce.reduce.memory.mb让容器拿到更大的内存。不过这一步不用太激进先跑通再慢慢调理解变化比单纯堆参数值更实际。4.4 常见问题速查表现象可能原因解决办法NameNode启动失败格式化目录权限异常检查dfs.namenode.name.dir对应目录属主是否为hadoop用户DataNode反复重启集群ID不一致删除DataNode目录下VERSION文件后重启ResourceManager界面看不到节点NodeManager和RM版本不一致统一三台Hadoop版本提交任务卡住安全组阻挡心跳端口放行集群内网全端口互通Web界面中文乱码浏览器字符集问题不理会生产环境影响不大YARN任务OOM容器内存分配过大调低yarn.scheduler.maximum-allocation-mbssh执行脚本卡密码免密没配全ssh-copy-id到所有节点SecondaryNameNode不启动没有配置http-address补全dfs.namenode.secondary.http-address磁盘空间告警数据目录建在系统盘挂载数据盘并将目录软链接过去4.5 磁盘和数据目录的一点建议ECS默认系统盘空间不大40G的系统盘装完Hadoop加上操作系统本身已经所剩无几。而HDFS一旦开始写入数据每个副本都占真实空间磁盘告警是迟早的事。我建议一开始就挂载一块数据盘比如100G的ESSD然后把HDFS的数据目录指过去。挂载并格式化数据盘之后把数据目录建好mkfs.ext4 /dev/vdb mkdir -p /data/hdfs mount /dev/vdb /data/hdfs再把hdfs-site.xml里的dfs.datanode.data.dir改成/data/hdfs/datanode这样数据块就存在独立的数据盘上哪怕系统盘坏了数据盘还能保留着重新挂载恢复。这个操作在搭建阶段就做掉比数据写满之后再迁移省心得多。4.6 关于配置同步和版本管理的一些实操心得配置同步这步看起来很机械但恰恰是最容易出问题的环节。每台机器上的Hadoop版本要和所有机器一致以及JDK版本一致否则不同版本之间的RPC协议会出现兼容性差异表现就是节点之间日志显示握手失败而Web界面看起来又一切正常。我习惯把整个/opt/module目录纳入版本管理每次修改配置后用rsync分发分发完跑一遍配置校验hadoop checknative它会把Hadoop的本地库检查一遍比如压缩编解码器是否可用如果显示openssl为false也不影响基础功能但看到false心里有数就行。这个命令不能当作集群配置是否正确的主判断只是用来扫一眼环境。5. 集群优化和后续扩展方向5.1 端口规划和多实例管理技巧如果以后你想在同一批ECS上跑多个Hadoop生态组件比如Hive、HBase端口规划要尽早统一。HDFS的8020端口、YARN的8088端口、JobHistory Server的10020端口这些在Hive或Spark连接的时候都会被引用。端口冲突是最让人抓狂的问题之一很多组件装好之后互相抢端口报错日志又不直接说端口被占排查起来非常耗时。一个建议是养成维护端口清单的习惯。比如我的实验环境就是一份简单的表格记录每个组件占用了哪些端口改动配置时先查表再动手。虽然听着很土但在多组件环境下能省下很多救命时间。5.2 从三节点扩展到更多节点三台机器组成的集群是最小可用架构但如果以后数据量涨了扩容思路很简单新买一台ECS配好JDK、配置好环境变量、把hosts同步过去、把Hadoop安装目录拷贝过去然后在workers文件里把新机器名字加进去重启DataNode和NodeManager进程即可。注意分布式扩容不需要重新格式化NameNodeDataNode进程会自动向NameNode注册。我见过有人扩容的时候手贱重新格式化导致整个集群的数据元信息全部丢失教训极其惨重。格式化这个命令在集群搭建成功以后就应该当作不存在。5.3 监控工具的引入时机集群刚搭好时靠着Web界面看状态就够了。但当跑的作业变多你会需要历史服务器来查看已完成任务的日志也就是MapReduce JobHistory Server。它默认不随start-dfs.sh启动需要单独运行mapred --daemon start historyserver然后访问10020端口查看任务的Map和Reduce阶段分别耗费了多少时间、有没有Shuffle异常。这个阶段看的是运行效率排查慢任务时比Web界面好用得多。如果以后集群规模超过5个节点再考虑引入监控平台把所有节点的CPU、内存、磁盘和网络指标集中展示。实验阶段不用过早部署那是给自己加戏。个人经验是在云上搭集群最大的好处不是性能多强而是你能快速制造一整套和真实生产环境几乎一致的网络拓扑和配置结构。在这里踩过的每一个坑都会让你在以后面对真实集群时更有底气。毕竟分布式系统那些问题不会因为你换了一家公司或者换了一套云平台就消失它们只是以不同形式重新出现而已。