MapReduce中的Map,Reduce个数设定

MapReduce中,Map任务个数由输入文件大小、splitsize参数和HDFS块大小决定,Reduce任务数量可通过setNumReduceTasks设置。FileInputFormat逻辑划分文件,TextInputFormat解析键值对。默认Reduce任务数为1,过多会影响性能。

一、Map的个数

    在map阶段读取数据前,FileInputFormat会将输入文件分割成spilt,而spilt的个数决定了map的个数(一个spilt分片对应一个map)。影响map个数的因素只要有:

    1)文件的大小。比如,当文件大于128M(block默认值)而小于256M时,文件会被划分成两个spilt。

    2)文件的个数。FileInputFormat按文件进行分割,如果单个文件大于128M会被划分为多个spilt,反之,如果单个文件小于128M,FileInputFormat会把小文件单独划分成一个spilt。

    3)splitsize的大小。分片是按照splitsize的大小进行的,默认情况下,splitsize的大小等同于hdfs的block大小。但可以通过参数调节。

            InputSplit=Math.max(minSize,Math.min(max.Size,blockSize))

     其中:

            minSize = mapred.min.split.size

            maxSize = maperd.max.split.szie

    我们可以在MapReduce程序的驱动部分添加如下代码进行设置:

           TextInputFormat.setMinInputSplitSize(job,1204*64L) ; //设置最小分片大小

           TextInputFormat.setMinInputSplitSize(job,1204*64L); //设置最大分片大小

总结如下:

      当mapreduce.input.fileinputformat.split.maxsize > mapreduce.input.fileinputformat.split.minsize > dfs.blockSize的情况下,此时的splitSize 将由mapreduce.input.fileinputformat.split.minsize参数决定

      当mapreduce.input.fileinputformat.split.maxsize > dfs.blockSize > mapreduce.input.fileinputformat.split.minsize的情况下,此时的splitSize 将由dfs.blockSize配置决定

      当dfs.blockSize > mapreduce.input.fileinputformat.split.maxsize > mapreduce.input.fileinputformat.split.minsize的情况下,此时的splitSize将由mapreduce.input.fileinputformat.split.maxsize参数决定。

 

 

 

  其中TextInputFormat继承自FileInputFormat,FileInputFormat继承自InputFormat。

          InputFormat这个类会将文件file进行逻辑划分,划分成的每一个spilt对应一个map,在MR中运行

          FileInputFormat这个类先对输入文件进行逻辑上划分,以128M(hdfs block默认值)为单位,将原始数据从逻辑上分割成若干个split,每个split切片对应一个Mapper任务。要注意的是FileInputFormat这个类只对比HDFS Block大的文件进行划分,比HDFS Block小的文件不进行划分,此时的小文件会被当做一个split块并分配一个Mapper任务。这也是Hadoop处理大文件的效率要比处理很多小文件的效率高的原因。

            当FileInputFormat这个类将文件file切分成block块之后,TextInputFormat这个类随后将每个split块中的每行记录解析成一个一个的键值对,即<k1,v1>

综上:我们可以简单理解为FileInputFormat这个类是将文件file切分成split块,而TextInputFormat这个类是负责将每一行记录解析为键值对<k1,v1>。

二、Reduce的个数

    Reduce任务是一个数据聚合的步骤,数量默认为1。而使用过多的Reduce任务则意味着复杂的shuffle,并使输出文件数量激增。而reduce的个数设置相比map的个数设置就要简单的多,只需要设置setNumReduceTasks即可.

 

下面是以WordCount为例的一个简单示范。

package hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * Hadoop
 */
public class WordCountAPP {
    public static class MyMapper extends Mapper<LongWritable,Text,Text,LongWritable>{
        @Override
        protected void setup(Context context) throws IOException, InterruptedException {
            System.out.println("setUp");
        }

        @Override
        protected void cleanup(Context context) throws IOException, InterruptedException {
            System.out.println("cleanUp");
        }

        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
                    String[] values = value.toString().split(",");

                    for (String s : values){
                        Text k = new Text(s);
                        context.write(k, new LongWritable(1));
                    }
        }
    }
    public static class MyReducer extends Reducer<Text,LongWritable,Text,LongWritable>{
        @Override
        protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
                long sum = 0;
                for (LongWritable v : values){
                    sum += v.get();
                }
                context.write(key,new LongWritable(sum));
        }
    }


    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf,"wordcount");
        job.setJarByClass(WordCountAPP.class);

        if (args.length < 2){
            System.err.println("Please enter <inputPath> and <outputPath>");
        }
        Path outputPath = new Path(args[1]);
       // Path outputPath = new Path(args[1]);
        FileSystem fs = FileSystem.get(conf);
        if (fs.exists(outputPath)){
            fs.delete(outputPath,true);
            System.out.println("outputpath exists,delete!");
        }
        //FileInputFormat.setInputPaths(job,new Path(args[0]));
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileInputFormat.setMinInputSplitSize(job,1024*1204*64L);
        FileInputFormat.setMaxInputSplitSize(job, 1204*64L);
        job.setMapperClass(MyMapper.class);
        job.setReducerClass(MyReducer.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(LongWritable.class);

        job.setNumReduceTasks(2);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

//        FileOutputFormat.setOutputPath(job,new Path(args[1]));
        FileOutputFormat.setOutputPath(job, outputPath);

        System.exit(job.waitForCompletion(true) ? 0: 1);
    }



}

    代码中设置的split大小为64M,切割文件大小为98M,运行结果如下:

 

 

 

 

 

### 合理设置 Hive 中 Map 数和 Reduce 数的最佳实践 在 Hive 中,合理设置 MapReduce 的数量对于任务性能至关重要。以下是关于如何根据数据量和集群资源进行优化的具体说明: #### 1. **Map 数的设置** Map 数的主要决定因素包括输入文件的数量、大小以及集群中块的大小。以下是一些关键点: - 输入文件的总个数会影响 Map 数。如果存在大量小文件(远小于 HDFS 块大小,默认为 128MB),每个小文件会被当作一个单独的任务分配给一个 Map[^5]。 - 如果一个小文件占用一个 Map 任务,而其处理时间较短,则会造成大量的启动开销和资源浪费。因此,在这种情况下应考虑合并小文件。 ##### 解决方案:减少 Map 数 为了减少因小文件过多而导致的低效问题,可以启用 Hive 提供的小文件合并功能: ```sql SET hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; SET hive.exec.reducers.bytes.per.reducer=<目标值>; ``` 这将允许多个小文件被组合到同一个 Map 任务中。 ##### 解决方案:增加 Map 数 当输入文件较大且任务逻辑复杂时,可以通过调整 `mapreduce.input.fileinputformat.split.maxsize` 参数来控制每个 Split 的最大尺寸,进而增加 Map 数。例如: ```sql SET mapreduce.input.fileinputformat.split.maxsize=67108864; -- 设置为 64MB ``` 这样可以让更多的 Map 并行运行,从而加速任务执行[^5]。 --- #### 2. **Reduce 数的设置** 合理的 Reduce 数取决于以下几个方面: - 默认情况下,每个 Reduce 处理的数据量由参数 `hive.exec.reducers.bytes.per.reducer` 控制,默认值为 256MB[^3]。 - 单个任务的最大 Reduce 数由参数 `hive.exec.reducers.max` 定义,默认为 1009。 ##### 计算公式 计算 Reduce 数的通用公式如下: \[ \text{N} = \min(\text{hive.exec.reducers.max}, \frac{\text{总输入数据量}}{\text{hive.exec.reducers.bytes.per.reducer}}) \] 其中: - 总输入数据量是指参与运算的所有数据总量; - `hive.exec.reducers.bytes.per.reducer` 表示每个 Reduce 应处理的理想数据量。 ##### 实际操作案例 假设总输入数据量为 1GB(约 \(10^9\) 字节),则可以根据上述公式得出: \[ \text{N} = \min(1009, \frac{10^9}{256 * 10^6}) = \min(1009, 4) = 4 \] 此时会生成 4 个 Reduce 任务。 ##### 动态设置 Reduce 数 也可以通过手动设置 `set mapreduce.job.reduces=N` 来覆盖默认行为。不过这种方式不推荐频繁使用,因为动态调整可能导致资源配置不合理[^2]。 --- #### 3. **注意事项** - **过少的 Reduce 数**:会导致单个 Reduce 负载过高,延长任务完成时间。 - **过多的 Reduce 数**:虽然能加快某些阶段的速度,但会产生额外的初始化成本,并可能引发下游任务中小文件过多的问题[^5]。 - 对于简单的聚合查询(无 Group By 或 Order By),尽量避免不必要的 Reduce 阶段。例如,将带 Group By 的语句重写为更高效的版本。 --- ### 示例代码 以下是一个完整的配置实例,展示如何针对不同场景调整 MapReduce 参数: ```sql -- 减少小文件带来的影响 SET hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 设置每个 Reduce 处理的数据量为 128MB SET hive.exec.reducers.bytes.per.reducer=134217728; -- 设定最大 Reduce 数为 500 SET hive.exec.reducers.max=500; -- 测试查询 SELECT COUNT(*) FROM large_table WHERE condition='value'; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值