
很多人在学习 Hadoop 时会遇到同一个问题资料多但乱课程多但散跟着某个教程复现又总在环境配置上卡壳。这篇内容按一套从零到实战的 Hadoop 课程路线来整理把环境准备、伪分布式搭建、集群扩展、HA 高可用、distcp 数据迁移、课程设计案例和常见面试题串起来目标是既理解原理也能动手验证。学完这部分内容你应该能独立完成一次 Hadoop 伪分布式安装能看懂集群配置的核心项能编写并运行一个简单的 MapReduce 程序也能回答面试中高频出现的 HDFS 读写、MapReduce 流程和 Hadoop 生态问题。1. Hadoop 到底解决什么问题1.1 从单机存储到分布式存储传统业务中数据量还在 GB 级别时一台服务器足够处理。但当数据增长到 TB、PB 级别单机的硬盘容量、内存大小和 CPU 算力都会成为瓶颈而且单机一旦宕机数据丢失风险很高。Hadoop 解决的核心问题有两个一是海量数据的可靠存储二是海量数据的分布式计算。它把数据分散存放在多台普通服务器上通过副本机制保证数据不丢再把计算任务拆分到数据所在节点上执行减少网络传输提升吞吐量。1.2 Hadoop 生态中的核心组件Hadoop 生态经过多年发展已经非常庞大但课程学习中必须先抓住三个基础组件。HDFSHadoop Distributed File System负责分布式存储。它由 NameNode 管理元数据DataNode 存储实际数据块SecondaryNameNode 辅助合并元数据镜像。客户端读写数据时先和 NameNode 交互再与 DataNode 传输数据。YARNYet Another Resource Negotiator负责集群资源管理和任务调度。ResourceManager 管理全局资源NodeManager 管理单节点资源ApplicationMaster 负责具体应用的任务调度。MapReduce 是分布式计算编程模型。它把计算拆成 Map 和 Reduce 两个阶段Map 阶段负责过滤、转换、分组Reduce 阶段负责聚合、汇总。虽然现在很多业务直接用 Spark、Flink但 MapReduce 是理解分布式计算思想的基础。1.3 为什么课程学习要动手搭一遍只看理论很容易产生一种错觉我会用 Hadoop 了。实际上Hadoop 课程中的安装配置、进程启动、日志排查、参数调整只有动手做一遍才能形成体感。伪分布式搭建是成本最低、收益最高的起点它只需要一台虚拟机或云服务器就能模拟 NameNode、DataNode、ResourceManager、NodeManager 的完整启动过程也能跑通第一个 MapReduce 作业。2. 课程学习路线与环境准备2.1 学习路线设计建议按照以下顺序推进理解 HDFS 架构和读写原理。在虚拟机上完成单机版 Hadoop 安装。配置 SSH 免密完成伪分布式搭建。编写并运行 WordCount 等示例程序。扩展为 3 节点集群观察数据块分布。学习 NameNode HA 高可用和 ZooKeeper 协调机制。学习 distcp、Hive、HBase 等生态工具。结合课程设计题目做一个小项目。每一个阶段都要带着问题去验证例如数据到底存在哪里为什么 DataNode 不能只有一个ResourceManager 挂了作业还能跑吗2.2 操作系统与 JDK 准备Hadoop 是 Java 语言开发的运行环境必须有 JDK。课程学习中推荐使用 Linux 系统常见选择是 CentOS 7、Ubuntu 18.04 及以上版本或者直接在本地 Windows 上安装 VMware/VirtualBox 虚拟机。虚拟机配置建议 2 核 CPU、4GB 内存、40GB 硬盘。内存太小会导致 NameNode 或 NodeManager 启动缓慢甚至 OOM。JDK 版本需要和 Hadoop 版本匹配。Hadoop 3.x 通常使用 JDK 8 或 JDK 11安装后配置环境变量。# 查看 JDK 是否安装 java -version # 编辑 /etc/profile 添加环境变量 export JAVA_HOME/usr/local/jdk export PATH$PATH:$JAVA_HOME/bin配置完成后执行 source /etc/profile 使其生效。这里要特别说明版本需要根据你的项目实际情况调整学习环境不必追求最新版稳定兼容比功能新更重要。2.3 Hadoop 版本选择与下载课程学习建议选择 Hadoop 3.x 稳定版本。Hadoop 3.x 相比 2.x 引入了基于容器的资源隔离、支持多 NameNode 联邦、默认端口调整等变化比如 NameNode Web UI 端口从 50070 变为 9870。下载 Hadoop 有两种常见方式一是从 Apache 官方镜像站下载二进制压缩包二是使用国内镜像站加速下载。下载后解压到指定目录建议路径中不要包含中文和空格。# 解压 Hadoop 到 /usr/local tar -zxvf hadoop-3.x.x.tar.gz -C /usr/local mv /usr/local/hadoop-3.x.x /usr/local/hadoop # 创建数据目录 mkdir -p /usr/local/hadoop/tmp mkdir -p /usr/local/hadoop/namenode mkdir -p /usr/local/hadoop/datanode然后编辑 /etc/profile 添加 Hadoop 环境变量。export HADOOP_HOME/usr/local/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin执行 hadoop version 能正常输出版本信息说明基础环境已经就绪。3. Hadoop 伪分布式搭建实战伪分布式是 Hadoop 课程中最重要的一步。所谓伪分布式就是在一台物理机上同时运行 NameNode、DataNode、ResourceManager、NodeManager 等多个进程模拟真实集群的角色分工。它既能验证配置正确性又不需要多台机器。3.1 配置 SSH 免密登录Hadoop 启动和停止时需要通过 SSH 登录到各个节点执行命令。虽然伪分布式只有一台机器但依然建议配置本机到本机的免密登录避免每次启动都要输入密码。# 生成密钥对 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如果 SSH 连接仍然要求输入密码检查当前用户是否为 root、/root/.ssh 目录权限是否为 700以及防火墙是否拦截了 22 端口。3.2 修改 Hadoop 核心配置Hadoop 的配置集中在 $HADOOP_HOME/etc/hadoop 目录下。最关键的配置文件有 core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml 和 hadoop-env.sh。首先修改 hadoop-env.sh设置 JAVA_HOME。# 文件路径/usr/local/hadoop/etc/hadoop/hadoop-env.sh export JAVA_HOME/usr/local/jdk export HADOOP_HOME/usr/local/hadoop配置 core-site.xml指定文件系统默认地址。!-- 文件路径/usr/local/hadoop/etc/hadoop/core-site.xml -- configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/usr/local/hadoop/tmp/value /property /configurationfs.defaultFS 定义了 HDFS 的入口地址。hadoop.tmp.dir 是 NameNode 和 DataNode 存放元数据、数据块的根目录课程中建议单独指定避免使用默认的 /tmp 目录被系统清理。配置 hdfs-site.xml设置副本数和 NameNode 的 HTTP 地址。!-- 文件路径/usr/local/hadoop/etc/hadoop/hdfs-site.xml -- configuration property namedfs.replication/name value1/value /property property namedfs.namenode.name.dir/name value/usr/local/hadoop/namenode/value /property property namedfs.datanode.data.dir/name value/usr/local/hadoop/datanode/value /property property namedfs.namenode.http-address/name value0.0.0.0:9870/value /property /configuration伪分布式只有一个 DataNode副本数必须设置为 1否则数据块会一直处于未复制状态。NameNode 和 DataNode 目录如果未提前创建启动时会自动创建。配置 yarn-site.xml启用 MapReduce Shuffle。!-- 文件路径/usr/local/hadoop/etc/hadoop/yarn-site.xml -- configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.nodemanager.env-whitelist/name valueJAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_HOME,PATH,LANG,TZ/value /property /configurationyarn.nodemanager.aux-services 是 NodeManager 提供的辅助服务MapReduce 作业需要 mapreduce_shuffle 来完成 Map 端数据混洗。配置缺失会导致作业在 Reduce 阶段卡住或直接失败。配置 mapred-site.xml。!-- 文件路径/usr/local/hadoop/etc/hadoop/mapred-site.xml -- configuration property namemapreduce.framework.name/name valueyarn/value /property /configurationmapreduce.framework.name 指定 MapReduce 运行框架为 YARN。如果不配置默认会使用 local 模式作业会在本地进程运行而不是提交到 YARN 集群。3.3 初始化与启动验证首次启动 HDFS 前需要对 NameNode 做格式化。格式化会初始化文件系统的元数据相当于创建一块空白的“目录索引”。# 格式化 NameNode hdfs namenode -format格式化成功后启动 HDFS 和 YARN。# 启动 HDFS start-dfs.sh # 启动 YARN start-yarn.sh启动后使用 jps 命令查看进程。jps伪分布式配置正确时至少应看到以下进程NameNodeDataNodeResourceManagerNodeManager如果 SecondaryNameNode 存在说明 HDFS 默认启动了辅助节点。接下来访问 Web UI 验证。 NameNode Web UI 地址http://虚拟机IP:9870 ResourceManager Web UI 地址http://虚拟机IP:8088在浏览器中打开后能看到 DataNode 状态、存储容量和活跃节点数说明 HDFS 已经正常运行。再跑一个官方示例验证 MapReduce 可用。# 创建 HDFS 输入目录 hdfs dfs -mkdir -p /input # 上传本地文件 echo hello hadoop hello world words.txt hdfs dfs -put words.txt /input # 运行 WordCount hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /input /output # 查看结果 hdfs dfs -cat /output/part-r-00000命令中的 /output 必须是不存在的目录否则 MapReduce 会报错“Output directory already exists”。输出结果应为每个单词出现的次数。4. 从伪分布式到集群搭建伪分布式跑通后下一步就是搭建真正的 Hadoop 集群。课程设计中常用 3 节点集群来模拟生产环境角色分配可以参考下面的规划。4.1 集群规划节点角色node1NameNode、ResourceManagernode2DataNode、NodeManagernode3DataNode、NodeManager也可以把 SecondaryNameNode 放在 node2 或 node3 上。生产环境通常会单独规划节点把 NameNode 和 ResourceManager 部署在不同机器避免单点资源争用。集群搭建前所有节点必须能够互相访问hosts 文件要配置主机名映射。# 所有节点执行 vim /etc/hosts 192.168.1.101 node1 192.168.1.102 node2 192.168.1.103 node34.2 关键配置差异集群配置和伪分布式类似但需要把 localhost 替换为 node1并调整副本数。core-site.xml 中 fs.defaultFS 改为 hdfs://node1:9000。hdfs-site.xml 中 dfs.replication 设置为 2同时把 NameNode 数据目录和 DataNode 数据目录指向独立磁盘目录。还需要编辑 workers 文件列出所有 DataNode 主机名。# 文件路径/usr/local/hadoop/etc/hadoop/workers node1 node2 node3在 Hadoop 3.x 中workers 文件替代了旧的 slaves 文件。start-dfs.sh 会读取该文件在所有列出的节点上启动 DataNode。4.3 集群启动注意事项集群启动顺序有讲究先启动 ZooKeeper如果配置了 HA再启动 HDFS最后启动 YARN。第 2、3 节点需要提前安装 Hadoop 并同步配置确保 JRE 版本一致。如果 DataNode 启动失败最常见原因是第 2、3 节点的 DataNode 存储目录中已经存在旧的 clusterID而它们连接的 NameNode 是新格式化的。解决方法是删除所有节点上的 NameNode 目录和 DataNode 目录重新格式化或者手动修改 clusterID 保持一致。不要在生产环境随意格式化这是一个高危操作会导致所有数据元数据丢失。5. Hadoop HA 高可用与 ZooKeeper 整合5.1 为什么需要 HA在普通集群中NameNode 是单点。如果 NameNode 宕机HDFS 客户端将无法读写文件整个集群不可用。为了提升可用性Hadoop 2.x 开始引入了 NameNode HA 机制。HA 集群中同时存在两个 NameNodeActive NameNode 负责对外提供服务Standby NameNode 实时同步元数据状态。当 Active 节点故障时Standby 节点可以快速切换为 Active继续提供服务。5.2 ZooKeeper 在 HA 中的作用NameNode 切换需要解决两个问题两个 NameNode 之间如何同步元数据以及多个节点如何决定谁是 Active。元数据同步通过 JournalNodes 实现。Active NameNode 会把编辑日志实时写入 JournalNode 集群Standby NameNode 从 JournalNode 读取日志并应用到内存中保证元数据基本实时一致。Active/Standby 的选举通过 ZooKeeper 完成。两个 NameNode 在 ZooKeeper 中创建同一个临时节点谁创建成功谁就是 Active。ZooKeeper 故障时 NameNode 进入 SafeMode不会自动完成切换。所以HA 高可用可以简化为ZooKeeper 负责选主JournalNode 负责元数据同步ZKFC 负责监控和触发切换。ZKFC 是 ZooKeeper Failover Controller随 NameNode 一起启动定期发送健康检查。5.3 HA 部署核心思路HA 集群需要额外部署 ZooKeeper 集群和 JournalNode。课程实验中可以在三台节点上各部署一个 ZooKeeper 和 JournalNode。关键的 HA 配置项包括配置项含义dfs.nameservicesNameService 名称例如 myclusterdfs.ha.namenodes.mycluster两个 NameNode 的 IDdfs.namenode.rpc-address.mycluster.nn1第一个 NameNode 的 RPC 地址dfs.namenode.http-address.mycluster.nn1第一个 NameNode 的 HTTP 地址dfs.namenode.shared.edits.dirJournalNode 地址列表dfs.client.failover.proxy.provider.mycluster客户端故障转移代理类dfs.ha.automatic-failover.enabled是否启用自动故障转移ha.zookeeper.quorumZooKeeper 服务器列表HA 配置完成后启动顺序通常为# 在所有节点启动 ZooKeeper zkServer.sh start # 在 Active NameNode 初始化 HA 状态 hdfs zkfc -formatZK # 启动 HDFS start-dfs.sh通过 Web UI 可以看到两个 NameNode 的状态其中一个是 Active另一个是 Standby。手工模拟 Active NameNode 宕机后Standby 会在几十秒内自动切换为 Active。6. distcp 数据迁移与常用参数6.1 distcp 是什么distcp 是 Hadoop 自带的分布式数据复制工具。它可以跨集群、跨目录复制大批量数据底层基于 MapReduce 并行执行。相比普通的 hdfs dfs -cpdistcp 更适合海量文件迁移、数据备份和集群替换场景。6.2 基础用法最简单的用法是指定源目录和目标目录。hadoop distcp hdfs://node1:9000/user/data/access.log hdfs://node2:9000/user/backup/access.log如果要复制整个目录直接指定目录路径即可。hadoop distcp hdfs://node1:9000/user/data/logs hdfs://node2:9000/user/backup/logsdistcp 会为文件创建 Map 任务默认启动的 Map 数量由文件数决定。执行时可以加上 -m 参数限制并发数。6.3 常用参数解析参数作用-m指定最大并发 Map 任务数-overwrite覆盖目标目录中已存在的文件-update只复制源中新增或修改过的文件-delete删除目标目录中源目录没有的文件-skipcrccheck跳过 CRC 校验-bandwidth限制单个 Map 任务的复制带宽单位 MB/s-p保留文件属性如权限、时间戳、块大小-strategy动态或静态复制策略-diff基于快照的增量复制课程实验中最常用的是 -update 和 -m。hadoop distcp -update -m 10 hdfs://node1:9000/user/data hdfs://node2:9000/user/backup使用 distcp 时要注意跨集群复制需要两个集群的端口互通如果数据量非常大建议先用 -m 1 测试连通性再逐步提高并发复制过程中不要同时修改源目录否则可能产生不一致快照。7. 基于 Hadoop 的课程设计案例日志统计分析课程设计题目经常是“基于 Hadoop 的某某分析”。这里给出一个经典的入门案例分析 Nginx 访问日志统计每个 IP 的访问次数。通过这个案例可以完整练习 Mapper、Reducer、打包、提交、运行全流程。7.1 案例目标与分析假设 access.log 中每行记录一次访问请求格式如下192.168.1.10 - - [12/Jan/2025:10:00:01 0800] GET /index.html HTTP/1.1 200 1024需求是统计每个 IP 的出现次数。Map 阶段输入是日志文件的每一行输出键为 IP 地址值为 1。Reduce 阶段把相同 IP 对应的值累加输出 IP 和访问次数。7.2 Mapper 与 Reducer 实现创建一个 Java Maven 项目在 pom.xml 中引入 Hadoop 依赖。如果不想用 Maven也可以直接使用 Hadoop 安装目录下的 share/hadoop/common 和 share/hadoop/mapreduce 目录中的 jar 包。!-- 文件路径pom.xml -- dependencies dependency groupIdorg.apache.hadoop/groupId artifactIdhadoop-client/artifactId version3.x.x/version /dependency /dependenciesMapper 类代码如下// 文件路径src/main/java/com/example/log/IPMapper.java import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; public class IPMapper extends MapperObject, Text, Text, IntWritable { private final static IntWritable one new IntWritable(1); private Text word new Text(); Override protected void map(Object key, Text value, Context context) throws IOException, InterruptedException { String line value.toString(); String[] fields line.split( ); if (fields.length 0) { word.set(fields[0]); context.write(word, one); } } }Reducer 类代码如下// 文件路径src/main/java/com/example/log/IPReducer.java import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class IPReducer extends ReducerText, IntWritable, Text, IntWritable { private IntWritable result new IntWritable(); Override protected void reduce(Text key, IterableIntWritable values, Context context) throws IOException, InterruptedException { int sum 0; for (IntWritable val : values) { sum val.get(); } result.set(sum); context.write(key, result); } }还需要一个 Job 提交入口类// 文件路径src/main/java/com/example/log/LogAnalysisJob.java import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class LogAnalysisJob { public static void main(String[] args) throws Exception { if (args.length ! 2) { System.err.println(Usage: LogAnalysisJob input path output path); System.exit(2); } Configuration conf new Configuration(); Job job Job.getInstance(conf, IP Access Count); job.setJarByClass(LogAnalysisJob.class); job.setMapperClass(IPMapper.class); job.setCombinerClass(IPReducer.class); job.setReducerClass(IPReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }这里把 Reducer 同时设置为 Combiner可以在 Map 端先做一次局部聚合减少网络传输数据量对日志统计这类求和任务非常有效。7.3 打包与运行使用 Maven 打包。mvn clean package -DskipTests将生成的 jar 包上传到 Hadoop 集群节点把日志文件放到 HDFS。# 上传日志 hdfs dfs -mkdir -p /input hdfs dfs -put access.log /input # 提交作业 hadoop jar log-analysis-1.0-SNAPSHOT.jar com.example.log.LogAnalysisJob /input /output # 查看结果 hdfs dfs -cat /output/part-r-00000输出结果形如192.168.1.10 5 192.168.1.12 3到这里一个最简单的课程设计案例就完成了。实际课程设计中可以在此基础上扩展统计 URL 访问量、统计状态码分布、指定时间窗口等思路都是类似的在 Mapper 中提取对应字段在 Reducer 中聚合统计。8. 高频面试题与排错清单8.1 面试高频问题Hadoop 相关的课程考试和面试中以下问题出现频率很高。HDFS 写入流程客户端向 NameNode 发起写请求NameNode 检查权限和可用空间返回可用的 DataNode 列表。客户端将数据分包写入第一个 DataNode再由第一个 DataNode 复制到第二个依次完成副本复制。写完一个数据块后继续写下一个全部完成后关闭输出流。HDFS 读取流程客户端向 NameNode 请求文件元数据NameNode 返回文件的块列表及所在 DataNode 地址。客户端就近读取第一个块如果本地没有副本则从网络读取。多个块会并行读取读完后合并为完整文件。MapReduce 执行流程MapReduce 作业经过 InputFormat 切片、Map 阶段、Shuffle 阶段、Reduce 阶段和输出阶段。Shuffle 阶段包括分区、排序、合并、拷贝是影响作业性能的关键。数据倾斜的原因和处理方式数据倾斜通常是因为某个 key 的数量远大于其他 key导致单个 Reduce 任务处理耗时过长。解决思路包括增加 Reduce 数量、对 key 加盐做二次聚合、调整分区器、使用 Combine 提前聚合等。小文件问题小文件会导致 NameNode 元数据膨胀、Map 任务数量过多、作业调度开销变大。解决办法包括使用 CombineTextInputFormat 合并输入、用 Hive 或 spark 定期的合并小文件、控制落盘文件大小。8.2 常见搭建错误与排查问题现象常见原因解决思路jps 看不到 NameNode未格式化或启动日志报错查看 logs 目录下的 hadoop-hadoop-namenode-*.logDataNode 进程不存在clusterID 不一致删掉 DataNode 目录并重新启动或手动统一 clusterID9870 端口无法访问防火墙未放行或 NameNode 未启动检查防火墙、hosts、core-site.xml 配置MapReduce 作业卡住不动内存不足或 Shuffle 配置缺失检查 yarn.nodemanager.aux-services 和 JVM 参数输出目录已存在安全机制不允许覆盖输出换一个输出路径或先删除旧目录SSH 免密不生效权限不对或公钥未写入检查 authorized_keys 权限和目录权限上报“java.net.ConnectException: Connection refused”目标节点进程未启动确认对应端口进程存在检查网络连通性排查时要养成看日志的习惯。Hadoop 日志位于 $HADOOP_HOME/logs 目录文件命名中包含进程名例如 hadoop-hadoop-namenode-node1.log。报错信息往往比桌面提示更准确。9. 最佳实践与后续学习建议9.1 工程化建议学习阶段配置可以怎么简单怎么写但一旦进入课程设计或生产环境就要养成工程化习惯。配置管理方面所有 HDFS、YARN 配置必须经过版本管理避免随意手工修改。集群中每台节点的配置要同步维护最好使用脚本统一分发。日志和监控方面启动 Hadoop 后要主动查看日志而不是只看 Web UI 的绿色状态。课程设计中可以加入指标采集例如统计作业执行时间、查看 Map 和 Reduce 的耗时分布。安全方面不要在 root 用户下长期运行集群建议创建独立用户 hadoop按最小权限原则授权。NameNode 格式化是不可逆操作执行前必须确认数据已经备份。数据保障方面即使是学习环境也要养成定期备份元数据的习惯。大规模数据迁移时优先使用 distcp而不是手工复制因为 distcp 支持断点续传、增量同步和限速控制。9.2 继续深入的方向Hadoop 本身是生态的基石走完这条课程路线后可以根据目标继续进阶。如果偏数据分析可以学习 Hive把 SQL 翻译成 MapReduce大幅降低数据统计门槛。如果偏实时计算可以学习 Flink 和 Spark Streaming。如果偏存储可以学习 HBase理解列式存储和键值模型。如果做大集群运维则需要继续深入研究 YARN 调度器、HDFS 联邦、Ranger 权限控制等。不管选择哪个方向Hadoop 课程阶段建立的“分布式思想”都会成为继续学习的基础数据副本怎么保证可靠性任务怎么拆解并行节点挂了怎么做故障恢复。这些原理在 Spark、Flink、Kafka 中依然适用。如果这篇文章对你有帮助可以收藏备用。搭建过程中如果遇到奇怪的报错欢迎在评论区带上日志信息一起交流。