当数据量从GB级跃升到TB甚至PB级时,传统单机计算模式立刻暴露出致命缺陷。我曾在一个日志分析项目中深有体会:用Python脚本处理200GB的服务器日志,单机跑了8小时才完成。而同样的任务在10节点Hadoop集群上,通过MapReduce仅用12分钟就处理完毕——这就是分布式计算的威力。
MapReduce的核心价值在于它用"分而治之"的思想解决了三大难题:
提示:MapReduce特别适合批处理场景,如日志分析、ETL、数据统计等。但对于实时性要求高的场景(如实时推荐),可能需要考虑Spark或Flink。
用快递分拣的类比最容易理解MapReduce的工作流程:
Map阶段(分拣员拆包)
Shuffle阶段(传送带分类)
Reduce阶段(打包员统计)
java复制// 典型Map函数实现(WordCount示例)
public void map(LongWritable key, Text value, Context context) {
String[] words = value.toString().split(" ");
for (String word : words) {
context.write(new Text(word), new IntWritable(1));
}
}
bash复制# 验证Hadoop安装
hadoop version
# 创建测试文件
echo "hello world hello hadoop" > input.txt
hdfs dfs -put input.txt /user/input
java复制public class WordCount {
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{...}
public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,IntWritable> {...}
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);
}
}
bash复制# 打包提交任务
hadoop jar wordcount.jar WordCount /user/input /user/output
# 查看运行状态
yarn application -list
# 获取结果
hdfs dfs -cat /user/output/part-r-00000
| 问题现象 | 优化方案 | 实现方式 |
|---|---|---|
| 某个Reducer处理数据量过大 | 增加Reducer数量 | job.setNumReduceTasks(10) |
| 存在热点Key | 自定义Partitioner | 重写getPartition方法 |
| Map输出过大 | 启用Map端Combiner | job.setCombinerClass() |
xml复制<!-- mapred-site.xml 优化示例 -->
<property>
<name>mapreduce.task.io.sort.mb</name>
<value>256</value> <!-- 提高排序内存 -->
</property>
<property>
<name>mapreduce.map.output.compress</name>
<value>true</value> <!-- 启用Map输出压缩 -->
</property>
Container内存溢出
Container killed by YARN for exceeding memory limitsmapreduce.map.memory.mb和mapreduce.reduce.memory.mbShuffle阶段卡顿
数据倾斜导致任务失败
bash复制# 查看详细错误日志
yarn logs -applicationId <app_id>
# 启用任务调试模式
-Dmapreduce.map.failures.maxpercent=10
虽然Spark等内存计算框架日益流行,但MapReduce在以下场景仍不可替代:
我在实际项目中总结的经验是:对于每天定时运行的ETL作业,特别是需要处理历史归档数据的场景,MapReduce+HDFS的组合仍然是最经济可靠的选择。而对于需要亚秒级响应的实时分析,才会考虑Spark Streaming或Flink。