兼顾性能的数据倾斜处理方案

目录

前言

一、场景描述

二、常见的优化方法

2.1 Mapjoin

2.2 特殊值/空值打散

2.3 热点值打散,副表呈倍数扩散

2.4 热点数据单独处理/SkewJoin

2.5 方案总结

三、Distmapjoin

3.1 核心思路

3.2 代码实现

3.3 真实效果

四、方案总结

   文章主要是介绍在支付宝支付数据链路改造升级过程中,针对数据倾斜的优化实践方案,在解决数据倾斜问题的同时,还能兼顾更优的计算性能。

一、场景描述

  数据倾斜可能发生在join,group by,count distinct等环节,但本质上其实都类似,即因为数据重分发或重分布等原因,导致大部分数据仅分发到少数几个计算节点上。以ODPS场景为例,少数几个Fuxi Instance处理的数据量,远大于同一环节的其他Instance处理的数据量,并伴有明显的长尾现象。

  典型的案例是在淘宝双十一场景中,交易订单明细大表需要关联商家信息维表以补全商家信息,在数据关联处理中,同一个商家对应的交易订单个维表对应商家信息,将根据卖家ID shuffle至同一个数据处理节点上。由于TOP商家在大促中产生的交易单量远大于普通商家, 从而导致大量的数据集中到一台或者几台机器上计算,这些数据的计算速度将远远低于平均计算速度,导致整个计算过程被拖慢。

  如上图所示,数据重分发过程中,按照Join Key(即卖家ID)进行shuffle,大部分交易数据记录分发至处理节点1,导致三个并发处理节点中,处理节点1需要处理的数据量远大于其他两个处理节点,从而造成数据处理的不均匀,即数据倾斜。

二、常见的优化方法

2.1 Mapjoin

  实现原理是:通过把小表广播到大表所在计算节点上,有效避免了大表的shuffle,因而避免了数据重分布导致的数据倾斜。若大表数据的原始分布本身就有不均匀的情况,此时也可以通过增加随机重分布的临时打散方式,将数据打的散一些,再通过Mapjoin实现数据关联。

SELECT /*+MAPJOIN(dim)*/  * 
FROM (SELECT * FROM dwd_tbl) base 
LEFT OUTER JOIN (SELECT * FROM dim_tbl) dim
ON base.dim_key = dim.dim_key

2.2 特殊值/空值打散

  • 特殊值/空值场景也比较普遍,比如主表中有个属性字段在某些场景下为空或者为一些无业务含义的特殊字符串(如DEFAULT),然后此属性字段本身对应了一张数据量较大的维表,需要关联打宽补全。此时做数据关联,由于两张表按照关联key进行shuffle,就会导致主表中该字段为空/相同特殊字符串的数据记录shuffle到同一个节点上,从而导致数据倾斜。
  • 此类场景好解决,对特殊值/空值在关联时转为随机值就行。
SELECT * 
FROM (SELECT * FROM dwd_tbl) base 
LEFT JOIN (SELECT * FROM dim_tbl) dim
ON IF(COALESCE(base.dim_key,'')='',CONCAT('HIVE_',RAND()),base.dim_key) = dim.dim_key

2.3 热点值打散,副表呈倍数扩散

  • 此类方法使用较少,实现原理是对主表附加一个随机值(例如1~10)字段,记为ext_a字段,然后对应被关联维表数据按照对应倍数进行复制膨胀,并依次赋予1~10的编号,记为ext_b字段,然后在关联两张表时把ext_a、ext_b两个字段也作为关联字段之一。
  • 此方法适用于被关联表远远比主表小,但又因数据大小超过内存容量而无法使用Mapjoin,且主表的数据倾斜程度不大的情况下可以使用,但整体上此方案只能对数据热点成倍数的削弱
SELECT * 
FROM (
    SELECT *,CAST(RAND()*10 AS BIGINT) AS ext_a
    FROM dwd_tbl
 --主表dwd_tbl
) base 
LEFT JOIN (
    SELECT *
    FROM dim_tbl
   --被关联表 dim_tbl
    LATERAL VIEW EXPLODE(SPLIT('0;1;2;3;4;5;6;7;8;9',';')) tt AS ext_b
    -- 或者Join一个用于倍数膨胀的小表
) dim
ON  base.dim_key = dim.dim_key
AND base.ext_a   = dim.ext_b

2.4 热点数据单独处理/SkewJoin

  • 使用此方法通常也意味着被关联的维表数据大小较大,无法使用Mapjoin,只能走普通shuffle模式的join方案。此类场景最典型的案例就是双十一淘系交易大表去关联商家维表,此时的商家维表因记录数和数据大小都较大,所以无法放入到内存,此外部分商家的交易单量远超大盘平均,此时的数据倾斜就需要使用热点数据单独处理的方案。
  • 将热点数据提取出来单独处理,可以用Mapjoin的方式完成关联维表热点记录行,非热点则使用普通的shuffle模式的join完成关联。
  • 具体操作主要分为三个部分:基于主表统计获得Top热点的属性值:用热点属性值将关联维表拆成热点小表和非热点表,同时也将主表拆成热点主表和非热点主表;热点小表通过Mapjoin与热点主表join,非热点表与非热点主表join,最终两部分再union到一起,完成数据关联。

-- Step01:热点数据记录提取
INSERT OVERWRITE TABLE tmp_hot_list PARTITION (dt = '${bizdate}')
SELECT   dim_shop_id AS hot_id
FROM   main_table
WHERE   dt = '${bizdate}'
GROUP BY dim_shop_id
HAVING COUNT(1) > 10000;


INSERT OVERWRITE TABLE final_result_table PARTITION (dt = '${bizdate}')
-- Step02:热点数据处理,使用MapJoin完成处理
SELECT   /*+MAPJOIN(a2,a3)*/ 
         a1.trade_no    AS trade_no
        ,a1.dim_shop_id AS shop_id
        ,a3.shop_name   AS shop_name
        ,a3.shop_type   AS shop_type
FROM (SELECT * FROM main_table WHERE dt = '${bizdate}') a1 

-- Step02-1:主表用JOIN关联热点表进行热点记录筛选
JOIN (SELECT * FROM tmp_hot_list WHERE dt = '${bizdate}') a2 -- 热点数据清单
ON a1.dim_shop_id = a2.dim_shop_id
-- Step02-2:热点维度数据处理
LEFT OUTER JOIN (
    SELECT /*+MAPJOIN(b2)*/ b1.*
    FROM  (SELECT * FROM dim_table_info WHERE dt = '${bizdate}') b1
    JOIN  (SELECT * FROM tmp_hot_list   WHERE dt = '${bizdate}') b2 -- 热点数据清单
    ON    b1.dim_shop_id = b2.dim_shop_id
) a3
ON    a1.dim_shop_id = a3.dim_shop_id
UNION ALL 
-- Step03:非热点数据处理,使用普通Join完成处理,两张表均需要进行Shuffle
SELECT   /*+MAPJOIN(a12)*/ 
         a11.trade_no    AS trade_no
        ,a11.dim_shop_id AS shop_id
        ,a13.shop_name   AS shop_name
        ,a13.shop_type   AS shop_type
FROM (SELECT * FROM main_table WHERE dt = '${bizdate}') a11 
-- Step03-1:主表用ANTI JOIN关联热点表进行剔除
LEFT ANTI JOIN (SELECT * FROM tmp_hot_list WHERE dt = '${bizdate}') a12
ON a11.dim_shop_id = a12.dim_shop_id
-- Step03-2:非热点维度数据处理
LEFT OUTER JOIN (
    SELECT /*+MAPJOIN(b12)*/ b11.*
    FROM  (SELECT * FROM dim_table_info WHERE dt = '${bizdate}') b11
    LEFT ANTI JOIN  (SELECT * FROM tmp_hot_list WHERE dt = '${bizdate}') b12
    ON    b11.dim_shop_id = b12.dim_shop_id
) a13
ON a11.dim_shop_id = a13.dim_shop_id
  • 整个步骤稍有些复杂,这里也可以直接用平台的skewjoin参数完成倾斜处理, skew的核心思路就是上面提到的热点数据单独处理,只是做了平台级别的集成,方便用户一键解决数据倾斜问题。
INSERT OVERWRITE TABLE final_result_table PARTITION (dt = '${bizdate}')
SELECT  /*+SKEWJOIN(a1)*/ 
         a1.trade_no    AS trade_no
        ,a1.dim_shop_id AS shop_id
        ,a2.shop_name   AS shop_name
        ,a2.shop_type   AS shop_type
FROM (SELECT * FROM main_table   WHERE dt = '${bizdate}') a1 
LEFT JOIN (SELECT * FROM dim_table_info WHERE dt = '${bizdate}') a2 
ON  a1.dim_shop_id = a2.dim_shop_id;

2.5 方案总结

  总结,上面集中方案核心都是在围绕解决数据重分发(即为shuffle)导致的热点问题,一种是采用Mapjoin的方式避免热点数据重分发,一种是让数据充分发过程中尽可能的均匀。

三、Distmapjoin

3.1 核心思路

 数据倾斜的核心在于数据处理不均匀,而数据处理的不均匀往往又来自于数据重分发,也就是shuffle。因此如果能解决好shuffle不均匀问题,或者在不需要对大表进行shuffle的同时就能完成数据关联计算的操作,就能避免数据倾斜的问题。

   Mapjoin用于处理热点数据,将维表热点记录广播至大表所在计算节点;Distmapjoin用于处理非热点数据,用于通过构建远程分布式查询节点,实现大表在无需移动的情况下,完成数据关联操作。

https://help.aliyun.com/zh/maxcompute/user-guide/distributed-mapjoin?spm=a2c4g.11186623.0.i1#concept-2197457icon-default.png?t=N7T8https://help.aliyun.com/zh/maxcompute/user-guide/distributed-mapjoin?spm=a2c4g.11186623.0.i1#concept-2197457

3.2 代码实现

WITH 
-- STEP01:热点Key采集
tmp_hot_pid AS (
    SELECT dim_shop_id,'Y' AS is_hot
    FROM main_table_detail
    WHERE dt = '${bizdate}'
    GROUP BY dim_shop_id
    HAVING COUNT(1) > 100000
)
-- STEP02:维表热点数据打标
,tmp_dim_tbl AS (
    SELECT   /*+MAPJOIN(hot)*/ 
              dim.*
            ,COALESCE(hot.is_hot,'N') AS is_hot
    FROM (
        SELECT *
        FROM dim_table_info
        WHERE dt = '${bizdate}'
    ) dim
    LEFT OUTER JOIN tmp_hot_pid hot 
    ON dim.dim_shop_id = hot.dim_shop_id
)
-- STEP03:明细热点数据打标
,tmp_dwd_tbl AS (
    SELECT /*+MAPJOIN(hot)*/ 
             base.*
            ,COALESCE(hot.is_hot,'N') AS is_hot
    FROM (
        SELECT *
        FROM main_table_detail
        WHERE dt = '${bizdate}'
    ) base 
    LEFT OUTER JOIN tmp_hot_pid hot 
    ON base.dim_shop_id = hot.dim_shop_id
)

-- STEP04:数据合并处理,热点数据用Mapjoin,非热点数据用DISTMAPJOIN
INSERT OVERWRITE TABLE final_result_table PARTITION (dt = '${bizdate}')
SELECT *
FROM (
    -- STEP04-1:非热点数据用DISTMAPJOIN
    SELECT  /*+ DISTMAPJOIN(dim(shard_count=77)) */ 
           dwd_tbl.trade_no   AS trade_no
          ,dwd_tbl.trade_date AS trade_date
          ,dwd_tbl.shop_id    AS shop_id
          ,dim.shop_name      AS shop_name
          ,dim.shop_type      AS shop_type
    FROM (SELECT * FROM tmp_dwd_tbl WHERE is_hot = 'N') dwd_tbl
    LEFT OUTER JOIN (SELECT * FROM tmp_dim_tbl WHERE is_hot = 'N') dim 
    ON dwd_tbl.partner_id = dim.partner_id
    UNION ALL
    -- STEP04-1:热点数据用Mapjoin
    SELECT /*+MAPJOIN(dim)*/ 
           dwd_tbl.trade_no   AS trade_no
          ,dwd_tbl.trade_date AS trade_date
          ,dwd_tbl.shop_id    AS shop_id
          ,dim.shop_name      AS shop_name
          ,dim.shop_type      AS shop_type
    FROM (SELECT *FROM tmp_dwd_tbl WHERE is_hot = 'Y') dwd_tbl
    LEFT OUTER JOIN (SELECT *FROM tmp_dim_tbl WHERE is_hot = 'Y') dim 
    ON dwd_tbl.partner_id = dim.partner_id
) base ;

3.3 真实效果

   当前新方案在支付宝核心支付数据链路上线,给相关可优化节点带来了平均40%的计算耗时缩减和平均30%的计算资源缩减。方案主要应用于支付交易join商家维表、支付交易join合约维表等场景,方案将原本需要手动拆分热点利用“Mapjoin+shuffle进行热点数据处理”的过程,改为利用Distmapjoin或Mapjoin+Distmapjoin的方案,让支付交易大表在计算全过程中均无需移动,在解决数据倾斜问题的同时,也实现了降低计算资源和提升产出时效。

四、方案总结

上面介绍了一种结合Mapjoin和Distmapjoin的数据倾斜处理方案,在有效解决数据倾斜问题的同时还可以避免大表的shuffle,提供了更优的性能表现。实际上如果数据倾斜情况不是特别严重(比如 热点数据行/平均单节点处理数据行 < 100),完全可以直接使用纯Distmapjoin的方案。

综合我们基于Distmapjoin提出的两种方案,我们结合各种方案的优劣势进行方案分级,然后根据具体场景进行更优的方案选择。

参考文章:

https://mp.weixin.qq.com/s/VGgT1faRKGnUuQ-HHQ3Q5g

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用自己训练的superpoint与superglue模型进行图像配准

基于官方团队发布的预训练模型&#xff0c;使用SuperPoint与SuperGlue实现图像配准&#xff0c;可以参考https://blog.csdn.net/a486259/article/details/129093084 基于官方团队发布的代码训练自己的模型&#xff0c;可以参考https://blog.csdn.net/a486259/article/details/…

xilinx原语详解及仿真——ISERDESE2

前面在讲解HDMI接口之前&#xff0c;讲解过IDDR、ODDR、OSERDESE2、IBUFDS等原语&#xff0c;之后一直有读者在问什么时候更新ISERDESE2这个原语。前文讲解过这些原语都在HDMI或者RGMII中使用过&#xff0c;但是ISERDESE2这个原语目前我的板子除了HDMI输入&#xff0c;其余并不…

Python概率编程库之pymc使用详解

概要 Python PyMC库是一个强大的概率编程库,用于贝叶斯统计建模和蒙特卡罗采样。它提供了丰富的功能和灵活的API,使得贝叶斯推断和概率建模变得简单而有效。 安装与配置 首先,看看如何安装Python PyMC库并进行基本配置: pip install pymc安装完成后,可以导入PyMC库并开…

Spring Security 实现后台切换用户

Spring Security version 后端代码&#xff1a; /*** author Jerry* date 2024-03-28 17:47* spring security 切换账号*/RestController RequiredArgsConstructor RequestMapping("api/admin") public class AccountSwitchController {private final UserDetailsSe…

深入浅出 -- 系统架构之垂直架构

当业务复杂度增加、访问量逐渐增大出现高并发时&#xff0c;单体架构无法满足需求&#xff0c;可以根据业务功能对系统进行拆分&#xff0c;以提高访问效率。 垂直架构介绍 1.垂直架构一般是因为单体架构太过于庞大而进行的拆分&#xff0c;拆分后各个系统应满足独立运行互相不…

5.1 输出hw,求数组最大、小值,字符串转大、小写

5.1 输出hw&#xff0c;求数组最大、小值&#xff0c;字符串转大、小写】 1. 注释 1.1 单行注释 ;注释内容 1.2 多行注释 comment* 注释内容 *comment2. 输出“hello&#xff0c;world” 头文件&#xff0c;命名数组定义字符串&#xff0c;结束代码&#xff0c;直接在c:下…

注解(Annotation)

文章目录 1 注解概述1.1 什么是注解1.2 注解与注释1.3 注解的重要性 2 常见的Annotation作用3 三个最基本的注解3.1 Override3.2 Deprecated3.3 SuppressWarnings 4 元注解5 自定义注解的使用5.1 声明自定义注解5.2 使用自定义注解5.3 读取和处理自定义注解 6 JUnit单元测试6.1…

通讯录项目实现

引言&#xff1a;通过顺序表的逻辑实现通讯录。这里就不讲关于顺序表的函数了。如果有不明白的可以看我写的顺序表的博客。 目录 顺序表与通讯录的比较 各源文件文件大榄 Contact.c中通讯录相关函数的定义 初始化和销毁通讯录 添加联系人&#xff1a; 删除联系人&#xf…

欧拉角及其旋转矩阵,旋转顺序与内旋/外旋及其代码

目录 欧拉角介绍 旋转矩阵公式推导 旋转顺序 内旋/外旋 欧拉角介绍 欧拉角&#xff1a; 横滚&#xff1a;roll&#xff08;绕X轴旋转&#xff09;&#xff1b; 俯仰&#xff1a;pitch&#xff08;绕Y轴旋转&#xff09;&#xff1b; 偏航&#xff08;也称航向角&#x…

腾讯云服务器4核8g配置好不好?用它干啥使?

腾讯云4核8G服务器多少钱&#xff1f;腾讯云4核8G轻量应用服务器12M带宽租用价格646元15个月&#xff0c;活动页面 txybk.com/go/txy 活动链接打开如下图所示&#xff1a; 腾讯云4核8G服务器优惠价格 这台4核8G服务器是轻量应用服务器&#xff0c;详细配置为&#xff1a;轻量4核…

CSS简介

1. CSS简介 CSS(Cascading Style Sheets)层叠样式表&#xff0c;又叫级联样式表&#xff0c;简称样式表&#xff0c;文件后缀名为.css&#xff0c;用于HTML文档中元素样式的定义。CSS语法&#xff1a; <!DOCTYPE html> <html lang"en"> <head><…

C语言—用EasyX实现反弹球消砖块游戏

代码效果如下 #undef UNICODE #undef _UNICODE #include<graphics.h> #include<conio.h> #include<time.h> #include<stdio.h>#define width 640 #define high 480 #define brick_num 10int ball_x, ball_y; int ball_vx, ball_vy; int radius; int ba…

删除中间节点(狸猫换太子法)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 每一个裂缝都是为透出光而努力&#…

香橙派OPI Airpro上的智能交通监管系统(保姆级代码)

首先&#xff0c;你需要安装必要的软件包和库&#xff0c;例如Python3和TensorFlow。然后&#xff0c;你可以编写脚本来处理数据采集、分析和报告生成等任务。以下是一个简单的示例&#xff1a; # 安装必要的软件包 sudo apt-get update sudo apt-get install -y python3 pyth…

腾讯云4核8G服务器性能怎么样?大明白来说说

腾讯云4核8G服务器价格&#xff1a;轻量4核8G12M优惠价格646元15个月、CVM S5服务器4核8G配置1437元买1年送3个月。腾讯云4核8G服务器支持多少人同时在线&#xff1f;支持30个并发数&#xff0c;可容纳日均1万IP人数访问。腾讯云百科txybk.com整理4核8G服务器支持多少人同时在线…

4月4号总结

java学习 一.接口 1.介绍 定义接口需要使用到关键字interface去定义接口。 格式如下&#xff1a; 类与接口的关系不是继承&#xff0c;而是实现&#xff0c;用关键字 implements &#xff0c;格式如下&#xff1a; 这个类去实现接口&#xff0c;其中的关系就相当于&#xf…

DFS(基础,回溯,剪枝,记忆化)搜索

DFS基础 DFS(深度优先搜索) 基于递归求解问题&#xff0c;而针对搜索的过程 对于问题的介入状态叫初始状态&#xff0c;要求的状态叫目标状态 这里的搜索就是对实时产生的状态进行分析检测&#xff0c;直到得到一个目标状态或符合要求的最佳状态为止。对于实时产生新的状态…

不到2000字,轻松带你搞懂STM32中GPIO的8种工作模式

大家好&#xff0c;我是知微&#xff01; 学习过单片机的小伙伴对GPIO肯定不陌生&#xff0c;GPIO &#xff08;general purpose input output&#xff09;是通用输入输出端口的简称&#xff0c;通俗来讲就是单片机上的引脚。 在STM32中&#xff0c;GPIO的工作模式被细分为8种…

gitcode 配置 SSH 公钥

在 gitcode 上配置SSH公钥后&#xff0c;可以通过SSH协议安全地访问远程仓库&#xff0c;无需每次都输入用户名和密码。以下是配置SSH公钥的步骤&#xff1a; 5分钟解决方案 用 OpenSSH公钥生成器 生成 公钥和私钥&#xff0c;私钥文件&#xff08;id_rsa&#xff09;下载&am…

算法设计与分析实验报告python实现(排序算法、三壶谜题、交替放置的碟子、带锁的门)

一、 实验目的 1&#xff0e;加深学生对算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、排序算法…