tidb server的oom问题优化探索
作者:张
原文来源: https://tidb.net/blog/de9bf174
【是否原创】是 【首发渠道】TiDB 社区
概述
最近在做个“枯树逢春”项目,迁移saiku到tidb上。在这个过程中发现并优化了tidb server的oom问题。本文记录了整个oom问题的排查和解决过程。oom问题的解决在社区有一些实践论述了,本文中尝试利用cgroup控制资源和STRAIGHT_JOIN注解优化join顺序实践比较少,撰文共享出来,希望能帮助遇到类似问题的同学选择合适的解决方案。因行业特殊,表的实际表名做了隐藏和转化(转化成A,B,C),带来的阅读体验下降,敬请见谅。
问题发现
saiku是个早已经没有维护的项目,由于用户习惯的原因(主要是用户肯付费),现在需要寻找一个数据库能够支撑saiku大数据量的查询,由于成本原因,最好还是开源(免费)的。
参考: https://github.com/OSBI/saiku
按照单表1.8亿的场景,断断续续测试过很多数据库:
- Mysql,单表过大,查询时间长,超过用户可忍受范围
- Mycat+Mysql,saiku的开发人员搞不定分表策略,我也不想搞
- GreenPlum,saiku存在sql查分,拆分后的sql主要用来进行维度校验,整个查询过程对GP来说不友好,查询也很慢
- ClickHouse,驱动问题,没有对接成功
- TiDB,勉强可以,但是三表关联有oom风险
本文描述的就是迁移saiku到TiDB上时,遇到的oom问题,以及解决过程。 问题描述参考: https://asktug.com/t/topic/574076 简单描述就是,A,B,C三表关联,A表约2亿数据,按日分区,700+分区,应用触发形如下列查询时:
select`B`.`code` as `c0`,`C`.`br_name` as `c1`,sum(`A`.`ss_num`) as `m0`,sum(`A`.`a_ss_num`) as `m1`,sum(`A`.`cb_num`) as `m2`
from`test`.`A2` as `A`,`test`.`B` as `B`,`test`.`C` as `C`
where`B`.`code` = '1010'
and`A`.`s_id` = `B`.`s_id`
and`A`.`b_code` = `C`.`b_code`
group by`B`.`code`,`C`.`br_name`;
此时客户端返回:
The last packet successfully received from the server was 86,645 milliseconds ago. The last packet sent successfully to the server was 86,645 milliseconds ago.
排查过程
本次迁移中,TiDB部署架构如下: nginx作为tidb的代理,应用连接nginx,代理到tidb上,tidb server可用资源是16C32G。 上述过程失败后查看了几个监控页面: dashboard->集群信息 发现TiDB在查询时全都重启过一遍。 grafana->Overview->TiDB->Memory Usage
三台tidb server都是打满机器内存后,断崖式下降,初步怀疑TiDB重启了。 查看三台机器的/var/log/messages,在对应的时间出现明显的oom-killer,主要信息如下:
Mar 14 16:55:03 localhost kernel: tidb-server invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
Mar 14 16:55:03 localhost kernel: tidb-server cpuset=/ mems_allowed=0
Mar 14 16:55:03 localhost kernel: CPU: 14 PID: 21966 Comm: tidb-server Kdump: loaded Not tainted 3.10.0-1160.el7.x86_64 #1
Mar 14 16:55:03 localhost kernel: Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
......
Mar 14 16:55:03 localhost kernel: Out of memory: Kill process 21945 (tidb-server) score 956 or sacrifice child
Mar 14 16:55:03 localhost kernel: Killed process 21945 (tidb-server), UID 1000, total-vm:33027492kB, anon-rss:31303276kB, file-rss:0kB, shmem-rss:0kB
Mar 14 16:55:07 localhost systemd: tidb-4000.service: main process exited, code=killed, status=9/KILL
Mar 14 16:55:07 localhost systemd: Unit tidb-4000.service entered failed state.
Mar 14 16:55:07 localhost systemd: tidb-4000.service failed.
Mar 14 16:55:22 localhost systemd: tidb-4000.service holdoff time over, scheduling restart.
Mar 14 16:55:22 localhost systemd: Stopped tidb service.
Mar 14 16:55:22 localhost systemd: Started tidb service.
Mar 14 16:55:26 localhost run_tidb.sh: [2022/03/14 16:55:26.327 +08:00] [INFO] [cpuprofile.go:111] ["parallel cpu profiler started"]
Mar 14 17:01:03 localhost systemd: Started Session 1108 of user root.
Mar 14 17:18:44 localhost systemd-logind: New session 1109 of user root.
Mar 14 17:18:44 localhost systemd: Started Session 1109 of user root.
以上日志说明,tidb被系统的oom-killer杀掉了,杀掉的原因是系统内存没有剩余了。 初步判断,TiDB发生oom问题了,继续排查发生的原因。 查看sql的执行计划: A的扫描结果首先跟C做HashJoin,C做Build,A自拍Probe,然后A和C的结果与B做HashJoin,A和C的结果做build,B做Probe,怀疑,这个步骤出现问题,A和C的结果过大。 怀疑执行计划有问题,查看健康度: SHOW STATS_HEALTHY where Table_NAME = 'A'; 看到所有分区健康度都是100,但是注意那个178是个坑,后文详细分析。 由于这个问题,可以反复重现,多次执行相关SQL,并多次执行手动分析: 直到tidb不能完成heap的分析为止,取最后一次成功的heap分析:
github.com/pingcap/tidb/util/chunk.NewColumn (/home/jenkins/agent/workspace/build-common/go/src/github.com/pingcap/tidb/util/chunk/column.go:0)> github.com/pingcap/tidb/util/chunk.New (/home/jenkins/agent/workspace/build-common/go/src/github.com/pingcap/tidb/util/chunk/chunk.go:0)> github.com/pingcap/tidb/executor.(*HashJoinExec).fetchBuildSideRows (/home/jenkins/agent/workspace/build-common/go/src/github.com/pingcap/tidb/executor/join.go:0)> github.com/pingcap/tidb/executor.(*HashJoinExec).fetchAndBuildHashTable.func2 (/home/jenkins/agent/workspace/build-common/go/src/github.com/pingcap/tidb/executor/join.go:0)> github.com/pingcap/tidb/util.WithRecovery (/home/jenkins/agent/workspace/build-common/go/src/github.com/pingcap/tidb/util/misc.go:0)
fetchAndBuildHashTable这个过程占用了绝大多数内存,跟上面的执行计划分析结果吻合,判断是第二步join中build端的表占用内存过大。
解决方案
saiku的特点是根据模型定义自动生成查询sql,所以saiku端完全避免这种sql产生不太现实,解决的思路还是从tidb端做一些优化,优化分为三个方向:
- 优化,尝试调整join时build和probe两个端所对应数据集,节省内存使用,例如:调整join顺序
- 转化,限制内存使用,或者转化引擎,让sql能够出来结果。例如:尝试调整内存参数、尝试使用TiFlash、尝试非分区表
- 保护,限制资源占用,必要时牺牲掉其中一个tidb server,但不要影响混部的其他组件
解决方案的描述按照解决问题时尝试的顺序编写,并不按照以上分类顺序。
尝试调整内存参数
首先尝试调整了内存的相关参数:
server_configs:tidb:enable-batch-dml: truemem-quota-query: 4294967296performance.server-memory-quota: 30064771072performance.txn-total-size-limit: 1073741824s
调整完成之后,进行回归测试,并没有效果,内存的波动仍然出现三个尖峰,并发现了oom-killer。
尝试使用tiflash
考虑到tiflash对ap友好,并且mpp架构正好可以应对这种单节点内存不足的场景,于是部署了tiflash,并增加tiflash的副本:
ALTER TABLE `test`.`A` SET TIFLASH REPLICA 1;
查看同步状态:
SELECT * FROM information_schema.tiflash_replica WHERE TABLE_SCHEMA = 'test' and TABLE_NAME = 'A';
完成同步后进行回归测试,内存的波动仍然出现三个尖峰,并发现了oom-killer。
从执行计划上看,虽然取数据用了tiflash,但是并没有使用mpp模式,即使设置强制使用:
set @@session.tidb_allow_mpp=1;
set @@session.tidb_enforce_mpp=1;
也没有使用,查找官方文档找到原因:
尝试非分区表
从前一个测试想到,如果非分区表,能否执行完成。 测试非分区表,因在上一步测试tiflash时,也同时为非分区表增加了tiflash副本,sql中增加注解:
select/*+ read_from_storage(tikv[test.A]) */`B`.`code` as `c0`,`C`.`br_name` as `c1`,sum(`A`.`ss_num`) as `m0`,sum(`A`.`a_ss_num`) as `m1`,sum(`A`.`cb_num`) as `m2`
from`test`.`A1` as `A`,`test`.`B` as `B`,`test`.`C` as `C`
where`B`.`code` = '1010'
and`A`.`s_id` = `B`.`s_id`
and`A`.`b_code` = `C`.`b_code`
group by`B`.`code`,`C`.`br_name`;
注意的是,注解需要使用数据库名+表名昵称,例如,A1或者test.A1,在我的测试中都不生效,A在当前session指定的数据库为test的情况下才生效,为了避免不必要的麻烦,采用数据库名+表名昵称,例如test.A 执行计划如下:
测试非分区表,使用tiflash,执行计划如下:
此两种方案都能正常运行出结果,跟saiku的研发沟通后发现,非分区表虽然解决三表关联的问题,但普通的按日期的两表关联查询反而变慢,影响了大部分模型,非分区表的方案也不能采用。
尝试利用cgroup限制资源使用
在其他项目应用Trino时,出现过Trino混部影响其他组件的问题,当时是采用cgroup相关策略解决的,尝试在tidb server上应用。 其中的关键设置:
- memory.soft_limit_in_bytes:内存软限制,超过此设置会优先回收超过限额的进程占用的内存,使之向限定值靠拢
- memory.limit_in_bytes:内存硬限制,默认超过此设置会触发oom-killer
- memory.oom_control:超过内存硬限制时,系统策略,值为0,则触发oom-killer,值为1,则挂起当前进程,等待有足够的内存后,继续运行。
实测步骤: 准备工作:
yum install -y libcgroup-tools.x86_64 libcgroup
cgcreate -g memory:/tidb
方案1:限制内存使用
cgset -r memory.soft_limit_in_bytes=30064771072 /tidb
cgset -r memory.limit_in_bytes=32212254720 /tidb
cgclassify -g memory:/tidb `ps -ef | grep tidb-server | grep -v grep | awk '{printf $2FS}'`
此方案中memory.soft_limit_in_bytes限制为28G,memory.limit_in_bytes限制为30G, 实测28G没有效果,内存很快到达30G限制,触发oom-killer,messages显示类似以前的oom日志。
方案2:关闭oom-killer行为
cgset -r memory.limit_in_bytes=32212254720 /tidb
cgset -r memory.oom_control=1 /tidb
cgclassify -g memory:/tidb `ps -ef | grep tidb-server | grep -v grep | awk '{printf $2FS}'`
此方案中 memory.limit_in_bytes限制为30G,内存达到30G之后,tidb server夯住,没有反应,强行重启之后才能继续使用,如图:
由于我测试过程中,挂的是第一个tidb server,所以dashboard无反应,查看tidb server进程还存活,处于不可中断的休眠状态。
调整join顺序
上述方案都不能达到目的之后,想要从控制执行计划方向,寻找一些方案。经查找,STRAIGHT_JOIN可以达到优化join顺序的目的:
STRAIGHT_JOIN 会强制优化器按照 FROM 子句中所使用的表的顺序做联合查询。当优化器选择的 Join 顺序并不优秀时,你可以使用这个语法来加速查询的执行
参考: https://docs.pingcap.com/zh/tidb/stable/sql-statement-select#%E8%AF%AD%E6%B3%95%E5%85%83%E7%B4%A0%E8%AF%B4%E6%98%8E saiku在组织sql的时候,也通常会把大表放到第一位,其他维度表依次关联,查看执行计划: 按照优化后的顺序,A先和B进行join,结果做为probe端和C进行join,能够完成查询,耗时约2m,此方案可以作为一个备选方案。
健康度的误读
前面这张图,查看健康度的时候,显示的条数只有178,分析时忽略了这个信息,在整个优化过程复盘过程中,发现了这个问题,猜测是这个表的analyze其实并没有完整执行过一次,导致表的统计信息中只收集了178个分区,这意味着执行计划很可能是不准的,花了一整晚的时间完整的执行了一次analyze:
ANALYZE TABLE test.A;
查看健康度: 分区数达到了732。 再次查看执行计划: 符合预期,实际执行大约在2m8s,这个时间,基本上能够给用户方解释了。
总结
兜兜转转,此次的问题,仍然是个统计信息不准的问题,因为不熟悉分区表的统计信息记录方式,导致了开始的误判。因为正式环境需要混合部署:
经过此次测试,正式环境调整策略如下:
- 修改nginx配置
server {listen 4000;proxy_pass tidb;proxy_next_upstream off;
}
关闭nginx失败转移策略,前面表述中,之所以有三个尖峰,是因为nginx的请求失败转移策略,这个慢sql会依次访问所有tidb server,导致tidb server依次重启,整个tidb上的请求会全部失败一次,影响太大。
- 增加cgroup策略
cgset -r memory.limit_in_bytes=34359738368 /tidb
cgclassify -g memory:/tidb `ps -ef | grep tidb-server | grep -v grep | awk '{printf $2FS}'`
防止有统计信息不准的表,导致oom问题,影响到混合部署的其他组件,最差情况就是单个tidb server重启。
- 设置定时analyze计划
ANALYZE TABLE test.A PARTITION prt_20210101;
lighting在导数据之后,会有analyze的语句执行,但表比较大,重试三次都是失败。计划在每次导数据之后,定时设置一个analyze,对有变动的分区执行analyze。
<!-- 下面这行代码会帮助你自动生成神奇的目录,需要的话请不要删除哦~ -->
<div data-theme-toc="true"> </div>
tidb server的oom问题优化探索相关推荐
- 美图HTTPS优化探索与实践
HTTPS 是互联网安全的基础之一,然而引入 HTTPS 却会带来性能上的损耗.本文作者深入解析了 HTTPS 协议优化的各个方面,对实战很有帮助. 2012 年斯诺登(Edward Snowden) ...
- TiDB Server
目录 TiDB Server架构 Online DDL GC 缓存管理 热点小表缓存 例题 TiDB Server架构 Protocol Layer:负责处理客户端的连接 Parse,Compile: ...
- TiDB数据库架构——TiDB Server
TiDB Server架构 TiDB Server 是SQL层,无状态,启动多个TiDBServer,均匀分摊,解析SQL,获取真实数据. Protocol Layer.:负责客户端的连接. Pars ...
- TiDB体系结构之TiDB Server
TiDB体系结构之TiDB Server TiDB Server TiDB Server主要组成模块 SQL语句的解析和编译 行数据与KV的转化 SQL读写相关模块 在线DDL相关模块 TiDB的垃圾 ...
- 数据库必知必会:TiDB(2)TiDB Server
数据库必知必会:TiDB(2)TiDB Server TiDB Server架构 SQL语句的解析和编译 Parse Compile 关系型数据与K-V型数据的转换 SQL读写相关模块 在线DDL相关 ...
- 美图 HTTPS 优化探索与实践
HTTPS 是互联网安全的基础之一,然而引入 HTTPS 却会带来性能上的损耗.本文作者深入解析了 HTTPS 协议优化的各个方面,对实战很有帮助. 2012 年斯诺登(Edward Snowden) ...
- Flutter Web 在《一起漫部》的性能优化探索与实践
一起漫部 是基于区块链技术创造的新型数字生活. 目录 前言 开发环境 渲染模式 首屏白屏 优化方案 启屏页优化 包体积优化 去除无用的icon 裁剪字体文件 deferred延迟加载 启用gzip压缩 ...
- SQL Server 数据库的整理优化的基本过程(二)
SQL Server 数据库的整理优化的基本过程(二) 高建刚 第一节 基本维护 第二节 索引 索引相信大家都不陌生,而且在因特网上,有了很多关于如何通过索引来优化数据库的文章,在这里,我主要是结合我 ...
- 一个SQL性能问题的优化探索(二)(r11笔记第38天)
继续前几天的一个案例一个SQL性能问题的优化探索(一)(r11笔记第33天) 如下的SQL语句存在索引字段CARD_NO,但是执行的时候却走了全表扫描,因为这是一个核心表,数据量很大,导致数据库负载很 ...
最新文章
- 数列分块入门2(区间小于c的个数)
- 信息系统项目管理师-组织级项目管理与大型项目管理知识点
- shopeeLazada越南站点“热销品类”推荐
- 上周五,小编参加了一场高大上的“9”会
- mysql优化了解_了解MySQL如何优化
- 嘴上说着喜爱Java 9 ,身体却诚实地拥抱了Java 8
- 网上偶看一文,有感。特贴在下面。
- iOS开发常用技能点(持续更新中。。。)
- 推荐使用maven生成mybatis代码
- Atitit 企业知识管理PKM与PIM
- 从哥德巴赫说开去(3)
- 2022-04-行为经济学-光华管理学院-孟涓涓
- 数据库表关系详解(一对多、一对一、多对多)
- html主菜单和子菜单,刻录dvd光盘设置dvd菜单 只要子菜单可以吗 不要主菜单的
- 泡妞高手的经典三十六计
- ionic5 ion-refresher下拉更新
- 《Python》re模块补充、异常处理
- 润乾报表学习一:制作最简单的报表
- warmup lr+CosineAnnealingLR策略
- To run in silent mode, OPatch requires a response file for Oracle Configuration Manager (OCM).
热门文章
- 好用的识别植物的软件app合集分享,快码住了
- python递归函数例子_Python递归函数经典案例-汉诺塔问题
- 快手-开眼快创 Flutter 实践
- 3D Point Cloud Descriptors in Hand-crafted and Deep Learning Age: State-of-the-Art
- android 自定义属性
- Unity插件——文字转朗读语音RtVioce插件功能/用法/下载
- LinkedIn高级分析师王益:大数据时代的理想主义和现实主义(图灵访谈)
- 【RDMA】19. RDMA之iWARP Soft-iWARP
- TF/06_Neural_Networks/01_Introduction02gate03activate fuctions
- wps图片与图片间距怎么调整_wps图片与图片间距怎么调整_微信图文排版,字间距,行间距,怎么调整合适?......