首页 > 数据库 >SQL千亿数据膨胀OOM优化经验

SQL千亿数据膨胀OOM优化经验

时间:2025-01-12 16:33:02浏览次数:3  
标签:memory group OOM SQL -- 千亿 数据量 executor

图片

性能监控Dashboard

一、 业务背景

作为一个日活过亿的APP,随着新特性的不断迭代,包越来越大,谁也无法预料哪个Dev会发布一个bug,导致手机掉电飞快或卡到怀疑人生。所以软件性能的监控是非常重要的一环。毕竟用户离开的时候会抱不留情。常见的监控指标,一般有CPU、温度等,手机硬件数据采集都是通过埋点上报,每5秒频率。同时性能团队也会做AB实验,来跟踪实验效果,再决定是否推全。

二、问题恶化

随着用户增加和性能策略迭代,任务运行时间由3小时上升为7小时,性能团队要T-2才能回收实验效果。

我们可以预估一下数据量: 每日用户手机端上报的数据量约200亿,但是这里要关联另一张表:用户实验关系表,关联下来日级增量数据就是2000亿。

三、定位分析

数据量大到无法呼吸,而且业务需求还有100个指标要计算,只能硬着头皮扫描一下核心脚本,这里只截取一小段,实际脚本大概2K行左右。

图片

Grouping sets:对分组集中指定的组表达式的每个子集执行group by。

group by A,B 

grouping sets(A,B)就等价于 

group by A union group by B

其中A和B也可以是一个集合,比如group by A,B,C grouping sets((A,B),(A,C))

1. 查看执行计划

这里用到了grouping sets,所以膨胀2倍数据也就是2000亿 x 2 = 4000亿。

图片

通过SparkUI数据也可以发现。

图片

目前来看膨胀2倍其实还好,大不了处理的慢一点,但报错却有点诡异。

图片

# -java.lang.OutOfMemoryError: Java heap space# -XX:OnOutOfMemoryError="kill %p"# -Executing /bin/sh -c "kill 4209"...

2. OOM暴力堆资源

确定是OOM带来的问题,为了先把任务跑成功,给下游有个交代。所以先给executor的内存放大,当然目前内存已经很大了,但还是暴力加资源。通常处理OOM的要关注几方面,我的经验整理在《常见资源分配策略》的文章里,大家可以看看。

Before

--driver-memory 12G --executor-memory 12G --executor-cores 2 --num-executors 100

After

--driver-memory 12G --executor-memory 18G --executor-cores 2 --num-executors 200

3. OOM参数配置

重新调起运行后,依旧OOM,再次调整memoryOverhead的参数。调大这个参数观察效果,一般我们会选择memoryOverhead的大小为spark.executor.memory的25%,如果OOM还存在,则要进一步检查代码的原因,毕竟代码不是我写的,有一些业务背景不熟悉,不敢随便修改代码。

spark.executor.memoryOverhead = 4G

继续看SparkUI的内容,输入和shuffle的数据膨胀了近40倍!!!!!居然不是2倍

图片

4. 业务代码理解

默默的回去看源代码

count ( distinct exp_id)

居然还有N个子查询带着count distinct,然后和上面的片段进行full join,把这个天杀的给拖出去砍了。熟悉count distinct操作的应该知道,它也是靠expand来实现的,也就是至少这个代码里还藏着10个count distinc,这意味着数据将膨胀10倍。。。。

图片

果不其然,真正的罪魁祸首在这里卡着。都还没有到最开始的千亿数据量的那张表,首先在这里就卡住了。

图片

这里刚好是stage 1.0的位置,回去看它的task metrics

图片

5. 降低Input Size

明明文件才89M左右,但数据量很大,已经76610100条数据,这里让我不由自主的想要缩小一下read的数据量,可以使用这2个参数。

spark.sql.files.maxPartitionBytes = 20971520spark.sql.files.openCostInBytes = 10485760

以为这个时候把read的数据量降下来,那问题应该就解决了,但没想到还是OOM了。百思不得其解。继续看SparkUI的统计指标。

图片

虽然task增加了,但是task的inputsize的中位数是52.2KB,想必75分位的15.1M而言,妥妥的有问题,我们称之为:大部分任务在空跑。

Google了一下,发现这个是一个已知的问题,说的是这2个参数只对csv或text文件生效,对已经压缩的parquet效果并没有什么作用。

6. 上游表重分区

我们把读取的底层表再重新repartition一下,生成更小的文件,这将导致小文件也会增加。虽然知道可行,而且改造成本有点儿高,暂时换一条路再试试。

7. 业务代码改写

我们目的是为了避免expand的代价,但业务要求又要使用count distinct。那就用我们最习惯的group by来粗糙演示。

图片

这里隐藏了额外的判断:当state=succ才计算,那改成max和sum,新增按照event_id进行打标和间接去重,最外层sum只会把tag=1的数据进行加总。

图片

改写完后,重新运行,expand的情况就避免了,数据也正常产出,至少给业务有了一个交代。

四、后续改造

  • 方案一:

    我们跟业务方沟通后,其实这个性能数据少一部分都没关系,毕竟最后看的是分位数分布,那其实随机采样也是不影响整体数据形状。那其实可以这样做:

图片

  • 方案二:

    这个SQL脚本太大大大大大大大大大,完全可以拆分多个任务进行处理,而且非常适合预聚合一轮之后,再进行汇总,但前任大侠为何没有做这些操作,估计有可能大概率他也是接的别人吧。

五、结语

整体优化也花了一天的时间,主要这个任务太大,改动一些参数要看效果,也得等到5小时以后,解决问题的过程和思路还是值得复制在其他地方,借此以飨读者。

如果它对您有一些价值,可以关注一下,原创不易,需要支持。

参考阅读 

[1] “Partition” in “Apache Spark”:

https://oindrila-chakraborty88.medium.com/introduction-to-partition-in-apache-spark-66e005c6e15d 

[2] Spark Memory Overhead

https://stackoverflow.com/questions/63561233/spark-memory-overhead

标签:memory,group,OOM,SQL,--,千亿,数据量,executor
From: https://blog.csdn.net/lssilu/article/details/145094390

相关文章

  • MySQL 16 章——变量、流程控制和游标
    一、变量在MySQL数据库的存储过程和存储函数中,可以使用变量来存储查询或计算的中间结果数据,或者输出最终的结果数据在MySQL数据库中,变量分为系统变量和用户自定义变量(1)系统变量1.1.1系统变量分类变量由系统定义,不是用户定义,属于服务器层面。启动MySQL服务,生成MySQL服务实......
  • 基于PHP的MYSQL注入(2)
    符号拼接由于网站开发者对数据类型或者对sql语句的写法(框架)导致1、数字型(无符号干扰)select*fromuserswhereid=$id;2、字符型(不光是单引号,也可能是双引号或者其他)select*fromuserswhereid='$id';3、搜索型(多符号干扰)select*fromuserswhereidlike'%$......
  • 【DMSQL系列】 达梦数据库写文件的方式探索
    前沿这篇文章整体算是......
  • ⭐MySQL的底层原理与架构
    前言了解MySQL的架构和原理对于很多的后续很多的操作会有很大的帮助与理解。并且很多知识都与底层架构相关联。了解MySQL架构通过上面的架构图可以得知,Server层中主要由连接器、查询缓存、解析器/分析器、优化器、执行器几部分组成的,下面将主要描述下这几部分。1、连......
  • 前端必知必会-Node.js连接MySQL
    文章目录Node.jsMySQLMySQL数据库安装MySQL驱动程序创建连接查询数据库总结Node.jsMySQLNode.js可用于数据库应用程序。最流行的数据库之一是MySQL。MySQL数据库为了能够试验代码示例,您应该在计算机上安装MySQL。您可以在https://www.mysql.com/down......
  • [免费]微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端)【论文+源码+SQL脚本
    大家好,我是java1234_小锋老师,看到一个不错的微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端),分享下哈。项目视频演示【免费】微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端)Java毕业设计_哔哩哔哩_bilibili项目介绍随着越来越多的用户借助于移动手机......
  • 如何修改网站SQL中的密码?
    修改网站数据库中的密码是一个常见的需求,尤其是在忘记管理员密码或需要增强安全性的情况下。以下是针对不同类型的网站(如WordPress、Joomla、Drupal、织梦等)修改数据库密码的具体步骤和注意事项。一、通用步骤1.登录数据库管理工具使用phpMyAdmin:通过控制面板(如cPanel、Plesk......
  • MySQL 死锁
    死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。1数据库层面解决死锁的两种方式1、解决死锁的问题最简单的方式是不要有等待,将任何的等待都转化为回滚,并且事务重新开始。 这种没有死锁问题的产生。在线上环境中,可能导致并发性能的下降,甚......
  • MySQL sleep 线程过多怎么解决
    1知道sleep线程过多原因首先要知道到底是什么原因导致的sleep线程过多的:程序逻辑问题,导致连接一直不释放;mysql参数的问题,是不是参数配置的不合理,一直不释放连接;mysql语句的问题,数据库查询不够优化,过度耗时。大并发情况问题,导致sleep情况过多;2临时解决s......
  • MySQL主从同步不一致解决办法
    一般主从同步错误首先要考虑是不是在从库中误操作导致的。结果发现,有人在从库中进行了一条针对有主键表的sql语句的插入,导致主库再插入相同sql的时候,主从状态出现异常。发生主键冲突的报错。解决方法:在确保主从数据一致性的前提下,可以在从库进行错误跳过。像从库如果不提供......