☰
Windows IDEA连接伪分布式Hadoop实战指南
2026/10/2 1:13:22 网站建设 项目流程

简介:本资源是一份面向高校大数据课程学习者与Hadoop初学者的Java版MapReduce实战实验报告,聚焦气象数据分析场景,解决分布式环境下最大值计算与数据分区输出的核心实践问题。文档以完整实验流程为主线,涵盖CentOS 7+Hadoop 2.7.7+JDK 1.8环境配置、气象数据FTP下载与HDFS上传、Map端温度清洗(含正负号处理及异常值+9999过滤)、Reduce端月度最高温提取、自定义双分区器(1–6月/7–12月分离输出)及jar包打包部署全流程,附详细调试技巧与排错建议。资源为单个Word文档(.doc),大小765KB,结构清晰,含实验目的、环境、代码逻辑解析、命令行验证截图说明及指导教师评语栏,便于对照复现与教学参考。目前已有190人学习下载,适合需要从理论到集群实操闭环掌握MapReduce编程范式的入门者。

1. 这不是“写个Java类就能跑通MapReduce”的实验报告:它是一份能让你在Windows IDEA里连上伪分布式Hadoop、写出可调试的Mapper/Reducer、提交作业到YARN并看懂日志堆栈的实战手记

你手头这份标题叫《Hadoop大数据处理技术-java操作MapReduce(实验报告完整版).doc》的文档,大概率是高校课程实验或企业内训材料——但别急着复制粘贴交差。真实场景里,90%的“Java操作MapReduce”翻车点根本不在算法逻辑,而在:Windows下IDEA找不到hadoop.dll、本地运行时抛No FileSystem for scheme: hdfs、提交到YARN后ApplicationMaster直接失败却只报Exit code: 1、甚至job.waitForCompletion(true)卡死无响应。这不是Java基础不牢,而是Hadoop生态的“环境契约”没签好。本文不讲MapReduce抽象模型,不画流程图,只聚焦一个目标:用纯Java代码,在你自己的Windows笔记本上,从零配置伪分布式Hadoop环境,写出可断点调试的WordCount,提交到YARN并拿到正确输出结果。适合正在赶课设、准备大数据开发岗面试、或刚接手遗留Hadoop任务的工程师——所有步骤经实测(Hadoop 3.3.6 + JDK 11 + IDEA 2023.3),命令、路径、参数全部带版本锚点,避坑点直指日志里最常出现的5行错误堆栈。


2. 环境筑基:Windows下IDEA连伪分布式Hadoop的三道生死门

伪分布式模式(Pseudo-Distributed Mode)是Hadoop学习的黄金起点:它用单机模拟HDFS+YARN集群行为,既避开真集群的运维复杂度,又保留完整的RPC通信、资源调度和容错机制。但Windows与Hadoop的兼容性,是横在Java开发者面前的第一道墙。核心矛盾在于:Hadoop原生依赖Linux系统调用(如fork进程、stat文件属性),而Windows需通过Cygwin或MinGW模拟,但现代Hadoop已弃用Cygwin;更现实的解法是——用Windows Subsystem for Linux(WSL2)跑Hadoop服务端,IDEA在Windows层写Java客户端,通过HDFS URI和YARN ResourceManager地址通信。这是目前最稳定、最接近生产环境的本地开发范式。

2.1 WSL2中部署Hadoop伪分布式(Hadoop 3.3.6 + JDK 11)

提示:不要在Windows原生CMD/PowerShell里装Hadoop!微软官方已明确标注WSL2对Hadoop 3.x支持完善,且避免了hadoop.dll缺失、路径分隔符混乱等玄学问题。

# 在WSL2 Ubuntu 22.04中执行(确保已安装OpenJDK 11) sudo apt update && sudo apt install -y openjdk-11-jdk wget https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz tar -xzf hadoop-3.3.6.tar.gz -C /opt/ sudo chown -R $USER:$USER /opt/hadoop-3.3.6 export HADOOP_HOME=/opt/hadoop-3.3.6 export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

关键配置文件修改(全部位于$HADOOP_HOME/etc/hadoop/):

  • core-site.xml:定义默认文件系统为HDFS

    <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> </configuration>
  • hdfs-site.xml:设置NameNode和DataNode存储路径(务必用WSL2绝对路径)

    <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/opt/hadoop-3.3.6/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/opt/hadoop-3.3.6/data/datanode</value> </property> </configuration>
  • mapred-site.xml:指定MapReduce运行框架为YARN

    <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>
  • yarn-site.xml:配置ResourceManager地址和NodeManager内存

    <configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>localhost</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> </configuration>

启动服务前格式化NameNode:

hdfs namenode -format

启动HDFS和YARN:

start-dfs.sh && start-yarn.sh

验证服务状态(在WSL2中执行):

jps # 应看到 NameNode, DataNode, ResourceManager, NodeManager, SecondaryNameNode hdfs dfs -ls / # 应返回空目录列表,证明HDFS可读写

2.2 Windows IDEA中配置Hadoop Java客户端:绕过hadoop.dll的终极方案

IDEA在Windows上直接调用Hadoop Java API时,会尝试加载hadoop.dll(用于本地模式文件操作),但Hadoop 3.x已移除该DLL编译支持。强行放置旧版DLL会导致UnsatisfiedLinkError。正确做法是:彻底禁用本地模式,强制走HDFS Client协议。

在IDEA项目中添加Maven依赖(pom.xml):

<dependencies> <!-- Hadoop Client核心包 --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.3.6</version> </dependency> <!-- 日志桥接,避免SLF4J绑定冲突 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.36</version> </dependency> </dependencies>

关键:在Java代码中显式设置Configuration,关闭本地文件系统自动探测:

import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; public class HdfsClientTest { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); // 强制使用HDFS协议,禁用file://协议 conf.set("fs.defaultFS", "hdfs://localhost:9000"); // 关键!禁用本地模式,避免寻找hadoop.dll conf.set("fs.file.impl", "org.apache.hadoop.fs.LocalFileSystem"); conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); FileSystem fs = FileSystem.get(conf); System.out.println("Connected to HDFS: " + fs.getUri()); fs.close(); } }

参数说明:fs.file.impl设为LocalFileSystem看似矛盾,实则是Hadoop的“协议路由”机制——当URI为hdfs://时,fs.hdfs.impl生效;设此值仅为防止Configuration自动fallback到Windows本地实现。若不设,FileSystem.get(conf)可能静默返回RawLocalFileSystem,导致后续hdfs dfs -ls命令失效。

2.3 网络穿透:WSL2与Windows的端口映射与防火墙放行

WSL2使用虚拟网络,其localhost与Windows主机localhost不互通。Hadoop服务监听0.0.0.0:9000(HDFS)和0.0.0.0:8088(YARN Web UI),但Windows无法直接访问。需手动映射端口:

在Windows PowerShell(管理员权限)中执行:

# 查看WSL2 IP地址 wsl -d Ubuntu-22.04 -e bash -c "ip addr show eth0 | grep 'inet ' | awk '{print \$2}' | cut -d/ -f1" # 假设输出为 172.28.123.45,则映射端口 netsh interface portproxy add v4tov4 listenport=9000 listenaddress=127.0.0.1 connectport=9000 connectaddress=172.28.123.45 netsh interface portproxy add v4tov4 listenport=8088 listenaddress=127.0.0.1 connectport=8088 connectaddress=172.28.123.45 netsh interface portproxy add v4tov4 listenport=8032 listenaddress=127.0.0.1 connectport=8032 connectaddress=172.28.123.45 # YARN RM端口

注意:每次WSL2重启IP会变,需重新执行映射。可将上述命令写入Windows批处理脚本,配合WSL2启动触发。

验证Windows端连通性:

# 在Windows CMD中执行 telnet localhost 9000 # 应连接成功 curl http://localhost:8088 # 应返回YARN Web UI HTML

3. Java MapReduce编码实战:从WordCount到可调试的Job提交链

MapReduce不是“写两个类就完事”,而是一条完整的作业生命周期:Client提交 → ResourceManager分配Container → NodeManager拉起ApplicationMaster → AM调度Map/Reduce Task → Task读取HDFS数据 → 输出结果回写HDFS。Java代码必须精准控制每个环节的参数,否则作业会在任意节点失败。

3.1 标准WordCount的Mapper与Reducer实现(Hadoop 3.x API)

Hadoop 3.x废弃了org.apache.hadoop.mapred.*包(旧API),必须使用org.apache.hadoop.mapreduce.*包(新API)。旧API在YARN上无法获取正确计数器,且与Hadoop 3.x的Shuffle机制不兼容。

// WordCountMapper.java import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; import java.util.StringTokenizer; public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 按空格分割,忽略标点(生产环境应使用正则) String line = value.toString().replaceAll("[^a-zA-Z\\s]", ""); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken().toLowerCase()); context.write(word, one); // 输出 <word, 1> } } }
// WordCountReducer.java import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result); // 输出 <word, sum> } }

逻辑说明:Mapper接收<offset, line>,按空格切词转小写后输出<word, 1>;Reducer聚合相同key的value,求和后输出<word, count>。Context对象是MapReduce的“生命线”,所有I/O、计数器、状态更新都通过它完成。

3.2 Job驱动类:控制作业全流程的12个关键参数

Job对象是MapReduce的总控中心。以下代码是经过生产环境验证的最小可行配置,覆盖95%的本地调试需求:

// WordCountDriver.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; import java.io.IOException; public class WordCountDriver { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); // 1. 强制使用YARN框架(非本地模式) conf.set("mapreduce.framework.name", "yarn"); // 2. 指定ResourceManager地址(对应WSL2映射的8032端口) conf.set("yarn.resourcemanager.hostname", "localhost"); conf.set("yarn.resourcemanager.port", "8032"); // 3. 设置HDFS默认地址(对应WSL2映射的9000端口) conf.set("fs.defaultFS", "hdfs://localhost:9000"); // 4. 关键!禁用推测执行(本地调试时易导致Task重复执行) conf.setBoolean("mapreduce.map.speculative", false); conf.setBoolean("mapreduce.reduce.speculative", false); // 5. 设置Map/Reduce内存(匹配WSL2中yarn-site.xml的2048MB) conf.set("mapreduce.map.memory.mb", "1024"); conf.set("mapreduce.reduce.memory.mb", "1024"); // 6. 设置JVM堆内存(避免OutOfMemoryError) conf.set("mapreduce.map.java.opts", "-Xmx800m"); conf.set("mapreduce.reduce.java.opts", "-Xmx800m"); // 7. 设置输入/输出路径(必须是HDFS路径,非本地文件) String inputPath = "hdfs://localhost:9000/input/wordcount"; String outputPath = "hdfs://localhost:9000/output/wordcount_" + System.currentTimeMillis(); Job job = Job.getInstance(conf, "word-count"); job.setJarByClass(WordCountDriver.class); // 8. 设置Mapper/Reducer类 job.setMapperClass(WordCountMapper.class); job.setReducerClass(WordCountReducer.class); // 9. 设置Map输出类型(必须与Mapper的outputKeyClass/outputValueClass一致) job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); // 10. 设置最终输出类型 job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); // 11. 设置输入/输出路径(HDFS路径) FileInputFormat.addInputPath(job, new Path(inputPath)); FileOutputFormat.setOutputPath(job, new Path(outputPath)); // 12. 提交作业并等待完成(true表示阻塞等待) boolean success = job.waitForCompletion(true); System.exit(success ? 0 : 1); } }

参数说明:

  • mapreduce.framework.name=yarn:强制走YARN调度,而非本地JVM(local模式)。
  • yarn.resourcemanager.port=8032:YARN ResourceManager的IPC端口(非Web UI的8088)。
  • mapreduce.map.speculative=false:关闭推测执行,避免本地调试时Task被重复启动。
  • mapreduce.map.memory.mb=1024:Map Task容器内存上限,必须≤WSL2中yarn.nodemanager.resource.memory-mb(2048)。
  • inputPath和outputPath必须是hdfs://开头的URI,不能是file:///或相对路径,否则作业提交后Task会因找不到文件而失败。

3.3 数据准备与作业提交:HDFS文件上传与路径校验

在WSL2中创建输入文件并上传至HDFS:

# 创建本地测试文件 echo "hello world hello hadoop" > /tmp/input.txt echo "hadoop is great" >> /tmp/input.txt # 上传到HDFS(路径必须与Job中inputPath一致) hdfs dfs -mkdir -p /input/wordcount hdfs dfs -put /tmp/input.txt /input/wordcount/ hdfs dfs -ls /input/wordcount # 验证文件存在

在IDEA中运行WordCountDriver.main()。首次运行会触发YARN ApplicationMaster启动,耗时约10-20秒。成功后,HDFS中/output/wordcount_171xxxxxx目录下生成part-r-00000文件。

查看输出结果:

hdfs dfs -cat /output/wordcount_171xxxxxx/part-r-00000 # 输出示例: # hadoop 2 # hello 2 # is 1 # world 1 # great 1

调试技巧:在WordCountMapper.map()和WordCountReducer.reduce()中加断点,IDEA可直接调试Mapper/Reducer逻辑(需确保Job未设置job.setJarByClass(...)指向打包JAR,而是直接运行类)。


4. 避坑指南:5个让90%新手卡住的日志错误与根治方案

MapReduce作业失败时,YARN Web UI(http://localhost:8088)和Hadoop日志是唯一真相来源。以下是本地开发中最常遇到的5个错误,按现象→原因→解决逐条拆解,每条均来自真实调试记录。

4.1 现象:Application application_171xxxxxx_xxxx failed 2 times due to AM Container for appattempt_171xxxxxx_xxxx exited with exitCode: 1

原因:ApplicationMaster(AM)容器启动失败。常见于:

  • yarn.nodemanager.resource.memory-mb设置过小(如1024),而AM默认申请1536MB内存;
  • mapreduce.map.java.opts中-Xmx值超过NodeManager可用内存;
  • WSL2内存不足(默认仅分配50%物理内存,需在.wslconfig中调整)。

解决:

  1. 在WSL2中检查NodeManager内存:yarn node -list -all,确认Resource列显示<2048:0>;
  2. 修改yarn-site.xml,将yarn.nodemanager.resource.memory-mb设为3072;
  3. 在.wslconfig(Windows用户目录下)添加:
    [wsl2] memory=4GB swap=2GB
  4. 重启WSL2:wsl --shutdown,再wsl启动。

4.2 现象:java.lang.RuntimeException: java.lang.ClassNotFoundException: Class WordCountMapper not found

原因:YARN NodeManager无法加载Mapper类。根源是:

  • Job.setJarByClass()指向的类不在Hadoop Classpath中;
  • IDEA未将依赖JAR打包进Job JAR(job.setJar("path/to/job.jar")未设置);
  • Hadoop配置中mapreduce.application.classpath未包含IDEA输出的classes目录。

解决:

  1. 在IDEA中:File → Project Structure → Artifacts → + → JAR → From modules with dependencies,勾选WordCountDriver模块及所有依赖;
  2. 构建JAR后,在WordCountDriver.java中显式设置:
    job.setJar("D:/workspace/hadoop-demo/target/hadoop-demo-1.0-SNAPSHOT.jar");
  3. 或更简单:在WSL2中用hadoop jar命令提交(跳过IDEA Classpath问题):
    hadoop jar /mnt/d/workspace/hadoop-demo/target/hadoop-demo-1.0-SNAPSHOT.jar \ WordCountDriver \ hdfs://localhost:9000/input/wordcount \ hdfs://localhost:9000/output/wordcount_$(date +%s)

4.3 现象:org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /input/wordcount/input.txt could only be replicated to 0 nodes instead of minReplication (=1)

原因:HDFS DataNode未启动或磁盘空间不足。jps中缺少DataNode进程,或/opt/hadoop-3.3.6/data/datanode目录为空/只读。

解决:

  1. 检查DataNode日志:tail -100f $HADOOP_HOME/logs/hadoop-*-datanode-*.log;
  2. 常见错误Cannot create directory /opt/hadoop-3.3.6/data/datanode/current→ 手动创建并赋权:
    mkdir -p /opt/hadoop-3.3.6/data/datanode/current sudo chown -R $USER:$USER /opt/hadoop-3.3.6/data
  3. 重启DataNode:hadoop-daemon.sh start datanode。

4.4 现象:java.net.ConnectException: Call From DESKTOP-XXXXX/192.168.1.100 to localhost:9000 failed on connection exception: java.net.ConnectException: Connection refused

原因:Windows无法访问WSL2的9000端口。netsh portproxy未生效,或WSL2防火墙阻止。

解决:

  1. 在WSL2中检查NameNode是否监听:ss -tuln | grep :9000,应有0.0.0.0:9000;
  2. 在Windows中检查端口映射:netsh interface portproxy show v4tov4;
  3. 关闭WSL2防火墙:sudo ufw disable(Ubuntu);
  4. 临时关闭Windows防火墙测试。

4.5 现象:java.lang.IllegalArgumentException: Can not create a Path from an empty string

原因:FileOutputFormat.setOutputPath(job, new Path(""))传入空字符串,或outputPath变量为null。多见于System.currentTimeMillis()生成路径时,因时区/格式问题返回空。

解决:

  1. 在WordCountDriver中打印outputPath:
    System.out.println("Output path: " + outputPath);
  2. 改用安全的时间戳:
    String timestamp = String.valueOf(System.currentTimeMillis()); String outputPath = "hdfs://localhost:9000/output/wordcount_" + timestamp; if (outputPath.contains(" ")) throw new RuntimeException("Path contains space!");

5. 进阶验证:用YARN Web UI定位性能瓶颈与自定义Counter

作业跑通只是起点。真正体现MapReduce工程能力的,是读懂YARN Web UI中的指标,并用Counter量化业务逻辑。例如,你想知道“有多少单词被Mapper过滤掉(非字母字符)”,标准WordCount无法回答——必须用自定义Counter。

5.1 YARN Web UI核心指标解读(http://localhost:8088)

打开YARN Web UI后,点击你的Application ID(如application_171xxxxxx_xxxx),进入Application详情页。重点关注:

指标区域关键字段健康阈值说明
Application SummaryState, Final StatusSUCCEEDEDFAILED或KILLED表示作业异常终止
ContainersTotal Allocated Containers≥2至少1个AM容器 + 1个Map/Reduce容器;若为1,说明Task未启动
MetricsMemory Seconds, VCores Seconds与mapreduce.map.memory.mb匹配若Memory Seconds远低于预期(如Map Task申请1024MB但只用200MB),说明资源浪费
LogsLink to logs可点击点击logs链接查看AM、Container日志,定位Exit code: 1的具体原因

血泪经验:当Final Status为SUCCEEDED但输出为空时,90%概率是FileOutputFormat.setOutputPath()路径写错(如/output/wordcount末尾缺时间戳),导致HDFS中生成空目录。此时UI中Containers显示正常,但Logs里Container Executor会报Output directory ... already exists。

5.2 自定义Counter:统计Mapper过滤的非法字符数

Counter是MapReduce内置的分布式计数器,比System.out.println可靠万倍——它由ApplicationMaster统一收集,不受Task重试影响。

在WordCountMapper中添加Counter:

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); // 定义Counter枚举 enum FilterCounter { ILLEGAL_CHAR_COUNT } @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); // 统计原始字符数 int originalLen = line.length(); // 过滤非字母空格字符 String filtered = line.replaceAll("[^a-zA-Z\\s]", ""); int filteredLen = filtered.length(); // 计数被过滤的字符数 context.getCounter(FilterCounter.ILLEGAL_CHAR_COUNT) .increment(originalLen - filteredLen); StringTokenizer tokenizer = new StringTokenizer(filtered); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken().toLowerCase()); context.write(word, one); } } }

在WordCountDriver中读取Counter:

if (success) { Counters counters = job.getCounters(); long illegalCount = counters.findCounter(WordCountMapper.FilterCounter.ILLEGAL_CHAR_COUNT).getValue(); System.out.println("Total illegal chars filtered: " + illegalCount); }

提交作业后,在YARN Web UI的Application详情页 →Counters标签页,即可看到FilterCounter.ILLEGAL_CHAR_COUNT的累加值。这是调试数据清洗逻辑的“后悔药”——无需改代码、无需重跑,直接看Counter就知道过滤强度。

5.3 生产级调试习惯:日志级别控制与远程调试

本地开发时,将Hadoop日志级别调为DEBUG可暴露底层细节,但会淹没关键信息。推荐分层控制:

  • Mapper/Reducer内部逻辑:用context.getCounter()替代System.out;
  • Hadoop框架层:在log4j.properties($HADOOP_HOME/etc/hadoop/)中设置:
    log4j.logger.org.apache.hadoop.mapreduce=INFO log4j.logger.org.apache.hadoop.yarn=INFO log4j.logger.org.apache.hadoop.hdfs=INFO
  • IDEA远程调试:在WSL2中启动NodeManager时添加JVM参数:
    export YARN_NODEMANAGER_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" stop-yarn.sh && start-yarn.sh
    然后在IDEA中配置Remote JVM Debug,Host=localhost,Port=5005,即可断点调试NodeManager中运行的Task。

我坚持在每次提交作业前,先用hdfs dfs -ls确认输入路径存在、hadoop fs -du -s确认文件大小合理、yarn application -list确认无残留失败作业。这些动作花不了30秒,却能避免80%的“作业提交后卡死”问题。MapReduce不是黑匣子,它的每一步都在日志里留了线索——你只需要学会用YARN UI和Counter去读。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询