我的观念:数仓工程师的理论,需求在不断的实践中得到查验,终究才干沉淀为自己的知识与才能

作为第一篇关于数仓的文章,正好结合最近实践事例中的一次数据歪斜问题,来聊聊排查思路与修复计划

事发场景

在本周某天早上,意外收到某张宽表的报错(已跑了一个多月且近期没有任何修改)

当时还挺严重的,由于本周刚用这张表给管理层支持了核心看板

也来不及多想了,以处理问题优先

处理过程

  1. 先看看系统提供的报错信息

过错原因:Executor OOM

处理计划:Executor内存不足(堆内存溢出),请扩大内存参数重跑

参数主张:set spark.executor.memory=12g

由于不是Driver OOM,能够暂不考虑播送数据大小超过阈值的问题

猜测大概率是产生数据歪斜,导致某(几)个Executor的需处理的数据量过大

  1. 直接尝试调大内存后履行

万一成功了岂不是省时间了?

但与此同时,咱们仍是需求排查问题,由于加参数只是一种在事务SQL调优达到瓶颈后如虎添翼的手段

究竟有相当大的概率,加了参数后也是会履行失利

并且如果是Executor数据歪斜,调大参数后任务报错所花费的时间会更长

  1. 打开Spark UI检查卡点

3.1. 点击上方Tab里的「Stages」,能够看到详细失利在哪个Stage

Vol.01 实践事例-数据歪斜
Vol.01 实践事例-数据歪斜

3.2. 点击上方Tab里的「SQL」,通过WholeStageCodegen (8) 往上查找对应表名等信息,以判断是SQL的哪个位置

Vol.01 实践事例-数据歪斜

3.3. 点击「Description」对应的链接,检查详细的WholeStageCodegen (X)

  1. 终究定位到详细的SQL

已依据实践的杂乱SQL处理成好了解的简单SQL

select a.*
from a
left join b
    on  a.id = b.id
    and nvl(a.id, '-1') != '-1'
where a.日期分区 = 'XXXX'
  and b.id is not null

由于一些事务场景,该「id字段」实践不存在对应的事务值,咱们以-1进行填充,且事前也知道-1的量远超其他值

我个人写SQL的时分会以这样的方法,尝试去避免歪斜:期望-1不参加相关,预期的作用如下

-- 非-1的参加相关
select a.*
from a
left join b    -- 非日期分区表
    on a.id = b.id
where a.日期分区 = 'XXXX'
  and a.id != '-1'
  and b.id is not null
union all
-- -1单独处理并兼并
select a.*
from a
where a.日期分区 = 'XXXX'
  and a.id = '-1'
;

但依据终究的情况与成果看,-1的那些记载也参加了相关时的分组操作,否则也不会存在歪斜现象

经过了一开始的改参数调内存、再到仔细翻阅SQL,终究是将SQL从改成了第二段后成功履行

事后复盘

  1. 为什么近期未修改过的SQL,会莫名其妙产生歪斜了呢?

还记得排查问题期间,歪斜的那块UI履行计划上写的是ShuffledHashJoin吗?

我打开了前几天任务的履行计划,发现这块的相关操作都是播送BroadcastHashJoin

Vol.01 实践事例-数据歪斜

瞬间就明白了,看来是小表的数据量近期渐渐变大,超过了系统装备的播送阈值,因而从 BroadcastHashJoin 变成了 ShuffledHashJoin

  1. 那!= ‘-1’ 写在on里,其履行计划是什么样的呢?

我将「处理过程」中「4. 终究定位到详细的SQL」中,两段SQL的物理履行计划进行比较

  1. 歪斜SQL的核心履行计划

Vol.01 实践事例-数据歪斜

  1. 非歪斜SQL的核心履行计划

Vol.01 实践事例-数据歪斜

依据履行计划看下来,on里虽然写了左表的条件过滤,期望其不参加相关,但对应的值仍是会参加hashpartitioning

后续处理

排查一下这个核心链路上,是否还有其他类似的id相关(即存在空字符串、-1、0、null的情况)

如有,看是否需求使用**id != '-1' union all id = '-1'** 的快速方法优先处理

由于这个条链路是新上的(服务于核心看板),加上自己也疏忽未装备相应的电话告警(我是正好清晨醒了一下,看了眼手机);需求装备一下信息

漫笔慨叹

清晨调度的SQL,截止成功履行的那一刻前,你都不知道会不会产生什么事情意外的事情

至于面试时常被问到的数据歪斜问题,市面上的处理计划大部分数仓工程师应该都能口述几个

  1. 歪斜的Key单独拎出来进行 union all(像我这样)
  2. 找一个其他分散的字段打散后再处理
  3. 能走播送的话走播送

但真到了实战中,我觉得下述内容才是数仓工程师需求不断打磨、坚持的

  • 如安在杂乱的SQL代码中快速定位到详细的问题点

  • 找到长期有效的处理办法

  • 有强烈的责任心、夜间保证认识

数仓便是这样