spark shuffle有四种方式,分别是

  1. hashshuffle
  2. 优化后的hashshuffle
  3. sortshuffle
  4. bypass

一、hashshuffle与优化

一开始spark的shuffle方式是hashshuffle。hashshuffle有一个严重的问题,就是产生的小文件数量比较多。

我们知道,shuffle分为map端的shuffle write 和reduce端的shuffle read。

hashshuffle,每个task为下游每一个task都创建了一个文件,所以就产生了M*R的小文件数量,其中M是map的task数量,R是reduce的数量。

为了减少小文件的数量,spark随后提出了优化后的hashshuffle,即每个core处理的task文件的结果合并起来

比如:task1 write了3个小文件,里面是keyA keyB keyC,分别叫BlockA BlockB BlockC 吧

这时又来了一个task2,优化前task2 也产生三个小文件BlockA BlockB BlockC。这样就有6个小文件

但是task2 和task1是同一个core处理的,所以task2的BlockA BlockB BlockC 写入了task1 的BlockA BlockB BlockC,由于同一个文件中是同一个下游task处理的,所以只要追加写入就可以了。

该优化方法,本质上是小文件的合并(同一个core的小文件数量合并),朝着这个方向,我们可以继续优化成“同一个executor(jvm)产生的同一个下游task的小文件合并”,和同一台机器合并,不过spark并没有实现这些优化。

由于同一个stage里的map的task不分先后顺序,但是同一个core里的task是先后处理的。所以同一个jvm或者同一台机器的小文件合并,没有同一个core的合并那么简单。

spark也提出过内存共享的优化方法,跨executor(jvm)去共享一台机器上面的内存。

该优化最终将小文件数量下降了X倍,X为平均每个core处理的task数量,

  • 比如,有100个map,下游是500个reduce,那原本是100*500=5w的小文件数量,现在map端分配的core是20个(每个core处理5个task),就变成了20*500=1w,缩小了5倍。

该优化方法虽然好,但是受限于机器并行的能力,如果机器并行的能力强,分配的core数量接近于map的数量,该优化就十分有限。

二、sortshuffle

为了实现更进一步的小文件合并,spark在随后提出了sortshuffle。

sortshuffle的目的,还是实现"更宽"的“共享”。

上述讲到hashshuffle对spark的小文件做了同一个core的合并,但是由于不同core的task没有先后顺序,很难合并。sortshuffle就是为了实现“每台机器上的map task小文件都合并”。

因为一台机器上的task之间执行没有顺序,所以要等待所有的task执行完成。无法有效利用并发能力。

如果按照之前的做法,为每个reduce task创建一个文件,并且同一台机器上的同一个reduce task的文件合并的话,这样最多能节省的倍数为平均一台机器处理的task数量,

  • 比如,有100个map,下游是500个reduce,那原本是100*500=5w的小文件数量,现在map端分配的core是20个,20个core在5台机器上(机器是4核的),就变成了5*500=2000,缩小了20倍。

显然优化者不满足于这种程度的优化,于是优化者这次对"*500" 动手了(reduce task的数量)。如何优化"*500", 原来一个map task 会产生500个task,现在将这些都合并了。所以就没有了"*500"

  • 比如,有100个map,下游是500个reduce,那原本是100*500=5w的小文件数量,现在合并了同一个map task产生的reduce task,那么文件数量就变成了100个。虽小了500倍,(由于要增加索引文件,所以实际上要除以2,是250倍)

只不过如果一个map,为500个reduce task 产生一个文件,这500个reduce task要怎么使用呢?答案是排序+索引,这就是sortshuffle的由来。

为了实现500个reduce task对一个文件的高效操作,map write的文件内部是有序的,并且还为该文件提供了一个索引文件。这样reduce task 就可以根据索引文件在该文件中找到自己对应的数据了。

该方式的map write的方式也发生了改变,类似于lsm的操作那样,每次内存写满了就一次性把内存数据进行排序,写入到磁盘生成一个文件,等到所有的数据都写入磁盘后,再对所有生成的文件进行一个归并排序。

这种shuffle的好处是大大减少了小文件的数量,且优化的力度不受限于reduce task的数量,只受限于map的数量。坏处是增加了一个排序的开销。

既然map write产生的文件都是有序的,为什么不再对同一台机器或core的的文件进行归并呢。答案是没有必要,太多的小文件会增大网络IO的开销,太少的文件对降低并发的利用率。不过,如果上游的数据量很大(map数量很多),而该key的基数(去重后的数量)比较小的话,还是可以考虑按core或jvm或机器级别进行合并的(合并还要考虑到索引的合并),不过spark没有提供这类优化。

三、bypass

bypass是sortshuffle的一种优化。上述提到,map write的文件内部做了全局排序。是为了多个reduce task能找到各自需要read的数据。但是在一个reduce task内,数据并不需要有序,而reduce task的数量一般远远小于数据行数(数据key的基数),所以这就造成了计算的浪费。

为了停止这种浪费,spark提出了新的shuffle优化bypass,即改变map write的方式,在write的时候,原来要对每一个flush到磁盘的小文件进行排序,现在不排序了,复制之前hashshuffle的做法,为每个reduce task写一个小文件。最后,将这些同一个map产生的小文件合并成一个大文件,合并的方式很简单,就直接追加就可以了,最后对结果文件增加一个索引,这样下游每一个reduce task都能找到自己要读的数据。这样既省下了排序的开销,又将小文件数量缩小到了2*M的数量(和sortshuffle一样)。可谓是兼具了hashshuffle和sortshuffle的优点。

不过该方法也有限制的地方。该shuffle不支持预聚合,map的数量也尽量要小(和最初的hashshuffle一样,map数量过大会产生过多的临时文件)

触发bypass的map数量上限可以用参数 spark.shuffle.sort.bypassMergeThreshold 设置

spark_shuffle方式的演进过程的更多相关文章

  1. P9架构师讲解从单机至亿级流量大型网站系统架构的演进过程

    阶段一.单机构建网站 网站的初期,我们经常会在单机上跑我们所有的程序和软件.此时我们使用一个容器,如tomcat.jetty.jboos,然后直接使用JSP/servlet技术,或者使用一些开源的框架 ...

  2. 阿里P9架构师讲解从单机至亿级流量大型网站系统架构的演进过程

    阶段一.单机构建网站 网站的初期,我们经常会在单机上跑我们所有的程序和软件.此时我们使用一个容器,如tomcat.jetty.jboos,然后直接使用JSP/servlet技术,或者使用一些开源的框架 ...

  3. Spring-cloud微服务实战【一】:微服务的概念与演进过程

    本文是一个系列文章,主要讲述使用spring-cloud进行微服务开发的实战.在开始之前,我们先说一下从传统的单一部署架构到微服务的发展过程,以便让童鞋们更好的理解微服务的概念与演进过程. 1.单体架 ...

  4. RPC 是通信协议吗 ?→ 我们来看下它的演进过程

    开心一刻 一实习小护士给我挂针,拿着针在我胳膊上扎了好几针也没找到血管 但这位小姑娘真镇定啊,表情严肃认真,势有不扎到血管不罢休的意思 十几针之后,我忍着剧痛,带着敬畏的表情问小护士:你这针法跟容嬷嬷 ...

  5. 框架源码系列四:手写Spring-配置(为什么要提供配置的方法、选择什么样的配置方式、配置方式的工作过程是怎样的、分步骤一个一个的去分析和设计)

    一.为什么要提供配置的方法 经过前面的手写Spring IOC.手写Spring DI.手写Spring AOP,我们知道要创建一个bean对象,需要用户先定义好bean,然后注册到bean工厂才能创 ...

  6. 图解 Kafka 超高并发网络架构演进过程

    阅读本文大约需要 30 分钟. 大家好,我是 华仔, 又跟大家见面了. 上一篇作为专题系列的第一篇,我们深度剖析了关于 Kafka 存储架构设计的实现细节,今天开启第二篇,我们来深度剖析下「Kafka ...

  7. Java的类演进过程

    1.从面向过程到面向对象 在大家最熟悉的C语言中,如果要定义一个复杂的数据类型就用结构体(Struct)来实现,而为结构体的每个操作都定义一个函数,这个函数与结构体本身的定义没有任何关系.程序的重心集 ...

  8. WINDOWS硬件通知应用程序的常方法(五种方式:异步过程调用APC,事件方式VxD,消息方式,异步I/O方式,事件方式WDM)

    摘要:在目前流行的Windows操作系统中,设备驱动程序是操纵硬件的最底层软件接口.为了共享在设备驱动程序设计过程中的经验,给出设备驱动程序通知应用程序的5种方法,详细说明每种方法的原理和实现过程,并 ...

  9. 浏览器打开URL的方式和加载过程

    不同浏览器的工作方式不完全一样,大体上,浏览器的核心是浏览器引擎,目前市场占有率最高的几种浏览器几乎都使用了不同的浏览器引擎:IE使用的是Trident.Firefox使用的是Gecko.Safari ...

随机推荐

  1. ES6 第二天

    三点运算符 <script type="text/javascript"> function func(...params){ params.forEach(funct ...

  2. DevOps之Jenkins相关知识

    目录 认识Jenkins 持续集成 持续交付 Jenkins简介 为什么需要Jenkins Jenkins的目标 Jenkins安装 初次使用Jenkins 加速插件安装 Jenkins-CI Jen ...

  3. C语言-内存函数的实现(一)之memcpy

    C语言中的内存函数有如下这些 memcpy memmove memcmp memset 下面看看memcpy函数 memcpy 我们想想,之前有那个字符串拷贝的函数,即strcpy函数.都有拷贝的函数 ...

  4. Mycat Web监控工具

    简介 Mycat-web 是 Mycat 可视化运维的管理和监控平台,弥补了 Mycat 在监控上的空白.帮 Mycat 分担统计任务和配置管理任务.Mycat-web 引入了 ZooKeeper 作 ...

  5. Day07_35_Colection下的方法

    Collection 下的方法 * **Collection 集合的方法应用** ``` package com.shige.Collection; import java.util.ArrayLis ...

  6. IOS Widget(1):概述

    引言   本系列文章作者是安卓开发,以安卓开发的视角学习IOS小组件,记录一下踩坑记录,如有讲得不对的地方,路过大佬多包涵.如果你是想深入学习小组件,建议您顺着笔者的编号顺序阅读本系列文章.如果曾经了 ...

  7. 2- 计算机的组成以及VMware使用

    计算机的组成: 硬件: 处理器(CPU):I3 I5 I7 运行内存RAM(存储数据) 容量(字节为单位) 主板(总线设备) 输入输出设备(显示屏,键盘,鼠标,触目屏) 外部存储设备(硬盘,U盘,TF ...

  8. Windows系统之间文件互传

    1)利用Windows自带的文件共享服务 本次试验以Win7为服务器端,win10为客户端 1.确保Win7服务端开启对应的服务及开放相应的端口号 进入命令行界面,输入netstat -an,查看44 ...

  9. 基于Frida框架打造Art模式下的脱壳工具(OpenMemory)的原理分析

    本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80956614 作者dstmath在看雪论坛公布一个Android的art模式下基 ...

  10. POJ 2396 构造矩阵(上下流)

    题意:       要求构造一个矩阵,给你行和,列和,还有一些点的上下范围,输出一个满足题意的矩阵. 思路:       这个题目很经典,这是自己看上下流后接触的第一道题,感觉很基础的一道题目,现在我 ...