基于TDSQL-C对OOM问题进行优化
OOM是实例使用内存超过实例规格内存上限导致进程被kill,实例存在秒级的不可用。MySQL的内存管理比较复杂,内存监控需要开启performance schema查询(默认关闭),会带来额外的内存消耗和性能损失,在不开启performance schema情况下排查内存使用情况又比较困难。本文将基于TDSQL-C(基于MySQL5.7)总结一下在线上经常出现的一些OOM的场景、排查手段及相应的优化方案。
一、MySQL线上常见OOM问题
1.1 表数量较多导致innodb数据字典内存占用多
查询命令:show engine innodb status; 如下,dictionary memory allocated 显示数据字典内存已经占用约8G了,这部分内存不包含在 Buffer Pool 总内存大小中。
数据字典内存占用和innodb表的数量,表定义,table_open_cache,并发连接数等因素有关。
可以看到数据字典表有20w+,索引有70w+,对于这种场景要解决OOM风险,在不损失性能的前提下可以考虑升级内存规格。若能接受性能损失,可以降低innodb_buffer_pool_size或者table_open_cache来缓解内存开销。
1.2 大query带来内存上涨
若观察到实例内存抖动与业务流量增长一致,基本确定实例内存增长是用户连接内存开销导致。
- 通过performance schema来查看具体是哪一块内存占用过多:
# 1. 使用下述语句查询各个模块的内存占用(查看当前哪个模块内存占用多)SELECT SUBSTRING_INDEX(event_name,'/',2) AS code_area, sys.format_bytes(SUM(current_alloc)) AS current_alloc FROM sys.x$memory_global_by_current_bytes GROUP BY SUBSTRING_INDEX(event_name,'/',2) ORDER BY SUM(current_alloc) DESC; select *from sys.x$memory_global_by_current_byteswhere event_name like "memory/sql/%" order by current_alloc desc; # 2. 查看具体哪个连接占用内存多select thread_id, event_name, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_thread_by_event_nameorder by SUM_NUMBER_OF_BYTES_ALLOC desc limit 20; # 3. 查看占用内存最多的连接的详细信息select * from performance_schema.threads where THREAD_ID = xxx;
复制
- 通过show detail processlist(TDSQL-C 自研功能)对单个连接占用内存情况进行查询:
Server_memory_used: 该连接server层内存大小
Innodb_memory_used: 该连接innodb层内存大小
PFS_MEMORY_USED: 该连接performance schema内存大小
OS_MEMORY_USED: 从jemalloc层面上统计该连接内存大小
QUERY_MEMORY_USED: 从jemalloc层面上统计当前query的内存大小
单个连接占用内存过多,可以采用开启线程池限制并发连接数,或者升级内存规格。对于insert多value占用过多内存可以在业务侧进行sql拆分。
1.3 业务sql使用了prepare statement缓存
prepare statement cache用来缓存语句解析后的执行计划,缓存的语句越多,每个session所占用的内存也就越多。以sysbench为例,sysbench 1.1 默认打开了ps,导致prepare_statement缓存占用内存过大触发OOM。
升级内存规格可以缓解OOM,若能接受少量性能损失可以不使用ps缓存(例如sysbench--db-ps-mode=disable关闭ps),或者限制max_prepared_stmt_count大小。
1.4 业务连接数过多
小内存规格的实例出现过万的连接数,连接占用过多内存导致频繁OOM,可以通过开启线程池进行限制。
1.5 net buffer过大导致实例频繁OOM
如下有个实例的内存增长随负载的变化呈螺旋上升趋势:
开启performance schema后观察到是net::buffer的内存在持续上涨。
通过以下SQL查询具体哪些连接占用了net::buffer的内存:
select THREAD_ID,EVENT_NAME,COUNT_ALLOC,COUNT_FREE,CURRENT_NUMBER_OF_BYTES_USED,SUM_NUMBER_OF_BYTES_ALLOC,SUM_NUMBER_OF_BYTES_FREE from performance_schema.memory_summary_by_thread_by_event_name where EVENT_NAME like "memory/sql/NET::buff" order by CURRENT_NUMBER_OF_BYTES_USED desc;
复制
大量连接使用了16MB大小的net buffer内存,这里的具体原因是用户的sql比较大(大于MAX_PACKET_LENGTH,16MB),对于长连接来说执行完query这16MB缓存不会立即释放,用作下一次query的connection buffer,用户使用了大量的长连接导致这部分内存增长很快。
升级实例内存规格、业务侧减小每个sql的大小或者降低连接数可以解决。
1.6 内核bug导致内存泄露引起OOM
使用valgrind查看是否有内存泄漏:
- 下载valgrind
- 安装valgrind:1 ./configure 2 make 3 make install 4 valgrind -h
- 使用valgrind拉起mysqld
/valgrind --tool=memcheck --leak-check=full --log-file=valgrind_log --show-reachable=yes --trace-children=yes /data1/mysql_root/base_phony/20152/bin/mysqld --defaults-file=/data1/mysql_root/data/20152/my.cnf --basedir=/data1/mysql_root/base_phony/20152 --datadir=/data1/mysql_root/data/20152 --plugin-dir=/data1/mysql_root/base_phony/20152/lib/plugin --user=mysql20152 --core-file --disable-partition-engine-check
复制
4. 给实例加负载
5. shutdown实例,内存检查结果输出到valgrind_log中
6. valgrind_log最后会打印内存泄漏的总体情况,再去找各堆栈的情况
- "definitely lost":确认丢失。程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。
- "indirectly lost":间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与"definitely lost"一起出现,只要修复"definitely lost"即可。
- "possibly lost":可能丢失。大多数情况下应视为与"definitely lost"一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址),然后通过运算得到这块内存起始地址,再释放它。
二:TDSQL-C对OOM进行优化
2.1 TDSQL-C Server端参数优化
我们在不影响数据库性能的前提下修改实例默认配置来降低内存占用(括号内为优化后的默认值),主要包括以下参数的调整:
- innodb_log_buffer_size: 用来设置缓存还未提交的事务的缓冲区的大小
- innodb_ncdb_log_buffer_size:该参数对主库来说相当于innodb_log_file_size,对于备机来说相当于日志接受缓冲buffer
- key_buffer_size:key_buffer主要用于缓存MyISAM index block,TDSQL-C不支持MyISAM存储引擎
- innodb_ncdb_wait_queue_size:开启异步组提交后,innodb_ncdb_wait_queue_size表明最少可以同时容纳的事务异步提交数量,超过后需要同步等待
- innodb_ncdb_log_flush_events:唤醒等待log flush的event的个数
实验验证性能是否下降以及内存占用是否减少:
实例规格:2c4g 一主一从
测试场景:分别用1G和100G的数据量对应cpu bound和io bound场景进行sysbench读写性能测试
测试结论:在性能无显著变化的情况下,2c4g规格的实例实际内存占用减少了约200MB。
压测后观察实例的实际内存占用情况:
注意:
目前腾讯云原生数据库TDSQL-C有新春特惠活动,新人1.88元起
2.2 支持information_schema.detail_processlist快捷查询各连接数内存使用
进一步支持将show detail processlist的结果存储到information_schema.detail_processlist,便于以下查询:
- 按内存使用量排序查询出使用量Top n的链接;
- 计算所有连接内存使用量的总大小;
- 其他查询类似聚合或者top类的字段;
2.3 支持innodb buffer pool冷热page数量查询,为用户推荐合理的innodb_buffer_pool
统计在一段时间内没被访问的page的数量,反映出来用户真正需要多大的buffer pool,便于自动缩容到用户需要用的 bp 上。
内核新增参数:innodb_hot_page_time,单位秒,表示一定时间内访问过的page都是热page。
新增命令:show coldpage status,表明在buffer pool中,在innodb_hot_page_time时间内没有被访问过的page数量。
用户可以根据业务情况设置innodb_hot_page_time计算出准确的热数据量,根据热数据设置合理的buffer pool size。
2.4 限制innodb_buffer_pool的最大使用率,降低OOM的风险
实例启动后,innodb buffer pool随着使用率的增长,内存分配也逐渐增加,假如innodb buffer pool使用率未达到100%,但是实例存在OOM的风险,通过设置
innodb_max_lru_pages_pct限制innodb buffer pool的实际使用率,避免innodb buffer pool内存进一步增加导致OOM。
2.5 resize innodb buffer pool 性能优化,减小动态设置innodb buffer pool对业务的影响
对于有OOM风险的实例可以通过动态调整innodb buffer pool大小进行规避。但是对大实例进行调整innodb buffer pool往往会造成性能抖动。
如下图所示分别是动态增大和减小innodb buffer pool的过程。增大buffer pool size的过程比较简单,对并发负载没有太大影响。减小buffer pool size的过程需要将回收区的page转移到非回收区,这个过程需要长时间持有buffer pool mutex,阻塞其他线程无法访问buffer pool。
TDSQL-C对resize buffer pool回收page过程进行了性能优化,优化后仅需对回收区的page持有buffer pool mutex。
以下是BP在33g和22g之间每隔60s resize 一次,同时利用sysbench进行读写压测,持续观察QPS变化情况。
根据结果可以看到优化后的性能抖动减小,性能下降维持时间缩短。大大减小了动态设置innodb buffer pool对业务的影响。
基于TDSQL-C对OOM问题进行优化的更多相关文章
- 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化
高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...
- Tair LDB基于Prefixkey中期范围内查找性能优化项目总结
"Tair LDB基于Prefixkey该范围内查找性能优化"该项目是仅一个月.这个月主要是熟悉项目..以下从几个方面总结下个人在该项目上所做的工作及自己的个人所得所感. 项目工作 ...
- Android避免OOM(内存优化)
Android内存优化是性能优化很重要的一部分,而如何避免OOM又是内存优化的核心. Android内存管理机制 android官网有一篇文章 Android是如何管理应用的进程与内存分配 Andro ...
- 基于SSD固态硬盘的数据库性能优化
基于SSD固态硬盘的数据库性能优化 2010-11-08 00:0051cto佚名 关键字:固态硬盘 数据库管理 SSD 企业软件热点文章 Java内存结构与模型结构分析 Oracle触发器的语法 ...
- 记一次线上 OOM 和性能优化
大家好,我是鸭血粉丝(大家会亲切的喊我 「阿粉」),是一位喜欢吃鸭血粉丝的程序员,回想起之前线上出现 OOM 的场景,毕竟当时是第一次遇到这么 紧脏 的大事,要好好记录下来. 1 事情回顾 在某次周五 ...
- 字节跳动数据平台技术揭秘:基于 ClickHouse 的复杂查询实现与优化
更多技术交流.求职机会.试用福利,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 ClickHouse 作为目前业内主流的列式存储数据库(DBMS)之一,拥有着同类型 DBMS 难以企及 ...
- Tair LDB基于Prefixkey找到如何提取一系列性能优化项目key的prefix_size
眼下项目已快截止,编码任务也基本完毕.如今主要是性能測试. 项目是依照"Tair LDB基于Prefixkey的范围查找性能优化项目提议方案"的步骤一步步完毕的,首先先介绍第一个关 ...
- SSE图像算法优化系列二十一:基于DCT变换图像去噪算法的进一步优化(100W像素30ms)。
在优化IPOL网站中基于DCT(离散余弦变换)的图像去噪算法(附源代码) 一文中,我们曾经优化过基于DCT变换的图像去噪算法,在那文所提供的Demo中,处理一副1000*1000左右的灰度噪音图像耗时 ...
- 基于Linux服务器的性能分析与优化
作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行,但硬件问题.软件问题.网络环境等的复杂性和多变性,导致了对系统的优化变得异常复杂,如何定位性能问题出在哪个方面 ...
- 基于vue-cli项目打包慢的定位优化过程
入职一周后,上一个前端就离职了(超级坑爹的),留下了一个比较棘手的问题,就是基于vue-cli的项目打包超级慢,我接手项目的时候,打包需要45min(上个离职者也不知道原因),经过3个月之后,随着项目 ...
随机推荐
- libcamera 简介
libcamera 简介 libcamera 是一个开源的多媒体库,用于在 Linux 操作系统上支持多种摄像头硬件的访问,libcamera 是一个用户空间库,可用于开发基于摄像头的应用程序,如相机 ...
- JavaWeb项目编译前后的目录结构
JavaWeb项目编译前后的目录结构 编译前 页面和视图都放在webapp目录下 编译后 webapps WEB-INF
- [IOI2016] shortcut
有显然的 \(O(n^3)\) 做法,可以获得 \(38pts\).(退火在洛谷上能跑 \(75pts\)) 答案具有单调性,考虑二分一个 \(M\) 并判断.列出 \(i\) 到 \(j\) 的距离 ...
- 发布了一个jar包到中央仓库,我的心好累…
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra. 前几天我在网上冲浪的时候,看见有一个老铁在git上给我提了一个issue: 万万没想到,有一天我写的烂代码居然也 ...
- BBS升级版
BBS项目 项目的前期准备 1.django2.2 创建一个django目录 (需要配置环境变量和数据库) 'DIRS': [os.path.join(BASE_DIR, 'templates'), ...
- 期望与概率 dp
期望与概率 dp \(\text{By DaiRuiChen007}\) I. [洛谷4316] - 绿豆蛙的归宿 \(\text{Link}\) 思路分析 DAG 上做期望 dp,可以爆搜,也可以拓 ...
- 梯度下降算法 Gradient Descent
梯度下降算法 Gradient Descent 梯度下降算法是一种被广泛使用的优化算法.在读论文的时候碰到了一种参数优化问题: 在函数\(F\)中有若干参数是不确定的,已知\(n\)组训练数据,期望找 ...
- (11)go-micro微服务雪花算法
目录 一 雪花算法介绍 二 雪花算法优缺点 三 雪花算法实现 四 最后 一 雪花算法介绍 雪花算法是推特开源的分布式ID生成算法,用于在不同的机器上生成唯一的ID的算法. 该算法生成一个64bit的数 ...
- 顶层QWidget弹窗设置背景为透明,透明部分为黑色。
setAttribute(Qt::WA_TranslucentBackground); 设置此属性,解决.
- C#如何提高代码质量(二)
多线程,异步,任务和并行 1.异步和多线程应用场景区分 多线程 计算密集型工作 异步 IO密集型工作 2.线城同步中使用信号量 EventWaitHandle AutoResetEvent Manua ...