spark并行度和mapreduce并行度对比

本文详细对比了Spark和MapReduce的并行度处理机制,包括它们的资源调度模型、任务执行方式以及如何优化并行度。介绍了Spark的多线程模型和MapReduce的多进程模型,以及它们在并行任务分配、资源利用和优化策略上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spark和mapreduce的区别

  • mapreduce是多进程模型,即里面的一个task对应一个进程
    • 优点:进程便于更细粒度的控制每个任务的占用资源,但是启动慢
  • spark是多线程模型,任务以分区为单位,一个分区对应一个task
    • 任务以线程的方式运行,启动快
  • 模型对比

    • mapreduce

      • 主节点resourcemanager负责分配资源调度
      • 从节点nodemanager负责计算,appmaster和container都是运行从节点nodemanager上
      • 一个job应用对应一个appmaster,一个appmaster管理多个container,
      • 一个container内部单线成执行(分配的是多核心cpu也是单线程)一个maptask或一个reducetask
      • 如果运行是resourcemanager挂掉或主备切换,正在运行的任务会等待resourcemanager重启或切换好后再继续运行,并任务可能失败
    • spark

      • 资源调度器clustermanager
        • standAlone版主节点master负责分配资源调度
          • 接受任务命令Worker启动Driver和Executor
        • yarn模式 ResourceManager负责
      • 从节点worker负责任务计算 如果是Yarn模式下就是NodeManager节点
      • 一个任务Job对应一个driver,一个driver可以有多个Executor,一个Executor可以有多个线程
      • 资源分配后driver和Executors通讯,不需要和master进行通讯的,因此主节点挂机不影响正在运行的人去

1.spark的并行度:

并行度指一个stage中可以同时并发执行task的能力

  1. 分区数量

    1. 默认和block相同,也可以手动设定例如sc.text.File("words.txt",10)设定10个分区,
    2. 注意设定10个分区和并行任务数量并不等价,如果设置并行度为20,那么对多运行10,剩下的10个不运行,但是还占用资源
    3. 参数spark.files.maxPartitionBytes 表示一个分片最大的大小默认是和block大小相同,目前没有后找到该参数的具体用法和调优案例,后期补充
    4. 文件源码底层与Hadoop有关,遵循Hadoop文件切片规则
  2. 并行度

    1. 并行数量=Executor数目*每个Executor核数 
    2. 注意:如果一个spark任务有100个分区,对应100个任务,而并行能力15,那么要运行7次才能运行完任务,并且却后一次只有个10task运行,5个空闲,但不会释放至于资源
  3. 设置Executor数目

    1. standlone模式下

      1. 数目计算公式 execuoterNum = spark.cores.max/spark.executor.cores
      2. spark.cores.max表示指定spark程序需要的总核数
      3. spark.executor.cores 是指每个executor需要的核数
        1. 例如:--driver-memory 6g --total-executor-cores 288 --executor-cores 2 表示指定spark程序需要的总核数288,,每一个executor运行2个核,execuoterNum=288/2=144
    2. 在yarn模式下直接指定 –num-executors 这个参数指定

  4. 设置并行的task数量(很重要)

    1. 设置参数 spark.default.parallelism
      1. 参数说明:参数用于设置每个stage的默认task数量,
      2. 官方建议设置数量 num-executors * executor-cores的2~3倍较为合适,可以充分利用资源
        1. 如果没有设置spark.default.parallelism,那么默认并行度与block数量相同,并且假如设置并行度10,而综总核心数100,那么运行是只有10核工作,其他都空闲

2.mapreduce并行度

mapreduce所属于对进程单线程模式,即一个task对应一个进程,一个进程中用一个线程来执行

  • maptask

    • maptask对应的也是切片数,切片数量是要计算出来,不能手动直接指定;一个切片开启一个进程,切片调用FileInputFormat.getsplit()方法(一个container运行一个maptask/reducetask)
      • 简单地按照文件的内容长度进行切片
      • 切片大小默认block大小
      • splicts大小=max(文件总大小/numSplits,min(minSize,blocksize))
      • 切片不考虑整体,只考虑一个block,例如130M文件有两个block,切片大小设定120M,会有三个切片,120M,8M,10M
      • 如果切片大于block,那么实际一个切片数量也是128M,不会将多个小文件合并对应参数
        •  mapreduce.input.fileinputformat.split.minsize  默认1
        • mapreduce.input.fileinputformat.split.maxsize 默认 Long.MAXValue 
  • reducetask

    • 多少个分区对应多少个reduce指定手动指定,job.setNumReduceTasks(4);默认是1,不使用分区(有设定分区也不会有效)
    • 如果reducetask数a>分区数b,只有b个线程处理数据,其他不工作,如果a<b程序无法运行
  • 优化相关 JVM重用

    • mapred.job.reuse.jvm.num.tasks
      • 默认情况下一个jvm进程运行一个maptask/reducetask。运行完后释放资源,进程消失,但是可以通过该参数来设置多个task,task必须是同一个job的,且执行是顺序执行

切片调用spark中是重写了FileInputFormat.getsplit()方法,但是基本逻辑相同,多了一个手动指定的数量

public InputSplit[] getSplits(JobConf job, int numSplits) throws IOException {
        Stopwatch sw = (new Stopwatch()).start();
        FileStatus[] files = this.listStatus(job);
        job.setLong("mapreduce.input.fileinputformat.numinputfiles", (long)files.length);
        long totalSize = 0L;
        FileStatus[] arr$ = files;
        int len$ = files.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            FileStatus file = arr$[i$];
            if (file.isDirectory()) {
                throw new IOException("Not a file: " + file.getPath());
            }

            totalSize += file.getLen();
        }

        //指定最小分区数可以划分的size大小
        long goalSize = totalSize / (long)(numSplits == 0 ? 1 : numSplits);
        //图片通过与hadoop的中最小值比较,获得比较大的
        long minSize = Math.max(job.getLong("mapreduce.input.fileinputformat.split.minsize", 1L), this.minSplitSize);
        ArrayList<FileSplit> splits = new ArrayList(numSplits);
        NetworkTopology clusterMap = new NetworkTopology();
        FileStatus[] arr$ = files;
        int len$ = files.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            FileStatus file = arr$[i$];
            Path path = file.getPath();
            long length = file.getLen();
            if (length == 0L) {
                splits.add(this.makeSplit(path, 0L, length, new String[0]));
            } else {
                FileSystem fs = path.getFileSystem(job);
                BlockLocation[] blkLocations;
                if (file instanceof LocatedFileStatus) {
                    blkLocations = ((LocatedFileStatus)file).getBlockLocations();
                } else {
                    blkLocations = fs.getFileBlockLocations(file, 0L, length);
                }

                if (!this.isSplitable(fs, path)) {
                    String[][] splitHosts = this.getSplitHostsAndCachedHosts(blkLocations, 0L, length, clusterMap);
                    splits.add(this.makeSplit(path, 0L, length, splitHosts[0], splitHosts[1]));
                } else {
//获取文件的快大小,如果是本地文件是33554432k对应32兆
                    long blockSize = file.getBlockSize();
//三个大小比较,得到最后切片大小
                    long splitSize = this.computeSplitSize(goalSize, minSize, blockSize);

                    long bytesRemaining;
                    String[][] splitHosts;
                    for(bytesRemaining = length; (double)bytesRemaining / (double)splitSize > 1.1D; bytesRemaining -= splitSize) {
                        splitHosts = this.getSplitHostsAndCachedHosts(blkLocations, length - bytesRemaining, splitSize, clusterMap);
                        splits.add(this.makeSplit(path, length - bytesRemaining, splitSize, splitHosts[0], splitHosts[1]));
                    }

                    if (bytesRemaining != 0L) {
                        splitHosts = this.getSplitHostsAndCachedHosts(blkLocations, length - bytesRemaining, bytesRemaining, clusterMap);
                        splits.add(this.makeSplit(path, length - bytesRemaining, bytesRemaining, splitHosts[0], splitHosts[1]));
                    }
                }
            }
        }

//三个大小的比较算法
 protected long computeSplitSize(long goalSize, long minSize, long blockSize) {
        return Math.max(minSize, Math.min(goalSize, blockSize));
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值