上一篇文章写了如何在腾讯轻量云服务器上把基础环境跑通,从购买实例到 JDK 配置、SSH 免密登录、目录规划,算是把“地基”打好了。这一篇直接进入正题,围绕“大数据项目实战”真正的内容:在轻量云上部署 HDFS、YARN、Spark、Hive 这一整套大数据核心组件,把集群跑起来,并且能正常提交一个离线统计任务。整个过程我会把每个关键操作、踩坑点和验证方式都写清楚。
1. 集群部署规划与服务器配置选型
1.1 轻量云服务器的资源配置思路
先交代一下我手头的机器情况。用的是腾讯轻量云服务器,CPU 2 核、内存 4GB、带宽 5Mbps,系统盘 50GB 标准 SSD,数据盘额外挂载了一块 80GB 的云硬盘。这个配置放在生产环境里不值一提,但做大数据实战学习、跑项目原型、甚至支撑小规模的数据处理任务,完全够用。
大数据组件对内存的消耗是目前最大的瓶颈,尤其是 HDFS NameNode、YARN ResourceManager、Hive Metastore 这些角色,JVM 堆内存一般要预留 1GB 到 2GB 才能跑得流畅。所以我在规划角色分配的时候,把内存占用大的进程分开部署,避免所有进程堆在一台机器上导致频繁 GC,甚至 OOM。
我这里没有用三台机器搭真正的分布式集群,而是在一台轻量云上采用“伪分布式 + 多进程”模式:HDFS 的 NameNode 和 DataNode 在同一台机器,YARN 的 ResourceManager 和 NodeManager 也在同一台机器,其他组件按角色叠加部署。这样做的好处是:
- 单机部署能理清每个组件的角色边界,排查问题更直观;
- 腾讯轻量云 4GB 内存足够支撑所有进程同时运行;
- 后续如果要对标分布式集群,只需把角色拆到多台机器,配置几乎不需要大改。
做过大数据生产环境的人可能会说,单机伪分布式和真正的分布式集群差距很大,这点我承认。但对一个实战项目来说,关键不是机器数量,而是把组件怎么协作、怎么配置、怎么提交任务这些核心链路跑通。
1.2 用户、目录与系统参数规划
目录规划沿用第一篇的约定,统一放在 /data 下,这样后续扩容和管理都方便:
- 软件安装目录:
/data/soft - 数据存储目录:
/data/disk1 - 日志目录:
/data/logs - 临时目录:
/data/tmp
创建专属用户 bigdata,避免直接用 root 跑大数据服务。大数据组件以 root 身份运行会有各种权限问题,而且一旦误操作删了不该删的目录影响面太大。我的习惯是单独建用户,把软件目录和数据目录的属主都改成这个用户。
部署前还需要调整几个关键的系统参数:
bash复制# 修改文件句柄数限制
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
echo "* soft nproc 65535" >> /etc/security/limits.conf
echo "* hard nproc 65535" >> /etc/security/limits.conf
# 关闭防火墙(内网环境测试用)
systemctl stop firewalld
systemctl disable firewalld
# 关闭 SELinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
文件句柄数和进程数不过调大的话,HDFS 在大量小文件场景下会疯狂报 “Too many open files”,这个坑我第一跑的时候就踩过,提前调好省得后面来回折腾。
1.3 组件版本选型与兼容性说明
目前用的组件版本如下:
| 组件 | 版本 | 说明 |
|---|---|---|
| JDK | 1.8.0_202 | Hadoop 生态兼容性最好的版本 |
| Hadoop | 3.3.4 | HDFS + YARN + MapReduce |
| Spark | 3.3.0 | 使用 pre-built for Hadoop 3.3+ 版本 |
| Hive | 3.1.3 | Metastore + HiveServer2 |
| MySQL | 8.0.x | 存储 Hive 元数据 |
| ZooKeeper | 3.7.1 | 可选,用于 HA 和高阶特性 |
版本这事情看起来简单,实际上是个大坑。Hadoop 3.3.x 有多个小版本,Spark 3.3.0 默认构建是基于 Hadoop 3.3.1,我一开始图省事用了 Hadoop 3.3.6,结果 Spark 和 Hadoop 的 RPC 协议在个别接口上不兼容,提交任务时总是报类找不到。后来统一降级到 3.3.4 之后,所有问题都消失了。建议装 Hadoop 生态组件时,不要盲目追新,选一个生态里大家普遍验证过的版本组合最重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础组件安装与配置实战
2.1 数据盘挂载与格式化
腾讯云轻量服务器购买后,数据盘默认是未格式化、未挂载的状态。先把这块盘搞定,否则后面 HDFS 的存储目录没法落地。
bash复制# 查看磁盘分区情况
fdisk -l
# 对 /dev/vdb 进行分区(按 n、p、1、回车、回车、w 的流程走)
fdisk /dev/vdb
# 格式化分区
mkfs.ext4 /dev/vdb1
# 挂载到 /data/disk1
mkdir -p /data/disk1
mount /dev/vdb1 /data/disk1
# 开机自动挂载
echo '/dev/vdb1 /data/disk1 ext4 defaults 0 0' >> /etc/fstab
这里有个细节:挂载数据盘的路径最好在安装组件之前就定好,因为后面 HDFS 的 dfs.datanode.data.dir 和 dfs.namenode.name.dir 都要指定到这个路径。如果你装完 Hadoop 再挂盘,就得去改配置然后重启 HDFS,虽然也能做,但没必要多这一趟折腾。
2.2 JDK 8 安装与环境变量配置
JDK 的安装本身不难,难的是和各个组件的兼容性确认。Hadoop 3.x 至今对 Java 8 的支持最稳定,Spark 3.3 官方文档明确支持 Java 8/11/17,但实际跑起来调度 YARN 应用时,Java 8 的坑最少。
bash复制cd /data/soft
tar -zxvf jdk-8u202-linux-x64.tar.gz
mv jdk1.8.0_202 jdk8
然后编辑 /etc/profile 添加环境变量:
bash复制export JAVA_HOME=/data/soft/jdk8
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
我只把 JDK 装在系统层面,每个组件(Hadoop、Spark、Hive)内部不再单独带 JDK。这样的话 JDK 升级只改一处,组件配置里的 JAVA_HOME 统一指过来即可。
2.3 SSH 免密登录配置(含单机回环)
单机部署也需要配置 SSH 免密登录,因为 Hadoop 的 start-dfs.sh 脚本会通过 SSH 连接 localhost 来启动远程进程,如果不做免密,每次启动都要输密码,脚本根本没法用。
bash复制# 生成密钥对(一路回车即可)
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
# 将公钥写入 authorized_keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
# 修改权限
chmod 600 ~/.ssh/authorized_keys
# 验证免密登录
ssh localhost
在轻量云上有一个常见的坑:如果你用公网 IP 去 SSH 免密登录,云厂商的安全组策略可能会拦截,所以集群内部通信地址要用内网 IP 或主机名。 我把 /etc/hosts 里加了这么一行:
bash复制127.0.0.1 vm-server
所有组件的配置里,只要涉及本机地址的地方,统一用 vm-server 这个主机名,不使用公网 IP。这样无论从内部通信还是后续安全配置角度,都是更合理的做法。
3. Hadoop 3.3.4 集群部署全流程
3.1 核心配置文件详解
Hadoop 的配置集中在 /data/soft/hadoop-3.3.4/etc/hadoop/ 目录下,所有配置项都为纯 XML 格式。我没有用 Hadoop 默认配置直接跑,因为默认参数在轻量云这种低配机器上会频繁触发内存问题。
先看 core-site.xml:
xml复制<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://vm-server:9820</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/data/tmp/hadoop</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>vm-server:2181</value>
</property>
</configuration>
fs.defaultFS 是 HDFS 的入口地址,客户端基本都靠这个属性找到 NameNode。hadoop.tmp.dir 用来存放 NameNode 的元数据临时文件和 DataNode 的块数据临时文件,这里默认是 /tmp,在轻量云上系统盘太小,容易写满,我改到数据盘上。
然后是 hdfs-site.xml:
xml复制<configuration>
<property>
<name>dfs.namenode.name.dir</name>
<value>/data/disk1/hdfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/data/disk1/hdfs/data</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.handler.count</name>
<value>20</value>
</property>
</configuration>
dfs.replication=1 是伪分布式的关键,如果你在单机环境配了默认值 3,DataNode 会不停报 “There are X missing blocks”,因为块副本复制不出 3 份。这一项改完,报错立刻消失。
yarn-site.xml 是资源调度的核心,这里我踩了不少坑,配置如下:
xml复制<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>vm-server</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>2048</value>
</property>
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>2</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>2048</value>
</property>
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>128</value>
</property>
</configuration>
aux-services 这个配置是 MapReduce 任务 Shuffle 阶段的支撑,漏配的话跑 MR 任务会直接报 “Shuffle handler not found”。资源设置上,我建议把 NodeManager 可用内存设置为机器内存的一半左右,留一半给操作系统、HDFS 和其他组件。4GB 内存的机器,NodeManager 给 2GB 比较合适,全给 YARN 进程会把系统内存吃光,触发内核 OOM Killer。
mapred-site.xml 设置 MapReduce 的运行时框架:
xml复制<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=/data/soft/hadoop-3.3.4</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/data/soft/hadoop-3.3.4</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/data/soft/hadoop-3.3.4</value>
</property>
</configuration>
最后这个 env 配置也很关键,如果不指定 HADOOP_MAPRED_HOME,提交 MR 任务时子进程找不到 Hadoop 的 classpath,会直接报类路径错误,很多新手在这里卡半天原因不明。
hadoop-env.sh 里还要改一下 JVM 内存参数,默认的 HADOOP_HEAPSIZE 是 1000,对于 NameNode 有点偏低,我改成 2048:
bash复制export HADOOP_HEAPSIZE=2048
3.2 NameNode 格式化与启动过程
所有配置文件都放好之后,第一件要做的事情是格式化 NameNode,拿到集群的初始元数据:
bash复制cd /data/soft/hadoop-3.3.4
bin/hdfs namenode -format
格式化成功会输出带 successfully formatted 字样,然后才能启动。这里提醒一句:不要重复格式化,每次格式化会把之前 HDFS 上所有数据清空。 我一开始为了测试,格式化了两三次,结果发现之前上传的文件全没了,只能重新上传,白白浪费时间。
启动顺序也有讲究,先起 HDFS,再起 YARN:
bash复制sbin/start-dfs.sh
sbin/start-yarn.sh
启动后通过 jps 命令确认进程是否都在:
bash复制jps
# 输出示例:
# 12345 NameNode
# 12346 DataNode
# 12347 SecondaryNameNode
# 12348 ResourceManager
# 12349 NodeManager
如果缺少任意一个进程,去 /data/logs/hadoop/ 目录下看对应角色的日志。
然后打开 Web UI 验证:
- HDFS 管理界面:
http://<公网IP>:9870 - YARN 管理界面:
http://<公网IP>:8088
注意:腾讯云轻量服务器默认安全组会拦截这些端口,需要在控制台的安全组规则里放行 9870、8088 这些端口,否则浏览器访问不了。我列一下端口规划,方便对照放行:
| 端口 | 组件 | 用途 |
|---|---|---|
| 9820 | HDFS | NameNode RPC |
| 9870 | HDFS | NameNode Web UI |
| 9864 | HDFS | DataNode Web UI |
| 8088 | YARN | ResourceManager Web UI |
| 8030/8031/8032 | YARN | ResourceManager RPC |
| 8042 | YARN | NodeManager Web UI |
| 10000 | Hive | HiveServer2 JDBC |
| 9083 | Hive | Metastore 服务 |
| 8080 | Spark | Spark Web UI |
| 7077 | Spark | Spark Standalone Master |
| 2181 | ZooKeeper | 客户端连接端口 |
3.3 HDFS 基本操作验证
先创建测试目录:
bash复制hdfs dfs -mkdir -p /user/bigdata/input
hdfs dfs -ls /
上传一个文件测试:
bash复制echo "hello hadoop" > test.txt
hdfs dfs -put test.txt /user/bigdata/input/
hdfs dfs -cat /user/bigdata/input/test.txt
如果这些命令都能正常执行,说明 HDFS 的读写链路已经通了。我每次搭建完都习惯先跑这一套最基本的验证,确认客户端到 NameNode、DataNode 的数据链路没有问题,再继续往上装组件。
3.4 跑一个 MapReduce 自带的 WordCount
Hadoop 自带了一个 wordcount 例子,先跑它来验证 YARN 调度链路:
bash复制hadoop jar /data/soft/hadoop-3.3.4/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.4.jar wordcount /user/bigdata/input/test.txt /user/bigdata/output/wc
跑完查看结果:
bash复制hdfs dfs -cat /user/bigdata/output/wc/part-r-00000
提交任务后要去 YARN 的 8088 页面看 Application 的执行状态,确认是 SUCCEEDED 还是 FAILED。如果失败,最常见的错误是内存不足,需要在 YARN 页面里看具体是哪个 Container 被 kill 了,然后调整 yarn.nodemanager.resource.memory-mb 或者 MapReduce 作业的内存配置。
4. Spark 3.3.0 部署与 Hive 集成
4.1 Spark 本地目录与配置
Spark 解压后需要改两个配置文件:spark-env.sh 和 spark-defaults.conf。
spark-env.sh 配置 Spark 运行环境:
bash复制export JAVA_HOME=/data/soft/jdk8
export SPARK_HOME=/data/soft/spark-3.3.0
export SPARK_MASTER_HOST=vm-server
export SPARK_MASTER_PORT=7077
export SPARK_WORKER_CORES=2
export SPARK_WORKER_MEMORY=2g
export HADOOP_CONF_DIR=/data/soft/hadoop-3.3.4/etc/hadoop
spark-defaults.conf 配置 Spark 默认提交方式:
bash复制spark.master yarn
spark.eventLog.enabled true
spark.eventLog.dir hdfs://vm-server:9820/spark-logs
spark.serializer org.apache.spark.serializer.KryoSerializer
spark.driver.memory 1g
spark.executor.memory 1g
spark.executor.cores 1
使用 spark.master=yarn 模式,Spark 客户端会把任务提交到 YARN 上,由 ResourceManager 分配资源,由 NodeManager 启动 Executor。这种模式不用单独启动 Spark Standalone 集群,整个资源调度统一走 YARN,比较符合真实项目的使用习惯。
注意要先在 HDFS 上创建 Spark 日志目录:
bash复制hdfs dfs -mkdir -p /spark-logs
4.2 Spark 提交任务运行测试
写一个最简单的 Spark Scala 应用测试:
scala复制import org.apache.spark.sql.SparkSession
object WordCount {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.appName("WordCount")
.getOrCreate()
val sc = spark.sparkContext
val rdd = sc.textFile(args(0))
val counts = rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
counts.saveAsTextFile(args(1))
spark.stop()
}
}
也可以直接用 Spark 自带的 spark-shell 验证环境:
bash复制spark-shell --master yarn --deploy-mode client
进入 shell 后执行:
scala复制sc.parallelize(1 to 10).filter(_ % 2 == 0).sum()
能出来结果说明 Spark on YARN 模式已经跑通了。我在实际使用中,Spark on YARN 模式下最常遇到的问题就是 Executor 启动失败,大概率是资源分配超过 NodeManager 可用内存,把 spark.executor.memory 调低一些就能解决。
4.3 集成 Hive 作为数据仓库
Hive 的部署重点在于元数据管理。这里我选择用 MySQL 存储 Hive 的元数据库,而不是 Hive 自带的 Derby,因为 Derby 只支持单会话连接,跑起来限制太多,改 MySQL 之后多个客户端并发访问就不会有问题了。
先安装 MySQL:
bash复制# Ubuntu 系统
apt install mysql-server
# CentOS 系统
yum install mysql-server
然后创建 Hive 元数据库和专用用户:
mysql复制CREATE DATABASE hive_metastore CHARACTER SET utf8mb4;
CREATE USER 'hive'@'%' IDENTIFIED BY 'Hive@123';
GRANT ALL PRIVILEGES ON hive_metastore.* TO 'hive'@'%';
FLUSH PRIVILEGES;
接着配置 Hive 的 hive-site.xml:
xml复制<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://vm-server:3306/hive_metastore?useSSL=false&characterEncoding=UTF-8</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>hive</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>Hive@123</value>
</property>
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
</property>
<property>
<name>hive.metastore.schema.verification</name>
<value>false</value>
</property>
<property>
<name>hive.server2.thrift.bind.host</name>
<value>vm-server</value>
</property>
<property>
<name>hive.server2.thrift.port</name>
<value>10000</value>
</property>
</configuration>
MySQL 8.x 的 JDBC 驱动类名是 com.mysql.cj.jdbc.Driver,和 MySQL 5.x 的 com.mysql.jdbc.Driver 不一样,很多人在这里会搞混。安装驱动的时候,把 mysql-connector-java-8.0.x.jar 放到 Hive 的 lib 目录下。
初始化 Hive 元数据库:
bash复制cd /data/soft/hive-3.1.3
bin/schematool -dbType mysql -initSchema
初始化成功后,启动 Metastore 和 HiveServer2:
bash复制nohup bin/hive --service metastore > /data/logs/hive/metastore.log 2>&1 &
nohup bin/hive --service hiveserver2 > /data/logs/hive/hiveserver2.log 2>&1 &
然后通过 beeline 连接:
bash复制bin/beeline -u jdbc:hive2://vm-server:10000 -n bigdata
建表测试:
sql复制CREATE TABLE test(id INT, name STRING);
INSERT INTO test VALUES (1, 'hello');
SELECT * FROM test;
能正常查询就说明 Hive 和 MySQL 元数据链路已经打通。
4.4 Spark 读取 Hive 表的配置
默认情况下 Spark 读不到 Hive 表,需要在 spark-defaults.conf 里加上 Hive 的支持:
bash复制spark.sql.warehouse.dir=hdfs://vm-server:9820/user/hive/warehouse
spark.sql.catalogImplementation=hive
javax.jdo.option.ConnectionURL=jdbc:mysql://vm-server:3306/hive_metastore?useSSL=false&characterEncoding=UTF-8
javax.jdo.option.ConnectionDriverName=com.mysql.cj.jdbc.Driver
javax.jdo.option.ConnectionUserName=hive
javax.jdo.option.ConnectionPassword=Hive@123
另外需要把 mysql-connector-java-8.0.x.jar 也复制到 Spark 的 jars 目录下,否则 Spark 无法连接 MySQL 元数据库,启动 SparkSession 时会报 “Failed to connect to metastore”。
5. 完整离线分析任务实践
5.1 任务场景与数据准备
前面的环境都通了之后,我用一个真实的离线分析任务来验证整体链路。假设现在有一份用户访问日志,每行格式是:
code复制用户ID,访问页面,访问时长(秒),访问时间
先手动造一批测试数据:
bash复制hdfs dfs -mkdir -p /data/input/log
cat > /tmp/user_visit.log <<EOF
1001,/index,30,2024-01-01 10:00:00
1002,/product/123,120,2024-01-01 10:05:00
1001,/cart,45,2024-01-01 10:10:00
1003,/search?q=iphone,90,2024-01-01 10:15:00
1002,/order,200,2024-01-01 10:20:00
1001,/index,15,2024-01-01 10:25:00
EOF
hdfs dfs -put /tmp/user_visit.log /data/input/log/
5.2 使用 Spark SQL 做统计分析
创建 Spark SQL 代码:
bash复制cd /data/soft/spark-3.3.0
bin/spark-sql \
--master yarn \
--driver-memory 1g \
--executor-memory 1g \
--executor-cores 1 \
-e "
CREATE TABLE IF NOT EXISTS user_visit_log (
user_id INT,
page STRING,
duration INT,
visit_time STRING
) USING text
LOCATION '/data/input/log';
SELECT
page,
COUNT(*) AS visit_cnt,
ROUND(AVG(duration), 2) AS avg_duration
FROM user_visit_log
GROUP BY page
ORDER BY visit_cnt DESC;
"
执行结果正常的话,就能看到每个访问页面的访问次数和平均停留时长。这个任务链路包含了:
- Spark 启动 Application 申请资源;
- 从 HDFS 读取文件;
- 用 Spark SQL 完成数据解析和聚合计算;
- 结果通过 YARN 日志或直接终端打印返回。
5.3 使用 Spark SQL 加载 Hive 表做统计
刚才那张表只是让 Spark 直接读文件,现在我把它注册成 Hive 表,再通过 Spark 做复杂分析:
sql复制CREATE TABLE IF NOT EXISTS user_visit_hive (
user_id INT,
page STRING,
duration INT,
visit_time TIMESTAMP
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
LOAD DATA INPATH '/data/input/log/user_visit.log' INTO TABLE user_visit_hive;
SELECT user_id, COUNT(*) AS visit_cnt FROM user_visit_hive GROUP BY user_id;
这一步做完,实际上就完成了 Hive 建表、HDFS 数据 Load、Spark 分析的完整闭环。在面试中经常被问到的“数仓是怎么分层、怎么把 HDFS 文件映射成表的”这个点,也在这里体现得比较清楚。
6. 轻量云环境下的大数据性能优化与踩坑记录
6.1 内存优化的关键策略
4GB 内存的机器跑大数据全家桶,内存是最好的优化方向。我总结了几个核心优化点:
第一,限制 JVM 堆大小。每个 Hadoop 服务的 JVM 堆大小由 HADOOP_HEAPSIZE 控制,Hive 的 Metastore 和 HiveServer2 也有自己的内存参数。比如 Hive 的服务端内存可以这样限制:
bash复制export HIVE_HEAPSIZE=1024
export HADOOP_HEAPSIZE=2048
所有 JVM 堆加起来不要超过物理内存的 60% 到 70%,否则系统内存被吃光后,内核会随机 kill 进程,表现就是某个服务莫名挂掉。
第二,YARN 内存分配必须控制。yarn.nodemanager.resource.memory-mb 设 2GB,yarn.scheduler.maximum-allocation-mb 设 2048MB,yarn.scheduler.minimum-allocation-mb 设 128MB。容器申请内存时如果超过 NodeManager 可用大小,就会一直处于 ACCEPTED 状态,然后立刻失败。
第三,关闭不需要的组件。大数据生态组件很丰富,但不是每个都需要落地。我在轻量云上没有启动 MapReduce 的 JobHistory Server,也不需要 HDFS HA 的 JournalNode,轻装上阵,把资源留给真正用的组件。
6.2 常见错误速查表
这里把我这两周实践过程中遇到的高频问题整理成一张速查表,方便以后巡检时对照:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| NameNode 启动后秒退 | dfs.namenode.name.dir 目录权限不对或没有格式化 |
检查目录属主,执行 hdfs namenode -format |
| DataNode 报 “There are X missing blocks” | dfs.replication 未改为 1 |
单机环境把副本数改为 1 |
| YARN 任务一直卡在 ACCEPTED | 容器内存超过 NodeManager 可用内存 | 调小 yarn.scheduler.maximum-allocation-mb |
| Spark Executor 启动失败 | Executor 内存 + Overhead 超过 NodeManager 分配 | 调小 spark.executor.memory,加上 spark.executor.memoryOverhead=512 |
| Hive 初始化报 Schema 错误 | Hive 版本和数据库驱动版本不匹配 | 使用相同版本的 schematool 和 MySQL 驱动 |
| Spark 读不到 Hive 表 | 缺少 Hive 配置或 MySQL 驱动没有放到 Spark jars 目录 | 在 spark-defaults.conf 配置 Hive,并添加驱动 |
| 8088/9870 打不开 | 腾讯云安全组未放行 | 控制台放行相关端口 |
6.3 轻量云磁盘空间管理
轻量云的数据盘空间有限,我遇到过 HDFS 空间写满导致集群停摆的情况。这里建议开启 HDFS 的回收站功能,避免误删数据后无法恢复,也便于快速清理:
xml复制<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
加入这段配置后,使用 hdfs dfs -rm 删除的文件会进入 /user/<username>/.Trash 目录,1440 分钟后才会被真正清理。日常清理时别急着往回收站删,先看下当前空间占用:
bash复制hdfs dfs -du -h /data/input/
如果确实需要腾空间,可以用:
bash复制hdfs dfs -rm -r /data/input/log
6.4 日志检查的最佳实践
大数据组件的问题排查,90% 的答案都在日志里。我的习惯是给每个组件建独立的日志目录,然后统一查看。
| 组件 | 日志路径 |
|---|---|
| Hadoop | /data/logs/hadoop/ |
| YARN | /data/logs/hadoop/yarn/ |
| Spark | /data/logs/spark/ |
| Hive | /data/logs/hive/ |
排查问题的标准流程是:
jps查看进程是否存活,确认没有进程后直接看对应服务日志;- 如果进程存在但功能异常,去 YARN Web UI 看 ApplicationMaster 日志;
- 如果是 SQL 任务失败,重点看 Spark Driver 的 stderr 日志;
- 如果是数据文件读写失败,先去 HDFS Web UI 看 DataNode 是否健康。
这里给一个我自己反复使用的日志观察命令:
bash复制tail -f /data/logs/hadoop/hadoop-bigdata-namenode-vm-server.log
通过实时追踪日志,基本能把问题定位到具体组件,再针对性去改配置,比瞎猜高效得多。
7. 项目经验总结与后续演进方向
这一套环境从裸机到跑通首个离线任务,前后花了两天左右,中间大部分时间都耗在版本兼容性和内存参数调整上。如果你也想在腾讯轻量云上搭建一套大数据实战环境,我给几个比较现实的经验:
第一,配置一上来就必须规划好。 很多新手喜欢先把 Hadoop 默认配置跑起来,出了问题才去看配置项。结果默认配置在低配机器上跑一次崩一次,根本不知道是环境问题还是配置问题。正确的做法是:先把内存分配、目录规划、主机名都定好,再照着配置文件逐项核对。
第二,每个组件跑通后再做下一步。 不要一次性把 Hadoop、Spark、Hive、ZooKeeper 全部装完再启动。我的顺序是:HDFS → YARN → MapReduce 测试 → Spark on YARN → Hive → Spark + Hive 整合。每一步都有明确的验证手段,出了问题能立刻判断是哪一层的问题。
第三,云服务器的安全组是隐形坑。 自建机房环境下,内网部署很少遇到端口问题,但腾讯轻量云上所有服务端口默认都是关闭的,要自己放行。很多人在本地明明一切正常,部署到云端后 Web UI 访问不了,就是安全组的锅。
后续如果想要把这套环境扩展成更完整的大数据平台,可以从这几个方向入手:
- 增加节点数量,把 NameNode 和 DataNode 分离到不同机器,实现真正的分布式;
- 引入 ZooKeeper + JournalNode,为 NameNode 和 ResourceManager 配置高可用;
- 引入 Flink,做实时流处理场景;
- 引入 DolphinScheduler 或 Airflow,做任务调度编排;
- 引入 HBase 或 ClickHouse,做 OLTP/OLAP 场景的扩展。
大数据这个方向,学习阶段最重要的就是亲手把环境搭一遍,把各种报错都见识一遍,你的理解深度会远超只看文档的状态。腾讯轻量云这种低配服务器,反而能逼着你把资源规划、内存优化这些细节想明白——换到生产环境的机器上,这些经验就是你的核心竞争力。
