如何解决由触发器导致 MySQL 内存溢出?

由触发器导致得 OOM 案例分析过程和解决方式。

作者:龚唐杰,爱可生 DBA 团队成员,主要负责 MySQL 技术支持,擅长 MySQL、PG、国产数据库。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 1500 字,预计阅读需要 5 分钟。

问题现象

一台从库服务器的内存使用率持续上升,最终导致 MySQL 服务被 kill 了。

内存监控视图如下:

内存使用率 92.76%

从图中可以看出,在 00:00 左右触发了 kill,然后又被 mysqld_safe 进程拉起,然后内存又会持续上升。

排查过程

基本信息

  • 数据库版本:MySQL 5.7.32
  • 操作系统版本:Ubuntu 20.04
  • 主机配置:8C64GB
  • innodb_buffer_pool_size:8G

由于用户环境未打开内存相关的监控,所以在 my.cnf 配置文件中配置如下:

performance-schema-instrument = 'memory/% = COUNTED'

打开内存监控等待运行一段时间后,相关视图查询如下:

从上述截图可以看到,MySQL 的 buffer pool 大小分配正常,但是 memory/sql/sp_head::main_mem_root 占用了 8GB 内存。

查看 源代码 的介绍:

sp_head:sp_head represents one instance of a stored program.It might be of any type (stored procedure, function, trigger, event).

根据源码的描述可知,sp_head 表示一个存储程序的实例,该实例可能是存储过程、函数、触发器或者定时任务。

查询当前环境存储过程与触发器数量:

当前环境存在大量的触发器与存储过程。

查询 MySQL 相关 bug,这里面提到一句话:

Tried to tweak table_open_cache_instances to affect this?

查询此参数描述:

A value of 8 or 16 is recommended on systems that routinely use 16 or more cores. However, if you have many large triggers on your tables that cause a high memory load, the default setting for table_open_cache_instances might lead to excessive memory usage. In that situation, it can be helpful to set table_open_cache_instances to 1 in order to restrict memory usage.

根据官方的解释可以了解到,如果有许多大的触发器,参数 table_open_cache_instances 的默认至可能会造成内存使用过多。

比如 table_open_cache_instances 设置为 16,那么表缓存会划分为 16 个 table instance*。当并发访问大时,最多的情况下一个表的缓存信息会出现在每一个 *table instance 里面。

再由于每次将表信息放入表缓存时,所有关联的触发器都被放入 memory/sql/sp_head::main_mem_root 中,table_open_cache_instances 设置的越大其所占内存也就越大,以及存储过程也会消耗更多的内存,所以导致内存一直上升最终导致 OOM。

下面简单验证一下触发器对内存的影响。

table_open_cache_instances 为 8 时:
#清空缓存

mysql> flush tables;
Query OK, 0 rows affected (0.00 sec)

[root@test ~]# cat test.sh
for i in `seq 1 1 8`
do
mysql -uroot -p test -e "select * from test;"
done

[root@test ~]# sh test.sh

mysql> show variables like '%table_open_cache_instances%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| table_open_cache_instances | 8 |
+----------------------------+-------+
1 row in set (0.00 sec)

mysql> SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+---------------+
| current_alloc |
+---------------+
| 119.61 KiB |
+---------------+
1 row in set (0.00 sec)

在该表上创建一个触发器。

mysql> \d|
mysql> CREATE TRIGGER trigger_test BEFORE INSERT ON test FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET message_text='Very long string. MySQL stores table descriptors in a special memory buffer, calle
'> at holds how many table descriptors MySQL should store in the cache and table_open_cache_instances t
'> hat stores the number of the table cache instances. So with default values of table_open_cache=4000
'> and table_open_cache_instances=16, you will have 16 independent memory buffers that will store 250 t
'> able descriptors each. These table cache instances could be accessed concurrently, allowing DML to u
'> se cached table descriptors without locking each other. If you use only tables, the table cache doe
'> s not require a lot of memory, because descriptors are lightweight, and even if you significantly increased the value of table_open_cache, it would not be so high. For example, 4000 tables will take u
'> p to 4000 x 4K = 16MB in the cache, 100.000 tables will take up to 390MB that is also not quite a hu
'> ge number for this number of open tables. However, if your tables have triggers, it changes the gam
'> e.'; END|
Query OK, 0 rows affected (0.00 sec)

#清空缓存

mysql> flush tables;
Query OK, 0 rows affected (0.00 sec)

然后访问表,查看缓存。

[root@test ~]# cat test.sh
for i in `seq 1 1 8`
do
mysql -uroot -p test -e "select * from test;"
done

[root@test ~]# sh test.sh

mysql> SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+---------------+
| current_alloc |
+---------------+
| 438.98 KiB |
+---------------+
1 row in set (0.00 sec)

可以发现 memory/sql/sp_head::main_mem_root* 明显增长较大。如果有很多大的触发器,那么所占内存就不可忽视(现场环境触发器里面很多是调用了存储过程)。

table_open_cache_instances 为 1 时:
mysql> flush tables;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%table_open_cache_instances%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| table_open_cache_instances | 1 |
+----------------------------+-------+
1 row in set (0.00 sec)

SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+---------------+
| current_alloc |
+---------------+
| 119.61 KiB |
+---------------+
1 row in set (0.00 sec)

mysql> #访问表

mysql> system sh test.sh

mysql> SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+---------------+
| current_alloc |
+---------------+
| 159.53 KiB |
+---------------+
1 row in set (0.00 sec)

可以发现 memory/sql/sp_head::main_mem_root 所占内存增长较小。

由于大量触发器会导致表缓存和 memory/sql/sp_head::main_mem_root 占用更多的内存,根据实际环境,尝试把该从库的 table_open_cache_instances 修改为 1 后观察情况。

可以看到内存值趋于稳定,未再次出现内存使用率异常的问题。

总结

  1. MySQL 中不推荐使用大量的触发器以及复杂的存储过程。
  2. table_open_cache_instances 设置为 1 时,在高并发下会影响 SQL 的执行效率。本案例的从库并发量不高,其他场景请根据实际情况进行调整。
  3. 触发器越多会导致 memory/sql/sp_head::main_mem_root 占用的内存越大,存储过程所使用的内存也会越大。
  4. 本文只是给出了解决内存溢出的一个方向,具体的底层原理请自行探索。

先清空缓存再访问表,查看缓存

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse

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

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

相关文章

如何用 RAG 技术玩转文档问答?Milvus × 网易有道 QAnything 为你揭秘!

过去一年,RAG 在技术层面发展迅速,为向量数据库赛道添了一把火。RAG 和向量数据库的结合,能够有效解决幻觉、时效性差、专业领域知识不足等阻碍大模型应用的核心问题。 不久前,网易有道开源了自研的 RAG 引擎 QAnything。用户的任…

如何下载安装chromium浏览器

下载安装chromium浏览器去这个网站下载: CNPM Binaries Mirror 参考链接:手写 Puppeteer:自动下载 Chromium - 知乎

渲染农场:大规模渲染任务的高效处理方式

在当今的数字内容创作领域,渲染农场是处理大规模渲染任务的关键技术,它利用多台计算机的集群来分担复杂的渲染工作,大大提高了效率和速度。这篇文章将深入探讨渲染农场的工作原理、技术架构,以及如何根据需求选择合适的渲染农场。…

Vmware 点进centos不显示鼠标

今天安装了Vmward16 安装后在里面安装了centos7,但进入centos7 时没显示鼠标,但有点击效果。 设置了右上角的 编辑->首选项 -输入-》单击鼠标时抓取键盘和鼠标输入然后重启下vmware,但鼠标还是不显示 后面我的电脑重启了,然后…

【数学】【网格】【状态压缩】782 变为棋盘

作者推荐 视频算法专题 本文涉及知识点 数学 网格 状态压缩 LeetCode:782 变为棋盘 一个 n x n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。 返回 将这个矩阵变为 “棋盘” 所需的最小移动次数 。如果不存在可行的变换&am…

小区水电智能化系统

随着科技的进步,我们的生活变得越来越智能化,而小区水电智能化系统正是这一趋势的典范。这个系统不仅仅是一种便利,更是未来智慧生活的关键组成部分。让我们一起来了解一下它的奥秘吧! 让我们来看看小区水电智能化系统的核心:智能…

【Spring】idea连接mysql数据库

1 MySQL安装 下载地址:https://dev.mysql.com/downloads/installer/ 安装server only选项,之后的可以选择默认安装选项 2 MySQL登录并创建数据 -- 创建数据库 create databases spring_db; use spring_db; -- 创建表 create table users (id INT AUTO…

现货黄金交易网上有用的交易技巧

在不同的现货黄金交易网上,经常有投资者分享交易技巧。由于在网上发文没什么限制,所以这些交易技巧都是泥沙俱下,质量良莠不齐。不过也有一些是有用的,下面我们就来介绍一下现货黄金交易网上那些有用的交易技巧。 培养防守意识。什…

DataFunSummit 2023因果推断在线峰会:解码数据与因果,引领智能决策新篇章(附大会核心PPT下载)

在数据驱动的时代,因果推断作为数据科学领域的重要分支,正日益受到业界的广泛关注。DataFunSummit 2023年因果推断在线峰会,汇聚了国内外顶尖的因果推断领域专家、学者及业界精英,共同探讨因果推断的最新进展、应用与挑战。本文将…

滑动窗口的概念,糊涂窗口综合征,nagle算法

目录 1.流量控制 2.滑动窗口 3.思考问题 1.流量控制 一般来说,我们总是希望数据传输得更快一些,但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失.所谓流量控制(flow control)就是发送方的发送速率不要太快,要让接收方来得及接收. 2.滑动窗口 T…

因为manifest.json文件引起的 android-chrome-192x192.png 404 (Not Found)

H5项目打包之后,总是有这个报错,有时候还有别的icon也找不见 一通调查之后,发现是因为引入了一个vue插件 这个插件引入之后,webpack打包的时候就会自动在dist文件夹中产生一个manifest.json文件这个文件里面主要就是一些icon地址的…

el-select 选项文字超长解决方案

先看现象 省略号显示 <el-selectv-model"configs.domain.secondLevel"style"width: 100%"filterableallow-createdefault-first-optionplaceholder"请输入二级网段名称&#xff0c;例如&#xff1a;广州研发中心/研发网"focus"setOpti…

#QT(本地音乐播放器)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;之前做的音乐播放器只做了一个界面&#xff0c;是因为跟的课程发现到后面需要付费&#xff0c;并且WINGW6.2.0运行QMediaPlayer时无法运行&#xff0c;会崩溃&#xff0c;现在退一步用WINGW5.12.2做一个本地音乐播放器 3.记录&am…

漏洞挖掘 | 没有弱口令的挖掘思路

没有弱口令怎么挖&#xff1f;依稀记得有一个很老的思路叫做禁用js可以跳转后台&#xff0c;奈何学习两年半到现在从未发现一个这种漏洞。 不过&#xff0c;虽然不能直接搞到未授权后台登录&#xff0c;但是站有站的设计&#xff0c;小白有小白的打法&#xff01; 访问某URL&am…

web开发——前端html、css、JavaScript学习总结(持续更新中.......)

目录模版 1 html:结构标签/属性文本标记: mark文本设置:删除线del / 下划线ins/ 加粗b / 强调的文本em / 重要的文本 strong超链接: a联系信息: addressdiv 定义文档中的分区或节: div行元素:spanhtml结构: main / section / articlenav表格:table html中各种标签/属性的英文扩…

ubuntu下vscode+STM32CubeMX+openocd+stlinkv2搭建STM32开发调试下载环境

1、换源 清华源 # 默认注释了源码镜像以提高 apt update 速度&#xff0c;如有需要可自行取消注释 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restr…

Flink K8S Operator 离线安装

一 推送镜像 docker pull quay.io/jetstack/cert-manager-cainjector:v1.8.2 docker tag quay.io/jetstack/cert-manager-cainjector:v1.8.2 10.177.85.101:8000/flink/cert-manager-cainjector:v1.8.2 docker push 10.177.85.101:8000/flink/cert-manager-cainjector:v1.8.2d…

大预言模型——ChatGPT,Claude3、Sora、等技术

原文链接&#xff1a;大预言模型——ChatGPT,Claude3、Sora、等技术https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247596849&idx3&sn111d68286f9752008bca95a5ec575bb3&chksmfa823ad6cdf5b3c0c446eceb5cf29cccc3161d746bdd9f26cc060f78c359ec3e2a8f35…

【C语言刷题】——初识位操作符

【C语言刷题】——初识位操作符 位操作符介绍题一、 不创建临时变量&#xff08;第三个变量&#xff09;&#xff0c;实现两个数的交换&#xff08;1&#xff09;法一&#xff08;2&#xff09;法二 题二、 求一个数存储在内存中的二进制中“一”的个数&#xff08;1&#xff0…

浏览器缓存 四种缓存分类 两种缓存类型

浏览器缓存 本文主要包含以下内容&#xff1a; 什么是浏览器缓存按照缓存位置分类 Service WorkerMemory CacheDisk CachePush Cache 按照缓存类型分类 强制缓存协商缓存 缓存读取规则浏览器行为 什么是浏览器缓存 在正式开始讲解浏览器缓存之前&#xff0c;我们先来回顾一…