
简介《云计算技术实验报告三运行Hadoop MapReduce程序》是一份面向云计算、大数据初学者的实验报告范本内容围绕在Linux环境下完整实现Hadoop MapReduce程序的开发全流程。报告中详细记录了从Java源码编辑、CLASSPATH环境变量配置、javac编译、jar打包到通过bin/hadoop jar命令提交并运行任务的步骤并配套展示了Hadoop自带wordcount程序的HDFS操作与结果验证适合需要完成同类课程实验或快速上手MR编程模型的读者参考。压缩包包含1个PDF文件大小约603KB内容结构清晰涵盖实验目的、算法分析、关键命令、实验结果与总结感想。目前已有382人学习浏览报告以实际运行案例解释MapReduce的分区、排序与Shuffle流程能帮助读者加深对分布式计算框架工作机制的理解。1. 先把实验跑通再说原理一次WordCount的完整旅程云计算技术课的第三个实验标题叫“运行Hadoop MapReduce程序”。我最早在虚拟机上做这个实验时以为最难的是写Java代码结果最简单的是代码最折腾的是环境Java版本不对、SSH免密没配、YARN起不来、作业一直停在ACCEPTED状态。这篇笔记就是把“运行Hadoop MapReduce程序”拆成环境搭建、代码提交、任务调度和排错四件事适合正在做实验报告、Hadoop课程设计或者想自己复现一次MapReduce全流程的从业者。跑通一次WordCount你对HDFS、YARN、Shuffle的理解会立刻从“看过”变成“摸过”。2. 实验环境的搭建从Linux装包到伪分布式的三个配置文件做“运行Hadoop MapReduce程序”这个实验最稳的起点不是直接搭三台机器的集群而是先把伪分布式跑通。伪分布式就是让一个节点同时扮演NameNode、DataNode、ResourceManager、NodeManager四个角色数据、调度、计算都在本机完成。它能让你完整经历HDFS上传、提交作业、Map执行、Shuffle、Reduce执行、结果回写这一整条链路同时把环境复杂度控制在一个人能Hold住的范围。网上有打包好的Hadoop Docker镜像确实能省掉配置步骤但实验报告通常需要你写清楚“为什么这样配”本地手动装一次反而更划算。至于Hadoop HA、Hadoop和Zookeeper整合实战那是多节点生产环境的课题单机实验阶段先不碰但要在报告里提一句“生产环境还需要引入ZooKeeper做故障切换”就能让老师看出你理解了边界。2.1 为什么伪分布式够用先搞清楚实验要验证什么云计算实验的核心目标是验证“MapReduce程序能不能在一个分布式文件系统上处理数据”。伪分布式虽然只有一个节点但HDFS的块机制、YARN的资源调度、MapTask和ReduceTask的调度逻辑都真实发生了和集群没有本质区别。区别只在于数据量和容错能力——单机没有真正的机架感知也没有多副本跨节点分布所以对外部读写的性能参考意义不大。我一般建议做这个实验时把目标定成能解释清楚一个输入文件从上传到HDFS再到输出结果的全过程而不是纠结数据跑得有多快。课程设计里常见的误区是一上来就搭三节点集群结果半天时间全耗在SSH同步和配置分发上反而不如先跑通伪分布式再用同样的配置扩展到集群。这也是为什么大多数实验报告的标准做法都是“先伪分布、后集群”。如果后续需要做三节点扩展核心配置文件几乎不用改只要把hdfs-site.xml里的副本数、yarn-site.xml里的内存参数调一下就行。2.2 从零到能启动JDK、SSH、解压与目录规划下面这套步骤以CentOS 7或Ubuntu Server为例Hadoop版本用3.x。版本差异主要影响Web UI端口和个别默认参数配置思路通用。先准备好JDK 8和Hadoop安装包然后按这个顺序操作# 1. 安装JDK并确认版本Hadoop 3.x要求JDK 8及以上 tar -zxvf jdk-8u202-linux-x64.tar.gz -C /usr/local/ cat ~/.bashrc EOF export JAVA_HOME/usr/local/jdk1.8.0_202 export PATH$PATH:$JAVA_HOME/bin EOF source ~/.bashrc java -version # 2. 解压Hadoop到固定目录尽量避免中文路径和带空格的目录 tar -zxvf hadoop-3.3.6.tar.gz -C /usr/local/ mv /usr/local/hadoop-3.3.6 /usr/local/hadoop # 3. 配置HADOOP_HOME很多报错都源于这里漏配 cat ~/.bashrc EOF export HADOOP_HOME/usr/local/hadoop export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin EOF source ~/.bashrc hadoop version # 4. 配置SSH本机免密MapReduce调度时需要SSH连接localhost启动NodeManager ssh-keygen -t rsa -P -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ssh localhost参数说明JAVA_HOME必须指向实际JDK解压路径Hadoop启动脚本会直接读取这个变量HADOOP_CONF_DIR建议显式声明否则有些版本会在启动时误读默认配置目录SSH免密配置完成后一定要执行一次ssh localhost确认不用输密码否则后面start-dfs.sh会反复要求认证。这步有一个关键细节修改~/.bashrc后所有后续启动命令都要在同一个Shell会话里执行。我见过不少人是配完环境变量直接新开终端结果新终端没有加载配置Hadoop命令提示找不到。稳妥做法是执行完source ~/.bashrc后先hadoop version确认能输出版本号再继续下一步。2.3 三个配置文件core-site、hdfs-site、yarn-site的必调项伪分布式环境下真正需要手工改的只有三个文件。core-site.xml里需要指定NameNode的地址hdfs-site.xml里把副本数降为1因为单节点存三份没有意义yarn-site.xml是伪分布式和单机模式的关键区别——必须显式开启YARN调度并给容器预留合理内存。以下是我的常用配置基线!-- core-site.xml -- configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value descriptionNameNode的RPC地址客户端提交作业时依赖此地址/description /property /configuration!-- hdfs-site.xml -- configuration property namedfs.replication/name value1/value description伪分布式只有一个DataNode副本数必须为1否则会一直处于副本不足告警/description /property /configuration!-- yarn-site.xml -- configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.nodemanager.aux-services.mapreduce_shuffle.class/name valueorg.apache.hadoop.mapred.ShuffleHandler/value /property property nameyarn.nodemanager.resource.memory-mb/name value4096/value description给YARN分配的总内存虚拟机上不能超过物理内存/description /property /configuration参数说明yarn.nodemanager.aux-services配成mapreduce_shuffle是很多新手最容易漏掉的一项不配的话作业能提交但MapTask的数据永远传不到ReduceTask最终表现为Reduce一直挂起。yarn.nodemanager.resource.memory-mb必须小于或等于物理内存如果你虚拟机只给了2G这里填4096会导致NodeManager直接启动失败。配置完成后执行格式化与启动# 首次启动前必须格式化NameNode之后不要重复执行否则元数据会丢失 hdfs namenode -format start-dfs.sh start-yarn.sh jpsjps输出里能看到NameNode、DataNode、ResourceManager、NodeManager四个进程就是成功的。Hadoop 3.x的NameNode Web UI端口是9870ResourceManager UI端口是8088浏览器能打开这两个页面环境才算真正就绪。提示jps能看到进程不代表集群可用。我习惯每次都先跑hdfs dfsadmin -report看一下DataNode是否正常注册再跑yarn node -list确认NodeManager在线两个命令都通过再进下一步。3. 提交第一个MapReduce程序WordCount从编写、打包到运行环境就绪以后要做的第一件事不是急着调复杂算法而是把最经典的词频统计跑通。网上大多数MapReduce编程实例也都是拿WordCount当模板因为它足够短却覆盖了MapReduce的完整数据流。你只要能把这个程序从编译到结果输出讲清楚实验报告的核心分就拿到了。3.1 为什么第一课永远是WordCount一次MapReduce的数据流还原WordCount处理的是文本文件输入格式是LongWritable加Text也就是“行偏移量加行内容”。Map阶段把每一行按空格拆成单词输出(单词, 1)Map结束后框架会对所有key做分区、排序、合并相同单词的计数被聚到同一个ReduceTask。ReduceTask拿到(单词, [1, 1, 1...])以后累加最终输出(单词, 总数)。这条链路里有三个容易被忽略的点第一Map的输出不是直接写磁盘而是先写入内存缓冲区达到阈值才溢写第二Shuffle阶段会在Map端做一次合并在Reduce端再做一次归并两个环节都有可能成为瓶颈第三MapTask和ReduceTask之间通过HTTP传输数据这就是yarn-site.xml里那个aux-services参数的作用。理解了这三件事再看后面的配置文件就有依据了。3.2 写代码、离线编译与打包javac、jar与Main-Class写WordCount只需要一个Java文件。我一般把三个类全写在一个文件里Map类、Reduce类、主类。这样编译和打包都不用管复杂的Gradle或Maven依赖一条javac命令就能完成。import java.io.IOException; import java.util.StringTokenizer; 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.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class WordCount { // Mapper输入是行偏移量行内容输出是单词计数1 public static class TokenizerMapper extends MapperObject, Text, Text, IntWritable { private final static IntWritable one new IntWritable(1); private Text word new Text(); public void map(Object key, Text value, Context context ) throws IOException, InterruptedException { StringTokenizer itr new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); } } } // Reducer把相同单词的计数累加 public static class IntSumReducer extends ReducerText, IntWritable, Text, IntWritable { private IntWritable result new IntWritable(); public 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); } } public static void main(String[] args) throws Exception { Configuration conf new Configuration(); Job job Job.getInstance(conf, word count); job.setJarByClass(WordCount.class); job.setMapperClass(TokenizerMapper.class); job.setCombinerClass(IntSumReducer.class); job.setReducerClass(IntSumReducer.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); } }代码逻辑说明setCombinerClass在这里直接复用Reducer类因为词频累加满足交换律和结合律可以在Map端先合并一次减少Shuffle数据量。如果你自己写的Reducer不满足这个条件千万不能复用否则结果会错。setJarByClass用来告诉Hadoop从哪个Jar里加载类本地跑的时候不明显提交到YARN时必须写。编译和打包用下面两条命令# 用hadoop classpath自动带上全部依赖避免手动找jar包的痛苦 javac -classpath $(hadoop classpath) -d wordcount_classes WordCount.java # 打成普通jar包即可不需要生成可执行jar jar cf wordcount.jar -C wordcount_classes .参数说明hadoop classpath会输出一大串路径它从HADOOP_HOME环境变量读取Hadoop安装位置。这一步经常出现“找不到命令”或“classpath为空”的问题基本都可以回溯到2.2节里的HADOOP_HOME漏配。网上有时能直接找到别人编译好的Hadoop已编译Jar包但那个包要能跑起来前提是你本机环境变量全部正确否则运行时会报ClassNotFoundException这个前面省的时间后面全得还回去。3.3 用yarn jar提交作业运行参数与输出目录的规矩打包完成后先准备输入数据并上传到HDFS。注意Hadoop MapReduce程序读取的是HDFS路径不是Linux本地路径这是最常见的第一个理解断层。# 建一个测试目录随便放几个文本文件 mkdir -p input_data echo hello hadoop hello mapreduce input_data/a.txt echo mapreduce is fun hadoop is powerful input_data/b.txt # 创建HDFS目录并上传 hdfs dfs -mkdir -p /input hdfs dfs -put input_data/*.txt /input/ # 提交作业输出目录必须是不存在的路径 hadoop jar wordcount.jar WordCount /input /output提交命令的参数含义如下参数作用说明hadoop jar提交作业等价于yarn jar新版推荐用后者wordcount.jar包含程序类的Jar包路径是本地文件系统路径WordCount主类全限定名这里类和包同名所以不用写包名/inputHDFS输入目录可以传多个路径目录下所有文件都会参与计算/outputHDFS输出目录必须不存在否则作业直接失败运行成功后HDFS根目录下会出现一个/output目录里面至少有一个_SUCCESS文件和一个part-r-00000文件。查看结果用hdfs dfs -cat /output/part-r-00000。如果只想验证代码逻辑可以用-D mapreduce.job.reduces1把Reduce数量固定为1这样结果只落在一个文件里方便看全貌。注意/output每次运行时都必须先删除或换新路径重复运行同一个实验时尤其容易踩这个坑。4. 搞清楚你提交的作业在集群里到底怎么跑InputSplit、Map数量与数据倾斜作业能跑通只是及格线。实验报告要拿高分下一步必须解释清楚“运行中的Hadoop任务里InputSplit到底是什么Map数量由什么决定”。这个问题在Hadoop面试题里出现频率也很高因为它直接决定了作业的并行度和执行效率。4.1 InputSplit是什么运行中的任务如何把文件切成可计算的切片InputSplit是MapReduce框架对输入数据的逻辑划分而不是物理存储单位。HDFS上文件被切成了块Block默认128MB一块这是存储层而MapReduce在读取数据时会按InputSplit创建对应数量的MapTask默认情况下一个Block对应一个Split所以Map数量约等于文件总大小除以块大小。这里有个容易混淆的点Split是逻辑概念Block是物理概念。一个Split可以横跨多个Block也可以只包含一个Block的一部分具体取决于文件格式和切分逻辑。框架拿到Split列表以后会尝试把Split分配给本地存有对应Block的节点这就是“计算向数据移动”的基本原理。在运行中的任务里我们要观察Split只需要看两处一是提交作业时控制台输出的number of splits二是ResourceManager UI上该作业的Map数。输入文件越大这个数字越直观。执行下面的命令可以查HDFS上每个文件的块分布hdfs fsck /input -files -blocks -locations输出里每行会列出一个文件路径、块大小、块的副本位置。把这些信息和Map数量对照就能确认Map数与块数基本相等。如果作业卡在本地读数据还可以用-D mapreduce.job.maps来强制指定Map数量但真实执行时框架会忽略这个参数因为InputFormat自己会计算Split正确做法是调整Split大小而不是直接命令Map数量。4.2 怎么控制Map数量从minSize、maxSize到CombineFileInputFormatSplit大小由三个参数共同决定公式是max(minSize, min(maxSize, blockSize))。这里的minSize是mapreduce.input.fileinputformat.split.minsizemaxSize是mapreduce.input.fileinputformat.split.maxsizeblockSize就是HDFS块大小默认128MB。把这个公式记住Map数量就能控制了。想增大Map数、让每个Map处理更少数据就把maxSize调小比如调到16MB想减少Map数就调大minSize。实际使用中直接改maxSize的场景占绝大多数。提交作业时这样传参hadoop jar wordcount.jar WordCount -D mapreduce.input.fileinputformat.split.maxsize33554432 /input /output参数说明33554432是32MB的字节数。Hadoop配置项很多都是字节为单位写数值时先做进制换算直接写32不会生效而且不会报错只会让你的结果和预期完全对不上。还有一类场景常见于“HDFS和MapReduce综合实训”输入目录里有大量小文件每个文件几十KB默认逻辑下一个文件可能就生成一个SplitMap数量暴涨到几千甚至上万每个Map处理的数据太少调度开销反而拖慢整体速度。此时不能靠改maxSize解决得用CombineFileInputFormat把小文件合并成一个Split。在代码里把job.setInputFormatClass(CombineFileInputFormat.class)即可它允许一个MapTask处理多个小文件这是处理小文件问题最直接的答案。4.3 数据倾斜与Shufflecombiner、自定义partitioner如何选数据倾斜在WordCount里不明显因为单词分布还算均匀但实验如果让你统计日志里的异常号、用户访问量数据倾斜立刻就会出现某个key的条目特别多它的ReduceTask要处理几百万条记录其他ReduceTask却很快就跑完了。最典型的现象是所有Map都完成但Reduce进度一直卡在33%或67%整体作业卡在最后阶段。解决倾斜有三板斧。第一板斧是加Combiner把Map端相同key的局部结果先合并这是最简单有效的手段。第二板斧是自定义Partitioner按业务把数据尽量打散。比如统计IP访问量时可以按源IP的哈希值分桶而不是直接用IP本身分区。下面给一个按key长度分区的简化写法import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Partitioner; public class LengthPartitioner extends PartitionerText, IntWritable { Override public int getPartition(Text key, IntWritable value, int numPartitions) { // 如果key很长大概率是同一个单词或同一类数据尽量散列到不同分区 return (key.toString().length() * 31) % numPartitions; } }逻辑说明Partitioner决定每一条Map输出进入哪个ReduceTask。默认实现是key.hashCode() % numPartitions它对分布均匀的key很公平但对热门key无能为力。按自定义规则重新散列本质是让每个分区的数据量尽量接近。第三板斧是调整Reduce端参数把mapreduce.reduce.memory.mb调大或者开启mapreduce.map.output.compresstrue减少Shuffle网络传输量。对实验而言Combiner已经能解决大部分问题自定义Partitioner更适合作为报告里的加分项。单独设置Combiner的写法是job.setCombinerClass(LocalSumCombiner.class)要求Combiner的输入输出类型与Reducer一致否则类型不匹配会在运行时才报错。5. 避坑指南MapReduce实验里最常见的五个翻车现场这一章是全篇最有血泪经验的部分。从课程设计到生产排查下面五个问题覆盖了伪分布式实验里绝大多数“看着配置没问题、代码也没问题、就是跑不起来”的情况。每条按“现象、原因、解决”的顺序写自己踩坑时按图索骥即可。5.1 启动后进程不对JAVA_HOME、Hostname、SSH免密三位一体检查现象执行start-dfs.sh后jps只能看到NameNode或DataNode其中一个或者干脆一个都看不到查看日志报错Error: JAVA_HOME is not set and Java could not be found。原因这类问题几乎都集中在三处。第一是JAVA_HOME写错或指向了JRE而非JDK第二是Hadoop使用hostname去注册节点而/etc/hosts里没有本机的hostname映射第三是SSH免密没生效DataNode启动时连接localhost被拒。解决先执行echo $JAVA_HOME确认变量值再检查hostname和/etc/hosts是否一致最后手动执行ssh localhost看是否还需要密码。三条都通过后执行stop-all.sh再重新start-all.sh。启动日志在$HADOOP_HOME/logs/目录下根据进程名找对应的.log文件这是定位启动问题的第一现场。5.2 作业一直ACCEPTED不进RUNNINGNodeManager没就绪是首要嫌疑现象hadoop jar提交后控制台停在Submitting application用yarn application -list能看到作业状态一直是ACCEPTED等几分钟也不变化。原因YARN集群接收了作业但没有NodeManager能执行它。常见原因是NodeManager进程没起来或者YARN内存配置超限导致容器无法分配。前者可以回到5.1检查jps后者要确认2.3节里的yarn.nodemanager.resource.memory-mb填的值没有超过物理内存。解决先执行yarn node -list -all如果输出为空说明NodeManager没有注册回到YARN日志排查启动失败原因。如果能看到节点但无法分配容器执行yarn node -status 节点名查看可用内存再对照mapreduce.map.memory.mb默认值调整。一台2G内存的虚拟机把YARN总内存降到1536MBMap容器内存降到512MB通常就能跑通。5.3 输出目录已存在FileAlreadyExistsException是最常报的错现象第一次运行成功第二次运行同一个作业时抛org.apache.hadoop.mapred.FileAlreadyExistsException提示输出路径已存在。原因MapReduce框架出于安全设计不会覆盖已有输出目录因为输出可能来自上一次作业直接覆盖会掩盖数据问题。解决换一个新路径或者先确认旧输出没用了再删。实际操作用hdfs dfs -rm -r /output删除。我把这当成一个习惯每次提交之前先检查输出路径有没有残留写成脚本也好、手敲命令也好总之不要在作业跑一半才发现路径冲突。5.4 中文乱码与编码问题默认读取行为和你本地文件编码不一致现象输出结果里中文全部变成??或者乱码英文单词正常。有时还会看到单词被意外切割比如“哈”和“密”被拆成两行。原因Hadoop的Text类型默认按UTF-8解码但Windows上生成的输入文件常是GBK编码。另外StringTokenizer只按空格切分中文字符之间没有空格整句话会被当成一个单词看起来就像“乱码”。解决上传前先把输入文件转成UTF-8用iconv -f GBK -t UTF-8 input.txt input_utf8.txt转换。如果要处理中文分词就不要依赖StringTokenizer改用手工按字符切分或引入分词器。实验场景下最简单的方法是输入文件就存UTF-8输出文件用hdfs dfs -cat查看时指定编码环境export LANGzh_CN.UTF-8可以避开大多数乱码问题。5.5 容器反复被杀、GC时间过长虚拟机内存参数没跟随实际环境现象作业提交后Map跑到20%左右就开始重试然后以Container killed by the ApplicationMaster之类的错误失败。日志里能看到物理内存超过限制的记录或者GC overhead limit exceeded。原因这是YARN按内存上限管理容器导致的。默认情况下mapreduce.map.memory.mb是1024MBmapreduce.map.java.opts最大堆设为-Xmx 819m。如果NodeManager一共只有2G内存同时跑两个Map容器就直接超了容器会被杀掉。解决按虚拟机实际内存重新分配报告里也要写清楚。我常用的最小配置是# 在yarn-site.xml中明确指定 yarn.nodemanager.resource.memory-mb2048 yarn.scheduler.maximum-allocation-mb2048 # 提交作业时临时指定容器内存 hadoop jar wordcount.jar WordCount \ -D mapreduce.map.memory.mb512 \ -D mapreduce.reduce.memory.mb512 \ -D mapreduce.map.java.opts-Xmx400m \ /input /output参数说明-Xmx必须小于mapreduce.map.memory.mb因为JVM堆只是容器进程的一部分还有元数据区和系统开销。这段配置本身也是实验报告里很好的“调优记录”素材。6. 让实验结论可验证从日志、历史服务到把WordCount升级成TopN程序跑完只是第一步能证明它“真的跑对了、可复现”比程序本身更能体现有没有吃透这个实验。这里分享三个我常用的验证和进阶方法。6.1 用HistoryServer和YARN日志核对真实执行情况作业结束后ResourceManager Web UI的历史列表里会保留每次作业的统计信息Map输入记录数、Map输出记录数、Shuffle传输字节数、Reduce输出记录数。对照这些数字就能判断是否发生了数据倾斜、Combiner是否生效。# 查看某个application的容器日志 yarn logs -applicationId application_xxxxxxxx app.log # 从日志中找到Map或Reduce的计数器输出 grep Combine output records app.log | head -5计数器里Combine output records如果存在且小于Map output records就说明Combiner确实合并过数据这个数字可以直接写进实验报告作为证据。6.2 把WordCount升级成词频TopN一个性价比很高的进阶练手要验证对排序和Shuffle的理解最快的做法是输出词频最高的前10个词。核心不是改Map或Reduce而是在Reduce端用一个容量为N的小顶堆维护最大值列表。可以参考下面的片段public static class TopNReducer extends ReducerText, IntWritable, Text, IntWritable { private TreeMapInteger, String top new TreeMap(); Override public void reduce(Text key, IterableIntWritable values, Context context) { int sum 0; for (IntWritable val : values) { sum val.get(); } top.put(sum, key.toString()); if (top.size() 10) { top.remove(top.firstKey()); } } Override public void cleanup(Context context) throws IOException, InterruptedException { for (Map.EntryInteger, String entry : top.entrySet()) { context.write(new Text(entry.getValue()), new IntWritable(entry.getKey())); } } }逻辑说明每个ReduceTask内部只保留10个最大的词频最后在cleanup阶段统一输出。这个练手能让你理解cleanup方法的用途也知道全局TopN在分布式环境里不能靠把所有数据做全局排序而是要先在局部裁剪一轮。6.3 固定输入与资源参数确保实验结果可复现写实验报告时最容易被问倒的一句话是“你这个结果能再跑一遍吗”。我自己的习惯是把三条信息记录下来输入文件的完整内容和大小、HDFS块大小、YARN内存参数。有了这三样任何人在同一台配置下都能跑出相同结果。这个实验做到最后最大的教训不是代码写不写得出而是过程中大部分时间花在了环境匹配上。希望这篇笔记能让你少走一些弯路把更多注意力放到理解分布式计算本身希望对你有帮助。本文还有配套的精品资源点击获取