【SOP】最佳实践之 TiDB OOM 分析

网友投稿 739 2023-11-24

大家可能经历过这样一个场景,在某个正在熟睡的凌晨突然收到告警电话有 tidb-server 节点频繁重启,可能还伴随有内存告警,然后赶紧起来排查确认。上线一看发现不少节点出现了 OOM ,类似上图,在找到对应的 SQL 和业务一确认后,确定是凌晨偷偷新上的统计任务导致了这次的问题,赶紧让业务先停掉完,告知业务完成优化且经过 DBA 确认后再另外排期上线,之后骂骂咧咧的再次滚回被窝去。这个案例起码至少说明了几个问题:

开发能力和开发规范遵循问题

上线流程控制问题

数据库自身资源管控问题

在问题出现后数据库管理员总结排查方法,还可以针对性的做好开发手册指引和培训工作。

而我们在 TiDB 的使用过程中,尤其是访问大量数据的分析型业务场景,很难不会遇到 OOM 的问题。OOM 的问题一旦出现,集群必然会受到影响,所以,这就要求我们能够以尽快的速度完成排查和处理。本文这里总结一些日常管理 TiDB 集群的经验,方便后面遇到类似问题时可以作为一个排查思路和操作指引,协助快速处理 OOM 问题。

是不是OOM问题?

有收到内存告警、节点卡住或重启的情况,我们可以在脑海中有个初判会不会是 OOM 问题。TiDB 集群 OOM 通常出现在 tidb-server 节点上,也有少数情况出现在 tikv-server 节点。大致可以先通过下面的分析流程进行排查,确认是不是 OOM 的问题。

如上图所示,我们遇到问题后可以有下面的分析来确认是不是具体组件出现了 OOM 。

是不是 tidb server OOM 问题

业务侧、用户端:

部分访问有明显延迟 

部分业务有lost connection 的报错

grafana监控:

uptime出现掉线重启 

Overview->TiDB->Memory Usage 出现高峰急剧掉线重启

tidb server日志:

tidb.log 在问题时段出现Welcome 重启关键字 

tidb_stderr.log有oom或can not allocate memory关键字

系统日志

tidb server节点系统日志 dmesg -T| grep tidb-server 在问题时段附近有OOM Killer出现

(图片来源https://tidb.net/blog/de9bf174

是不是 tikv server OOM 问题

业务侧、用户端:

集群访问延迟有突增

业务QPS有明显抖动

grafana监控

tikv detail->cluster->uptime出现掉线重启

tikv detail->cluster->memory面板看到有tikv实例的内存剧烈上升后突然掉零再慢慢增加,可判断为tikv OOM重启了

tikv server日志

排查tikv.log日志,在问题时段附近有Welcome实例重启标记

系统日志

dmesg -T| grep tikv-server在问题时段有OOM-killer日志

OOM原因是什么

当遇到OOM的问题之后,排查触发原因时,大致可以分为两类原因:

数据库原因导致的 OOM

非数据库原因导致的OOM

数据库本身导致的 OOM 问题,通常是统计信息不准确导致执行计划问题、集群配置参数使用不当等引起情况。非数据库原因导致的 OOM 问题,通常可以归类为硬件资源不足、混合部署等原因,比如其他应用进程抢占了过多的内存资源导致 TiDB 被系统的 oom-killer 直接干掉。

OOM如何处理

针对不同的 OOM 触发根因,我们会有不同的处理策略。

如何处理tidb server的OOM问题

非数据库原因

机器内存不足

确认部署 tidb server 的机器操作系统内存是否太少,导致内存不足。开发及测试环境建议值是16 GB+,生产环境建议值是48 GB+。

https://docs.pingcap.com/zh/tidb/v7.4/hardware-and-software-requirements

集群混部问题

排查是不是部署过多的实例节点,如果节点个数太多也容易引起 OOM。生成环境下内存 128 GB 的机器,通常建议部署 2 个 tidb server 节点就够了。可以考虑通过增加cgroup策略来进行资源划分。

排查tidb server 是不是和 tikv server 混合部署,如果是也有可能会有内存相互挤兑从而触发问题。可以考虑通过增加cgroup策略来进行资源划分。

确认是否有业务进程混合部署,导致内存资源挤兑。应该专机专用,不部署业务程序。

数据库原因

如果发现内存正在上涨还没有出现 OOM 但是也有 OOM 的风险,可以根据下面的方式获取相关信息来分析:

查看当前链接的内存使用情况

执行 SELECT * FROM information_schema.processlist; 查看 SQL 对应的 MEM 列的值,定位到使用内存最多的语句。

执行以下命令收集内存使用率高的 tidb server 的 Profile 信息

curl -G http://{TiDBIP}:10080/debug/zip?seconds=10" > tidb_server_profile.zip

原因判断和处理:

问题 SQL 定位

获取可能的问题 SQL,可以查看 INFORMATION_SCHEMA 中的 SLOW_QUERY 和 CLUSTER_SLOW_QUERY 。

也可以通过 tidb dashboard的 慢SQL和 SQL语句找到问题附近的 SQL并分析,定位到具体的问题 SQL,从 SQL 语句分析、慢查询的具体内容,可以详细查看内存使用量。

同时 grep expensive_query tidb.log 辅助定位问题时间点的 SQL 情况。

如果确认是 SQL 的执行计划有问题,如缺少合适索引、统计信息过期、优化器 bug 等原因,很可能会导致选错执行计划而导致大量中间结果数据累积在内存,出现 OOM。

可以添加合适索引、使用 analyze 重新收集统计信息等措施进行处理。

如果确认 OOM 时是系统在收集和加载统计信息的过程中消耗太多内存。

可以指定采样率、指定只收集特定列的统计信息、减少 ANALYZE 并发度等方式减少内存使用。

 v6.1.0 以后引入了系统变量 tidb_stats_cache_mem_quota对统计信息的内存使用进行限制,引入了系统变量 tidb_mem_quota_analyze控制 TiDB 更新统计信息时的最大总内存占用。

如果OOM 问题发生时间附近,tidb session 的并发度过高或者某些节点的连接数过多。

需要扩容或优化负载均衡策略。

查看执行计划,如果发现存在算子 HashAgg 处理大量数据。

HashAgg 是多线程并发执行,虽然执行速度较快,但会消耗较多内存,可以尝试使用 STREAM_AGG() 替代。

如果出现 OOM 问题时段附近,业务访问有大事务或大写入,导致消耗太多内存。

tidb server 在执行事务时 TiDB 进程的内存消耗相对于事务大小会存在一定程度的放大,最大可能达到提交事务大小的 2 到 3 倍以上。

所以针对单个大事务,可以通过拆分的方式调小事务,可能需要和业务沟通调整程序。

排查和调整 tidb server 的配置参数

设置单条 SQL 使用的内存上限。

可以调整 session 级别参数 tidb_memory_quota_query 参数限制单条SQL语句的内存使用量,默认值为 1GB

设置单个 tidb-server 节点使用的内存上限。

v6.5.0以后可以通过系统变量 tidb_server_memory_limit 设置 tidb-server 实例的内存使用阈值,默认为总内存的80%。

TiDB 会在内存用量达到该限制时对当前内存用量最高的 SQL 语句 Cancel,然后会尝试调用 Golang GC 立刻回收内存,以最快速度缓解内存压力。

一次只能 Cancel 一条 SQL 语句。如果 TiDB 完全 Cancel 掉一条 SQL 语句并回收资源后,内存使用仍然大于该变量所设限制,TiDB 会开始下一次 Cancel 操作。被强制终止的 SQL 操作会向客户端返回报错信息 Out Of Memory Quota!。

使用系统变量 tidb_mem_oom_action 来控制单条查询超过内存限制后所采取的操作是 CANCEL 还是 LOG。

CANCEL 则会中断查询并打印相关日志。

LOG 则不会中断查询,仅仅记录相关内存使用信息。

设置数据落盘

HashAgg 落盘功能目前不支持 distinct 聚合函数。使用 distinct 函数且内存占用过大时,无法进行落盘。

当 SQL 的内存使用超过 Memory Quota 时,tidb-server 可以通过落盘执行算子的中间数据,缓解内存压力。可以启用临时磁盘 oom_tmp_storage ,指定路径tmp_storage_path 和使用外部磁盘的空间上限tmp_storage_size。

当包含 HashAgg 算子的 SQL 语句引起内存 OOM 时,TiDB 默认不触发落盘,可以通过设置系统变量 tidb_executor_concurrency = 1 来触发 HashAgg 落盘的功能。

如何处理tikv server的OOM问题

非数据库原因

机器内存不足

确认部署 tikv server 的机器操作系统内存是否太少,导致内存不足。开发及测试环境建议值是32 GB+,生产环境建议值是 64 GB+。

https://docs.pingcap.com/zh/tidb/v7.4/hardware-and-software-requirements

集群混部问题

排查是不是部署过多的实例节点,如果节点个数太多也容易引起 OOM。可以考虑通过增加cgroup策略来进行资源划分。

排查 tikv server 是不是和 tidb server 混合部署,如果是也有可能会有内存相互挤兑从而触发 OOM 问题。可以考虑通过增加cgroup策略来进行资源划分。

确认是否有业务进程混合部署,导致内存资源挤兑。其他进程占用过多内存,也可能会导致系统误杀 tikv 进程。应该专机专用,不部署业务程序。

数据库原因

排查 block cache 参数配置是否合理。通过查看 TiKV Detail  -> RocksDB KV -> Block cache size 面板查看内存使用变化。

如果是block cache的问题,则合理调整storage.block-cache.capacity参数大小,默认为系统内存的45%,通常可以设置范围为45%-60%,配置过高导致容易OOM。如果是多个节点同时部署的时候,尤其要注意该参数的配置,可以设置 storage.block-cache.capacity = (MEM_TOTAL * 0.5 / TiKV 实例数量)。

https://docs.pingcap.com/zh/tidb/stable/hybrid-deployment-topology

在 v6 以后的版本支持在MySQL终端在线修改该参数set config tikv xxxx=xxxx (推荐);或者tiup cluster edit-confg xx 编辑修改再reload重启tikv实例。

确认是否因为读取大量数据导致 OOM 。查看 tikv details 的copprocessor 面板,以及查看 node-exporter的network面板查看 gRPC的网络传输量,确认是不是远远小于copprocessor读取的数据量。

如果是 copprocessor 读取大量数据而gRPC来不及消费传送到TiDB server,说明有大 SQL 出现导致 copprocessor 读取大量数据到 tikv 的 block cache 中而 gRPC 来不及消费传送到 tidb,会导致数据堆积过多而 OOM。此时可以采取下面的处理措施:

优化SQL使得一次性不读取大量数据。

如果机器使用的是千兆网卡,则建议升级为万兆网卡。

对于 TiKV OOM 的分析,社区里 h5n1 大佬的这篇文章也非常推荐阅读 https://tidb.net/blog/ab528ebf

总结

TiDB 出现 OOM 问题,最频繁的节点是在 tidb server 中,而引起问题的最多原因是因为大 SQL 或执行计划不准。

而 tikv 出现 OOM 的问题,大多数是因为 block cache 配置问题引起,在部署和排查时可以重点关注该方面问题。

我们在日常运维管理工作中,针对这些场景有一定的提前规划和准备,即可从容应对大部分的 OOM 问题。

社区也有不少很不错的 OOM 排查实践案例,在遇到问题时可以一并参考。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:MySQL 到 TiDB:vivo 的 Hive Metastore 横向扩展之路
下一篇:同城双机房公网+阿里云ECS搭建混合云TIDB集群
相关文章