搞大数据的这批人,几乎都要过Hadoop集群这一关。我自己当初从一张光秃秃的Linux系统开始,一路摸到能跑真实业务的集群,踩过的坑能写满一个笔记本。但凡当时有人把集群规划、版本选型、参数含义这些讲透,我至少能少走两周弯路。这篇文章就把我搭建Linux环境Hadoop集群的过程完整拆一遍——从空机器到一套能扛住测试负载的集群,属于这个系列的第一篇,重点解决“怎么把架构想清楚、把环境备好、把配置写对、把服务拉起来”的问题。适合刚接触大数据、准备自己搭集群的同学参考,也适合那些配过但没仔细想过参数逻辑的人查漏补缺。
Hadoop本身是什么,不再做名词解释了,但有一个观点需要先说清楚:集群搭建不是把几个配置文件一改、启动脚本一跑就完事。真正的高手在动手之前,就已经把机器规划、资源占比、故障场景全过了一遍。这篇文章宁可多花点篇幅讲“为什么”,也不赶进度只贴命令。
1. 动手之前:把架构和版本一次选对
1.1 高性能到底指什么
“高性能”这三个字,在Hadoop场景里并不是单指某一台机器算得快,而是整个集群在读写吞吐、任务调度、扩展能力上的综合表现。换句话说,集群的性能是设计出来的,不是安装包自带的光环。同样一套安装流程,硬件一样,参数不同,最终跑出来的吞吐可能差出好几倍。
我之前帮某实验室搭过一套三节点的集群,存储的是一批图像分析结果,单文件体积都不小。一开始全部默认参数,跑一个数据预处理任务经常要两三个小时。后来只是把副本策略、块大小、内存分配几个核心参数调了一下,同一个任务缩到四十分钟左右。这就是为什么这个系列的第一篇,就要先把架构和参数逻辑理清楚——后面的章节才能真正落实到性能上。
1.2 选对发行版:官方版还是Hadoop发行版
很多新手上来就问:装哪个版本?我一般建议自己学习、实验、以及中小规模部署,优先选择Apache Hadoop官方社区版本。为什么?因为官方社区版最贴近原生活,网上资料最多,遇到问题搜起来也容易。某些商业发行版确实提供了更顺滑的安装向导、界面化管理工具,但如果你还在学习阶段,直接上发行版很容易掩盖掉底层原理的细节,出了问题反而更难排查。
版本具体选哪一个,我的实践结论是:新环境选3.3.x这条线。2.x系列虽然经典,但很多老的默认参数、UI、YARN能力都已经跟不上当前需求了。除非你要维护老集群,否则没必要刻意选2.x。3.x里自带了一些容错改进,而且NameNode的web UI比2.x好用很多。具体小版本号,比如3.3.4、3.3.6,看官方发布情况和已知问题,选一个稳定版即可。
1.3 集群规模规划与硬件思路
搭建集群第一步不需要追求高大全。三节点是性价比最高的起步方案:一个节点跑NameNode和ResourceManager,另外两个节点作为DataNode和NodeManager。这样既有真正的分布式存储和计算能力,又不会把成本抬得太高。
硬件配置我给一个参考模板,这是我个人觉得三节点做测试和中小规模业务比较舒服的一套组合:
- 管理节点(主节点):4核CPU、8-16GB内存、100GB系统盘、1TB数据盘
- 计算节点(从节点):4核CPU、16GB内存、100GB系统盘、1TB数据盘
磁盘方面有个经验:DataNode的数据目录,尽量用独立的挂载点,别把系统盘和数据盘混在一起。原因很简单,日志、临时文件、系统本身都会占据系统盘空间,一旦数据目录和系统盘共享,很容易出现磁盘被写满导致DataNode挂掉的问题。如果有多块数据盘,可以再拆成多个目录,配置里可以写多个路径。
内存方面有个容易忽略的点:NameNode的默认堆大小只有1GB。小文件稍微多起来,NameNode内存直接吃紧,整个集群卡成PPT的事我都碰上过。建议带数据目录的节点,物理内存16GB起步,并在配置里单独把NameNode、ResourceManager的堆内存调大,这个后面会详细说。
1.4 网络和交换机:别让千兆网卡拖后腿
这一点在规划阶段就要考虑,网络是Hadoop集群的真正瓶颈之一。Hadoop的MapReduce任务和数据读写,大部分时间都在数据节点之间的网络传输里。我见过一个集群,CPU和内存都没怎么跑满,就是网络带宽卡住,任务迟迟跑不完。所以有条件的话,局域网至少是千兆起步,最好数据节点之间直接用万兆内网互联。就算暂时没有万兆,也要确保所有节点在同一个二层网络里,避免跨网段的吞吐损失。
另外,交换机的端口配置也很关键。曾经在机房遇到过这样的问题:新加的几台机器明明是千兆网卡,但插在交换机上协商出来的速率只有百兆。后来一查,是网线质量不过关,换了一批之后速率直接上来了。所以硬件准备好之后,先做一次基础的端口速率确认,再开始装系统,能省掉后面不少排查时间。
2. 基础环境准备:能省的地方都别浪费
2.1 操作系统与JDK的匹配
Hadoop跑在Linux上是最常见的做法,CentOS、Ubuntu、各种不带桌面环境的服务器发行版都有人用,我自己的选择是CentOS 7.x及其后续兼容发行版,原因是资料多、团队熟、兼容性好。如果使用Ubuntu,也完全可以,但要注意防火墙命令、服务管理命令和CentOS有区别。
JDK这一步卡住很多新手。Hadoop 3.x系列目前官方支持Java 8和Java 11,但多数人的生产实践仍然以Java 8为主。重点:系统自带的OpenJDK版本可能和Hadoop要求不一致,最好单独下载安装指定版本。安装完之后一定要确认java -version和echo $JAVA_HOME输出正确。很多启动失败的奇葩问题,最后都定位到JAVA_HOME没配好。
提示:Hadoop的bin目录下有很多脚本,启动时会通过$JAVA_HOME找Java。如果没配JAVA_HOME,脚本会去PATH里找,一旦PATH里混了多个版本的Java,就容易踩坑。
2.2 SSH免密配置的完整顺序
集群里主节点要随时登录到各个从节点去拉起进程,所以主节点到所有节点的SSH免密是必需项。很多教程把这步写得很简单,但这里有个细节:免密登录要做的,是从主节点的hadoop用户,免密登录到主节点自己和所有从节点的hadoop用户。注意,主节点自己也要配,因为有些脚本会从主节点ssh到localhost执行。
实操顺序是:
- 在所有节点创建hadoop用户,并设置密码。
- 在主节点的hadoop用户下执行
ssh-keygen -t rsa -b 4096生成密钥对。 - 将公钥追加到所有节点(包括本机)的hadoop用户
~/.ssh/authorized_keys里。 - 逐台测试
ssh hadoop@主机名,确认不用输密码。
公钥分发可以用ssh-copy-id命令,也可以手动拼接。个别环境里ssh-copy-id没装,那就直接手工追加:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这里权限要特别注意,authorized_keys权限不对,SSH会拒绝免密登录,这个问题我在不少机器上遇到过。
2.3 主机名、hosts与全域统一的用户
集群里的主机名必须全局统一规划。我见过有人机器上全是localhost,结果一启动,namenode、datanode互相找不到对方。我的习惯是:主节点叫hadoop01,从节点叫hadoop02、hadoop03,三台全部写进/etc/hosts。这里有一个容易踩的坑:有些云平台有自己的hostname配置逻辑,改了/etc/hostname,重启后又变回去,需要到云平台的控制台里改实例名称,才能保持生效。
hosts文件里要注意,别塞进去一堆用不到的IP映射。尽量只保留本集群相关的记录,避免某些DNS解析异常导致连不上。
还有一个经常被忽略的点:hadoop用户、hadoop用户组、用户ID和组ID,在所有节点上必须保持一致。这个问题在单节点实验时不会暴露,但一旦DataNode进程在不同用户下启动,目录权限就会互相冲突,出现各种Permission denied。所以建用户时,建议直接用-u参数指定统一的UID,比如:
useradd -u 1001 -m hadoop2.4 防火墙、时钟与文件描述符
防火墙策略有两种做法:要么干脆关闭,要么精确放行端口。生产环境肯定要精确放行,学习环境先关闭,省得排查问题时分心。CentOS 7上使用systemctl stop firewalld,Ubuntu使用systemctl stop ufw。Hadoop用到的端口不少,粗略列一下:9000是NameNode的RPC端口,9870是NameNode的Web UI端口,9864是DataNode的Web端口,8088是ResourceManager的Web端口,19888有时候是历史任务服务器端口。真正常用的话,我会在主节点和从节点之间互相放行,省得来回折腾。
时钟同步这块,没做的话,集群任务调度时容易出现时间偏差,任务迟迟不提交。三步走:先装chrony或ntp,再配置上游时间源,最后设置开机自启。其实一个简单的方法,就是让所有节点和主节点做时间同步。
文件描述符,这个初学者不会想到。Hadoop集群里每个DataNode会打开大量文件句柄,默认的1024根本不够用。建议在/etc/security/limits.conf里把hadoop用户的nofile和nproc都调大:
hadoop soft nofile 65535 hadoop hard nofile 65535 hadoop soft nproc 65535 hadoop hard nproc 655352.5 数据目录规划与挂载建议
我建议所有节点的目录结构尽量一致,这样后续脚本和配置都好管理。比如统一用/data/dfs/name存放NameNode元数据,用/data/dfs/data存放DataNode数据块。特别注意:NameNode的元数据目录默认只写一份,丢了就很麻烦。如果要正经跑数据,建议给这个目录做定期备份,或者用单独的磁盘挂载。
目录创建后就涉及权限。所有Hadoop相关目录的属主必须改成hadoop用户,否则启动时还是会撞权限:
mkdir -p /data/dfs/name chown -R hadoop:hadoop /data这个步骤如果漏了,启动NameNode时会直接报权限不足,排查起来还容易被表象误导。
3. 核心配置逐段拆解:性能藏在这些参数里
3.1 配置文件全景
Hadoop的配置集中在$HADOOP_HOME/etc/hadoop目录下。核心要改的文件就四个:core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml。还有一个workers文件(老版本叫slaves),用来告诉集群哪些节点是DataNode和NodeManager。
在动手改配置之前,先把配置文件备份一份。改坏了大不了回滚,这个习惯能救急。我自己的习惯是快速重命名备份,比如cp core-site.xml core-site.xml.bak,改出问题就马上恢复。
3.2 core-site.xml:全局基础与服务地址
这个文件里最关键是fs.defaultFS,它决定了HDFS的访问入口,也就是NameNode所在位置。我的配置一般写成:
<property> <name>fs.defaultFS</name> <value>hdfs://hadoop01:9000</value> </property>9000是这个RPC通信端口,也可以用8020,关键是所有节点都要保持一致,别主节点写9000,从节点写8020,那样从节点根本找不到NameNode。
另一个常用的参数是hadoop.tmp.dir。如果不配,默认会往/tmp/hadoop-xxx里写临时文件。Linux的/tmp目录一旦被系统清理,整个集群的元数据就没了,这是很多“莫名其妙丢数据”事故的真凶。所以建议显式指定一个可靠目录:
<property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property>3.3 hdfs-site.xml:副本数、块大小、内存才是重点
这个文件是HDFS性能影响最直接的地方。我按优先级顺序说一下我的选择。
首先是副本数。默认是3,生产环境保持3没问题。如果只是测试,副本数改成2就能省不少磁盘。但要注意,副本数不要写1,测试环境里我吃过亏:某次DataNode异常下线,副本数为1的块直接全部丢失,整个目录不可访问,恢复成本极高。配置示例:
<property> <name>dfs.replication</name> <value>2</value> </property>其次是块大小。HDFS默认块大小是128MB。如果是大文件存储和批处理场景,我建议改成256MB。为什么?块越大,单个块能存放的数据越多,NameNode维护的元数据总量会下降,同时MapReduce处理一个块对应一个Map任务,块大一点,Map任务数量就少,调度开销也低。但针对大量小文件的场景,块大小反而没必要调大,小文件本身的元数据压力才是主要矛盾。所以块大小不是越大越好,是场景决定。
配置块大小的写法:
<property> <name>dfs.blocksize</name> <value>268435456</value> </property>这个值是字节单位,268435456按计算刚好是256MB。
然后是NameNode内存。设置地方不是hdfs-site.xml里的常规property,而是hadoop-env.sh里HADOOP_NAMENODE_OPTS或HADOOP_HEAPSIZE。举个实际例子,如果有1000万个文件块,NameNode大概需要2GB以上堆内存。我的经验是这样配:
export HADOOP_NAMENODE_OPTS="-Xmx8g -Xms8g" export HADOOP_DATANODE_OPTS="-Xmx4g -Xms4g"生产环境那种几十亿块文件的集群,NameNode分配更大。总之内存配置不能省,默认的1GB撑不了多少文件数。
3.4 yarn-site.xml:资源管理器与容器分配
YARN是负责资源调度和任务执行的。如果这里配不好,即使HDFS读写很快,任务照样排队卡死。
ResourceManager在hadoop01上,所以配置:
<property> <name>yarn.resourcemanager.hostname</name> <value>hadoop01</value> </property>再就是每台机器能给YARN多少资源。我习惯把物理内存的60%到70%留给YARN容器用,剩下的留给操作系统和DataNode等进程。比如物理内存16GB,我配置可用12GB。配置示例:
<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>12288</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>8192</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>2048</value> </property>maximum-allocation-mb控制单个任务最多能申请的内存,minimum控制最少。这两个值设置不合理,任务要么申请不到内存,要么一个任务把资源全抢走。
CPU资源也是类似的逻辑,用yarn.nodemanager.resource.cpu-vcores配置可用核数。如果机器有8核,我给YARN用7核,留1核给系统。
3.5 mapred-site.xml:计算框架与任务调优
这个文件控制MapReduce的运行方式。核心是:
<property> <name>mapreduce.framework.name</name> <value>yarn</value> </property>这行告诉MapReduce任务通过YARN调度。如果不写,默认会尝试本地运行,分布式任务直接不生效。
还有两个常见的调优入口:mapreduce.map.memory.mb和mapreduce.reduce.memory.mb,分别控制Map和Reduce任务容器的内存。我一般设2GB到4GB之间,太大了浪费,太小了任务容易OOM。比如:
<property> <name>mapreduce.map.memory.mb</name> <value>3072</value> </property> <property> <name>mapreduce.reduce.memory.mb</name> <value>4096</value> </property>这两个值都要小于yarn.scheduler.maximum-allocation-mb,否则资源申请会被拒绝。
3.6 workers文件与整个配置同步
在$HADOOP_HOME/etc/hadoop/workers文件中,一行写一个主机名。比如:
hadoop01 hadoop02 hadoop03主节点写不写自己,取决于你希望主节点要不要存数据。多一个DataNode就多一份存储与计算资源,我建议三节点集群把主节点也写上,让三台一起参与数据存储和计算。
配置写完后,需要把整个etc/hadoop目录同步到所有节点。最简单是用rsync或scp挨个同步:
rsync -avz $HADOOP_HOME/etc/hadoop/ hadoop02:$HADOOP_HOME/etc/hadoop/ rsync -avz $HADOOP_HOME/etc/hadoop/ hadoop03:$HADOOP_HOME/etc/hadoop/同步完成以后,记得在每台机器上都执行source /etc/profile之类的操作,确保环境变量统一。
4. 启动与验证:第一次成功跑起来
4.1 格式化NameNode:一步只准做一次的操作
HDFS在第一次启动之前,必须先格式化NameNode,也就是在namenode目录里生成初始元数据。命令在hadoop01上执行:
hdfs namenode -format这一步需要注意,格式化是高度危险的动作。如果集群已经正常跑起来,再执行一次格式化,会把旧的元数据清掉,整个HDFS的文件索引就没了。所以线上哪怕反复格式化都要小心翼翼,确认目录里没有重要数据再执行。
格式化以后会看到日志里有successfully formatted之类的信息,然后检查一下配置的namenode数据目录是否生成了current目录。如果没生成,多半是目录权限或路径配置不对。
4.2 启动HDFS与YARN
启动顺序是先启动HDFS,再启动YARN,没有严格强制顺序,但惯例如此。脚本位置在$HADOOP_HOME/sbin下。
在hadoop01上执行:
start-dfs.sh start-yarn.sh启动之后,用jps命令检查进程。主节点hadoop01上应该看得到NameNode、SecondaryNameNode、ResourceManager三个进程;从节点hadoop02、hadoop03上应该看得到DataNode和NodeManager。
jps是最快的验证手段,但它显示的进程名和实际位置经常对不上,所以我还会补充用hdfs dfsadmin -report检查集群状态。这个命令会列出所有DataNode的地址、存储容量和状态,一目了然。
4.3 Web UI验证
Hadoop 3.x里NameNode的Web界面地址是http://hadoop01:9870,YARN的资源管理界面是http://hadoop01:8088。
第一次打开NameNode Web界面,重点看两个指标:一个是Live Nodes数量,正常应等于集群DataNode总数;另一个是存储容量,和管理员预期一致就没问题。如果Live Nodes数少了,说明有DataNode没起来,去对应机器上看日志。
为什么强调Web UI?因为jps只能看到进程在跑,但进程可能处于半死不活的状态。比如DataNode和NameNode之间心跳丢了,进程还在,但集群存储却不健康,这时候只有Web UI和dfsadmin才能看出来。
4.4 用put和get做第一次数据读写测试
启动完成后,在HDFS里创建一个测试目录,再上传一个文件验证读写。比如:
hdfs dfs -mkdir -p /user/hadoop/test hdfs dfs -put /etc/hosts /user/hadoop/test/ hdfs dfs -ls /user/hadoop/test/如果看到文件列出来,说明集群基本可用。再试一次下载:
hdfs dfs -get /user/hadoop/test/hosts /tmp/hosts_download对比原始文件和下载文件的内容,一致就OK。
接着跑一个WordCount测试任务,这是MapReduce的HelloWorld。我在Hadoop的share目录里找一个自带jar来运行:
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /user/hadoop/test/hosts /user/hadoop/test/output看到输出目录里有_SUCCESS文件,说明整个MapReduce链路通顺了。
5. 常见报错与排障心得
5.1 NameNode起不来:先看日志,再看格式化次数
NameNode启动失败,最常见的原因是namenode目录里已经有数据,但HDFS没正常关闭过,导致元数据日志和快照不一致。这时候不要急着重新格式化,先去看日志文件名是hadoop-hadoop-namenode-主机名.log,位置在$HADOOP_HOME/logs下。常见的一个错误是NameNode is not formatted,说明目录为空,确认没有旧数据后格式化即可。
排障原则:改动越大越要谨慎。我遇到过有人反复格式化,把整个集群的元数据全冲掉了,损失比配置错误大得多。所以任何有破坏性的操作,先确认目录、备份、再动手。
5.2 DataNode连不上NameNode:多半是hosts或端口问题
DataNode启动后,会尝试连接配置文件中的NameNode地址。如果连不上,日志里会看到Connection refused之类的报错。第一步检查hdfs-site.xml里NameNode地址在所有节点是否一致,第二步检查防火墙有没有放行9000端口,第三步用telnet hadoop01 9000或者nc -vz hadoop01 9000看端口通不通。
还有一种情况:DataNode能连上,但很快被移除,原因往往是namenode和datanode的clusterID不一致。这是因为有人单独格式化过DataNode,或者用了拷贝来的数据目录。解决办法很简单,找到各节点data目录里的VERSION文件,把clusterID改成与NameNode一致。改完重启DataNode。
5.3 资源不足与任务卡死:YARN内存配置失衡
任务提交后一直ACCEPTED,怎么都不调度,十有八九是YARN的可用内存少于任务申请内存。排查思路:看ResourceManager的Web UI,看看Active Node们的可用资源是多少。然后对照yarn-site.xml的三组内存参数检查。一个核心逻辑是:任务容器内存必须落在scheduler.min和max之间,并能被可用资源整除,否则一个任务都提交不出去。
这类问题还有一个隐藏坑:NodeManager进程起来了,可用内存也很多,但任务仍然排队。这就要看CPU资源,如果vcores配少了,内存够了但CPU不足,照样排队。所以配置时内存和CPU要一起看。
5.4 磁盘写满与副本丢失:续命指南
大数据集群最怕磁盘写满。DataNode默认会持续接收数据,某个磁盘一旦满了,相关副本写入失败,NameNode开始把数据块标记为缺失,集群进入安全模式。遇到这种情况,第一件事是看df -h找出最满的磁盘,把不需要的大文件清理掉或转移走,等磁盘正常后再观察副本状态。不要一上来就重启DataNode,重启只会让写满的磁盘压力更大。
副本丢失时使用:
hdfs fsck / -files -blocks检查具体丢块情况。如果文件不重要,删了腾空间;如果重要,等磁盘空间恢复后,用hdfs balancer触发再平衡。
5.5 排障速查表
| 现象 | 优先排查方向 |
|---|---|
| NameNode启动失败 | 日志、namenode目录、格式化状态 |
| DataNode启动后消失 | clusterID、hosts、防火墙端口 |
| 任务一直ACCEPTED | YARN内存/CPU配置、NodeManager资源 |
| 上传速度极慢 | 网络协商速率、副本策略、块大小 |
| 磁盘空间很快耗尽 | 副本数、回收站、大文件清理策略 |
这张表不是圣旨,但覆盖了我这几年遇到的大部分低频问题。真遇到没见过的错,优先看日志文件,日志里写了95%的答案。
我在最后一次搭建这套环境时,最大的体会是:别把搭建集群当成一条命令链,而是当成一个系统工程。从选型、规划、目录、配置,每一步都带着后续运维的视角去过一遍,后面维护起来会舒服很多。平时有人问我配置怎么填,我反倒会问他打算跑什么数据、有多少节点、磁盘多大——参数没有最优,只有适合当前场景。这也是这个系列第一篇想传递的核心。
下一篇我准备专门写高可用与性能调优的实战记录,包括NameNode的HA方案、DataNode多目录存储策略、以及结合真实任务做的资源参数调整。如果你现在也卡在启动、报错或者资源分配的某个环节,可以把这篇文章里的步骤先对照着走一遍,很多问题其实是规划阶段埋下的雷。