如何解决数据倾斜问题?

转载:https://blog.csdn.net/Mr_HHH/article/details/89399518

今天在工作中遇到了数据倾斜的问题,一条SQL执行了8小时才执行完,看计划是先join再做distinct,卡在了join上,数据量比较大,并且重复数据比较多,后续经过分析计划,查资料,在不影响结果的前提下,改为先进行distinct,然后再join,最后在2min12s就出了结果。

在网上查找资料时,发现与这篇文章中的解决数据倾斜的办法有相同的部分。

目前流行的大数据相关的计算框架之所以能够处理大量的数据和计算,基本上都是依赖分布式计算的思想,即由一个通过某种组织关系连接在一起的集群来共同完成计算任务。

这是一个非常好的计算模型,无论多大的数据量,只要集群可以扩展,就能够扩充算力,自如应对,但与此同时,也为数据倾斜的产生埋下了伏笔。

1:什么是数据倾斜?

前面提到分布式计算,是一个集群共同承担计算任务,理想状态下,每个计算节点应该承担相近数据量的计算任务,然而实际情况通常不会这么理想,数据分配严重不均就会产生数据倾斜。我们先来给数据倾斜下个明确点的定义。

数据倾斜,指的是并行处理的过程中,某些分区或节点处理的数据,显著高于其他分区或节点,导致这部分的数据处理任务比其他任务要大很多,从而成为这个阶段执行最慢的部分,进而成为整个作业执行的瓶颈,甚至直接导致作业失败。

举个实际发生的例子说明下,一个spark作业,其中有个stage是由200个partition组成,在实际执行中,有198个partition在10秒内就完成了,但是有两个partition执行了3分钟都没有完成,并且在执行5分钟后失败了。这便是典型的数据倾斜场景,通过观察SparkUI发现这两个partition要处理的数据是其他partition的30多倍,属于比较严重的数据倾斜。

2:数据倾斜的危害

知道了什么是数据倾斜,那么它到底有什么危害,让大家这么痛恨它的同时,又很畏惧它呢。

数据倾斜主要有三点危害:

危害一:任务长时间挂起,资源利用率下降

计算作业通常是分阶段进行的,阶段与阶段之间通常存在数据上的依赖关系,也就是说后一阶段需要等前一阶段执行完才能开始。

举个例子,Stage1在Stage0之后执行,假如Stage1依赖Stage0产生的数据结果,那么Stage1必须等待Stage0执行完成后才能开始,如果这时Stage0因为数据倾斜问题,导致任务执行时长过长,或者直接挂起,那么Stage1将一直处于等待状态,整个作业也就一直挂起。这个时候,资源被这个作业占据,但是却只有极少数task在执行,造成计算资源的严重浪费,利用率下降。

危害二:由引发内存溢出,导致任务失败

数据发生倾斜时,可能导致大量数据集中在少数几个节点上,在计算执行中由于要处理的数据超出了单个节点的能力范围,最终导致内存被撑爆,报OOM异常,直接导致任务失败。

危害三:作业执行时间超出预期,导致后续依赖数据结果的作业出错

有时候作业与作业之间,并没有构建强依赖关系,而是通过执行时间的前后时间差来调度,当前置作业未在预期时间范围内完成执行,那么当后续作业启动时便无法读取到其所需要的最新数据,从而导致连续出错。

可以看出,数据倾斜问题,就像是一个隐藏的杀手,潜伏在数据处理与分析的过程中,只要一出手,非死即伤。那么它又是如何产生的呢?想要解决它,我们就要先了解它。

3:为什么会产生数据倾斜?

3.1:读入数据的时候就是倾斜的

读入数据是计算任务的开始,但是往往这个阶段就可能已经开始出现问题了。

对于一些本身就可能倾斜的数据源,在读入阶段就可能出现个别partition执行时长过长或直接失败,如读取id分布跨度较大的mysql数据、partition分配不均的kafka数据或不可分割的压缩文件。

这些场景下,数据在读取阶段或者读取后的第一个计算阶段,就会容易执行过慢或报错。

3.2:shuffle产生倾斜

在shuffle阶段造成倾斜,在实际的工作中更加常见,比如特定key值数量过多,导致join发生时,大量数据涌向一个节点,导致数据严重倾斜,个别节点的读写压力是其他节点的好几倍,容易引发OOM错误。

3.3:过滤导致倾斜

有些场景下,数据原本是均衡的,但是由于进行了一系列的数据剔除操作,可能在过滤掉大量数据后,造成数据的倾斜。

例如,大部分节点都被过滤掉了很多数据,只剩下少量数据,但是个别节点的数据被过滤掉的很少,保留着大部分的数据。这种情况下,一般不会OOM,但是倾斜的数据可能会随着计算逐渐累积,最终引发问题。

4:怎么预防或解决数据倾斜问题?

4.1.尽量保证数据源是均衡的

程序读入的数据源通常是上个阶段其他作业产生的,那么我们在上个阶段作业生成数据时,就要注意这个问题,尽量不要给下游作业埋坑。

如果所有作业都注意到并谨慎处理了这个问题,那么出现读入时倾斜的可能性会大大降低。

这个有个小建议,在程序输出写文件时,尽量不要用coalesce,而是用repartition,这样写出的数据,各文件大小往往是均衡的。

4.2.对大数据集做过滤,结束后做repartition

对比较大的数据集做完过滤后,如果过滤掉了绝大部分数据,在进行下一步操作前,最好可以做一次repartition,让数据重回均匀分布的状态,否则失衡的数据集,在进行后续计算时,可能会逐渐累积倾斜的状态,容易产生错误。

4.3.对小表进行广播

如果两个数据量差异较大的表做join时,发生数据倾斜的常见解决方法,是将小表广播到每个节点去,这样就可以实现map端join,从而省掉shuffle,避免了大量数据在个别节点上的汇聚,执行效率也大大提升。

4.4.编码时要注意,不要人为造成倾斜

在写代码时,也要多加注意不要使用容易出问题的算子,如上文提到的coalesce。

另外,也要注意不要人为造成倾斜,如作者一次在帮别人排查倾斜问题时发现,他在代码中使用开窗函数,其中写到over (partition by 1),这样就把所有数据分配到一个分区内,人为造成了倾斜。

4.5.join前优化

个别场景下,两个表join,某些特殊key值可能很多,很容易产生数据倾斜,这时可以根据实际计算进行join前优化。

如计算是先join后根据key聚合,那可以改为先根据key聚合然后再join。又如,需求是join后做distinct操作,在不影响结果的前提下,可以改为先distinct,然后再join。这些措施都是可以有效避免重复key过多导致join时倾斜。

4.6.具体问题具体分析

某些具体问题或者解决方案,不具备普遍性,但是也可以作为一种思路参考。

例如,读入mysql数据时倾斜,这通常是由于mysql的id分布严重不均,中间存在跨度很大的区间造成的。解决方法有两种,一是加大读取时的分区数,将倾斜的区间划分开;另一种是,先把id取出来进行等宽切割,确保每个区段的id数量一致,之后再对各区间进行数据读取。

本文介绍了什么是数据倾斜、它的危害、产生的原因及一些常用的解决方案,希望可以帮助大家,加深对数据倾斜的认识,如果遇到类似问题,可以快速上手解决掉。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463346.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

白盒测试不是测试,更不高级

测试不仅仅是软件概念,但白盒测试仅仅是软件概念。 上面这句话足以说明白盒测试不是测试,至少不等同于测试。 认为白盒测试更牛逼的一个常用论据是白盒测试需要对代码本身更高的熟悉程度,但说这样的话的人往往没有搞清楚测试究竟需要什么样的…

剑指Offer题解(Python版)

https://blog.csdn.net/tinkle181129/article/details/79326023# 二叉树的镜像 链表中环的入口结点 删除链表中重复的结点 从尾到头打印链表 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 把字符串转换成整数 平衡二叉树 和为S的连续正数序列 左…

Paypal 在线支付接口应用从零开始,第2节,[支付API原理及流程]

今天看看Paypal支付流程和简单的认证原理,我画了一张图.应该能表达这两点意思了我们的站点名字,为了好理解,暂且就定为西狐的网站吧.点此查看清晰原图恩,理论知识很重要哈,先把这图理解了,下一步我们编程使用沙盒测试就很简单了.如果想更多研究一下还可直接查看Paypal官方提供的…

C语言指针深度理解

指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大…

PLSQL DEVELOPER 使用技巧

为什么80%的码农都做不了架构师?>>> 1、右键菜单 在PL/SQL Developer(下面简称PLD)中的每一个文本编辑窗口,如SQL Window,Command Window和Porgram Window,右键点击某个对象名称,会…

为什么不能同时用const和static修饰成员函数?

const修饰的函数: 表示在该函数体内不能修改成员的值,会在函数中添加一个隐式的参数const this*. static修饰的函数没有this指针,与const的用法冲突。 但可以使用static和const修饰成员。 例子如下: class Singleton { public: stati…

对于一颗完全二叉树,要求给所有节点加上一个pNext指针,指向同一层的相邻节点;如果当前节点已经是该层的最后一个节点,则将pNext指针指向NULL;给出程序实现,并分析时间复杂度和空间复杂度。

typedef struct TNode { int data; TNode* left; TNode* right; TNode* next; }; //时间复杂度为O(n)&#xff0c;空间复杂度为O(n) void addNext(TNode* root) { if (!root) { return; } queue<TNode*> q; q.push(root); while (!q.empty()) { int levelL…

T-SQL DML学习笔记

1. select 语句的基本结构是 select -->From-->where group By Having Order By 2. Exists 条件 Exists 后面括号内的条件语句如果为真的话 这此次查询继续 &#xff0c;如Exists跟的条件语句没有查询到数据则前面语句块的查询不再执行下去 select province…

反射--Class获得

/* Java提供3种方式获得Class对象 * * 不同应用场景&#xff0c;需要不同的方式获得Class对象 * * 方式&#xff1a; * 1.通过字符串&#xff08;全限定类名&#xff09;获得 * 格式&#xff1a;Class clazz Class.forName("字符串"); * 全限定类名&#xff1a;包名…

Android Drawable绘图学习笔记

如何获取 res 中的资源 数据包package&#xff1a;android.content.res 主要类&#xff1a;ResourcesAndroid SDK中的简介&#xff1a;Class for accessing an application’s resources.Class for accessing an application’s resources. This sits on top of the asset mana…

在类中调用delete this问题

转载&#xff1a;https://blog.csdn.net/kuimzzs/article/details/81517451 很多时候&#xff0c;一些定义在类内的变量的生命周期在类外并不是很好的掌控&#xff0c;这样就很容易造成内存泄漏得到问题 比如以下代码&#xff1a; class Test { public: void foo(); pri…

C++中对多态的理解

1 多态&#xff1a;是指类中具有相似功能的不同函数&#xff0c;使用同一个名称来实现&#xff1b;是对类的行为再抽象&#xff1b;多态是通过重载函数和虚函数来实现的。 2 继承讨论的是类与类的层次关系&#xff0c;多态则是考虑在不同层次的类中&#xff0c;以及在同一个类…

C#.NET中的事件2

/** Created by SharpDevelop. * User: noo * Date: 2009-8-17 * Time: 15:34 * * 事件2 */usingSystem ;usingSystem .Windows .Forms ;classTest { staticvoidMain()//入口函数{ Form frmnewForm ();//新建一窗体frm.Text "我的窗体"; …

HTML学习之基础

HTML是网页的标记语言不是编程语言&#xff0c;有一些标记段组成。大小写不敏感&#xff0c;可以用常用的编辑器软件编写用浏览器打开即可 有不同的版本<!DOCTYPE html> <meta charset"utf-8">在<title>前为了能正常显示中文。 超链接&#xff1a;…

linux最基础的几个指令

cd 切换目录使用 pwd 显示当前目录路径 ls 列出目录内容 跟参数 -a 显示所有文件和目录 -A 显示所有文件包括隐藏-l 使用详细格式列出-d 显示目录名称而非内容-i 显示文件和目录的inode号-Z 显示文件和目录的上下文-R 子目录显示touch 创建文件或者改变文件时间 touch 2…

Advapi 登录类型8的错误

登录类型8&#xff1a;网络明文&#xff08;NetworkCleartext&#xff09; 这种登录表明这是一个像类型3一样的网络登录&#xff0c;但是这种登录的密码在网络上是通过明文传输的&#xff0c;WindowsServer服务是不允许通过明文验证连接到共享文件夹或打印机的&#xff0c;据我…

Varint

什么是Varint Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字&#xff0c;值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。 比如对于 int32 类型的数字&#xff0c;一般需要 4 个 byte 来表示。但是采用 Varint&#xff0c;对于很小的 …

Ubuntu 17.10安装Qt 5.10环境与Qt Creator 4.5开发工具(转自linux公社)

记录下在Ubuntu 17.10搭建Qt环境与安装Qt Creator开发工具的过程。机器装的Linux是Ubuntu 17.10&#xff0c;16.04与17.04的应该也相同。Qt 5.10和Qt 3D Studio发布 http://www.linuxidc.com/Linux/2017-12/149267.htm 1&#xff0c;Qt安装 1.1 下载Qt 这里提供Qt Creator的下…

服务器USB启动故障一例

前几日&#xff0c;本公司一台prop平台服务器&#xff08;hp 380G5服务器&#xff09;接上key&#xff08;usb口&#xff09;后&#xff0c;出现重启不能启动现象&#xff0c;进入服务器bios设置启动项为硬盘启动也不行&#xff0c;之后仔细查看服务器usb控制选项&#xff1a;可…

C#基础(201)--常量枚举

本文知识点&#xff1a; 1.掌握常量的定义和使用方法 2.理解枚举的作用和特点 3.掌握枚举的使用方法 1.1.常量的定义语法 const 数据类型 常量名称 值&#xff1b; 1.2.常见错误 1.3常量的使用时机 经常使用并且值不变的变量&#xff0c;可以定义为常量 2.1枚举的作用及其…