数据倾斜浅述

数据倾斜

数据倾斜

数据倾斜即指在大数据计算任务中某个处理任务的进程(通常是一个JVM进程)被分配到的任务量过多,进程运行时间超长甚至最终失败,进而导致整个计算任务超长时间运行或失败的问题。

  • 外部表现的话,在MR任务(如跑HiveSQL)里看到map或reduce的进度一直是99%持续数小时没有变化;
  • 在SparkSQL任务重则是某个stage里,正在运行的任务数量长时间是1或者2不变。

简而言之,如果任务进度信息一直在输出,但内容长时间没有任何变化的时候,大概率是出现数据倾斜了。

有个特例需要注意,有时大家会看到SparkSQL的任务信息也显示有1到2个任务在运行中,但进度信息不再刷新而表现为假死很久的时候,这通常是进行最后阶段的文件操作,并不是数据倾斜(这通常意味着小文件问题严重)

类型分类

读倾斜

在读取数据阶段长期无法完成,这通常是因为文件分块过大或分块数据有异常,这种情况出现频率较小。

算倾斜

即在某个需要排序(如开窗函数或非广播关联时)或者聚合操作时候,同一个key(通常是一个或者多个字段或者表达式的组合)的处理耗时过长。这通常是最多的情况,情况也较为复杂。

大数据中动辄上亿行的数据,如果有排序(order by或sort by)的需求且数据量巨大的话,通常会产生溢写磁盘的操作,非常耗时,且容易造成OOM异常。99.99%的大数据场景下,完全的排序都是不必要的,因为业务通常需要的统计信息而非具体某一条记录的细节信息。

写倾斜

即某个操作需要输出大量数据,如超过几亿或者几十亿行。主要出现在关联后数据膨胀或某些只能由一个task来操作(如limit)的情况。

表关联,举例两张表join可能产生数十亿行记录。问题本质是一个task最多由一个进程来执行,而相同的key也必须在同一个task中处理。因为在无法改变这个机制的前提下,我们只有想办法减少一个task输出的行数

文件操作倾斜

即数据生成在临时文件夹后,由于数量巨大,重名民或移动的操作非常耗时,这通常发生在动态分区导致小文件的情况。

原因剖析与解决出发点

为什么会有数据倾斜

  1. 业务数据分布规律无法预知,比如系统无法不经过计算而提前知道某个表的某个字段的取值分布是否大致均匀
  2. 计算结果数量无法预知。比如两表关联的结果对于某些key(关联一个字段或多个字段组合)的输出行数无法不经过计算而预知而针对性处理:又比如某个字段的值进行split操作或者explode等操作后产生的结果数量无法预知而进行针对性的应对
  3. 某些操作只能由单一节点进行,一切需要维护一个全局状态的大多数操作,如排序、limit、count、distinct、全局聚合等,一般会安排到一个节点来执行,有概率导致在单节点上处理巨量的数据,造成所谓的倾斜问题。

当然,这些困难并不是理论上不可避免的,随着时间的推移,越来越多的针对性优化措施已逐渐出现(如spark3已经能自动应对部分数据倾斜的情况了),也许在不久的将来业务同学不会再被倾斜问题烦恼,但现阶段还需数据开发工程师主动关注并应对。

从业务逻辑审视出发

如果发生了数据倾斜,有不小的概率是业务逻辑/需求不合理,需要跟业务方反复确认逻辑的合理性,优化业务逻辑一定要高过优化技术方案。