1

我有一个具有以下参数的服务器:

  • 操作系统:Ubuntu 18.04.4 LTS x86_64
  • 主机:X11DPi-N(T)
  • 内核:4.15.0-112-generic
  • CPU:Intel Xeon Silver 4214 (48) @ 2.201GHz
  • GPU:ASPEED Technology, Inc. ASPEED 图形系列
  • 内存:18552MiB / 96336MiB
  • SSD 三星 MZQLB960HAJR-00007 894.3G x 2

随着安装5.5.5-10.4.12-MariaDB-1:10.4.12+maria~bionic。在此屏幕截图中显示了标准数据库负载:

在此处输入图像描述

所以我每秒大约有 400-500 次选择(主要来自具有 50 万条记录的不太大的表),每秒 100-190 次更新,以及大约 50-150 次同时连接。

我的问题是:有时,没有明显的原因,服务器有 2000-3000 个打开的连接/进程。根据SHOW FULL PROCESSLIST它们是标准 SQL 请求,但具有“发送数据”状态和 400-500 秒的运行时间。当然,此时服务器死机,无法正常运行。我说“没有明显的原因”,因为此时我没有看到用户数量增加或网站上的活动增加。此外,重新启动 MariaDB 服务或完全重新启动服务器有助于摆脱这种情况,但并非总是如此:有时即使在重新启动后,我几乎会立即获得相同的 2000-3000 个冻结进程。

有没有人遇到过类似的数据库行为?我会很感激任何想法。

升级版:

  1. 我所有的 SELECT 只调用一个表(约 50 万条记录,没有JOIN和/或子查询),而且大多数都有LIMIT 1,所以没有那么多数据。

  2. 错误日志显示了很多这样的记录:2020-08-26 22:12:35 787380 [Warning] Aborted connection 787380 to db: ... (Got timeout reading communication packets)

  3. innodb_lock_wait_timeout为 50(默认)

  4. 慢查询日志没有显示异常

  5. 我的optimizer_switch设置:index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on

4

4 回答 4

1

这听起来像是查询优化器随机死机的经典案例。这是一个长期存在的heisenbug。

当您看到查询堆积如山时,运行SHOW EXPLAIN FOR thread_id堆积的 ID 之一。查看查询计划是否不合理。如果是,请编辑查询应用端以包含索引提示,以防止查询优化器出错。如果您无法更改查询,您将不得不摆弄optimizer_switch设置,直到您确定并删除使优化器发疯的特定选项。

于 2020-08-25T14:31:56.770 回答
1

解决方案非常简单:在研究了 MariaDB 文档(尤其是这篇文章https://mariadb.com/kb/en/thread-pool-in-mariadb/)后,我添加了以下内容,my.cnf问题就消失了

thread_handling=pool-of-threads
thread_pool_size=48 
#48 is a number of CPUs
于 2020-09-08T02:11:03.200 回答
1

错误日志中有任何内容吗?

如果数据库冻结,很可能是磁盘问题:可能是磁盘已满,如果 mariadb 无法写入任何内容,则冻结 1 分钟,如果临时表填满磁盘,则磁盘可能已满,或者一个表上的更改,使用复制算法可以;您是否正在监视您的磁盘使用情况(不是在图像中,您应该)?可能是磁盘 I/O 都被一个查询使用:那么所有查询仍然会运行,但速度很慢,所以是卡住了还是真的很慢?可能是锁问题?

由于查询运行了很长时间(400-500s),它很可能不是锁:除非您更改了它,否则锁等待超时更短(至少它在 innodb 上:50s)。

如果您知道没有ALTER TABLE运行,并且没有磁盘问题(您可能也想检查 inode),它仍然可能是一个锁:SHOW ENGINE INNODB STATUS\G检查。

你说做一个SHOW FULL PROCESSLIST只有标准的 SQL 请求,所以很可能没有ALTER TABLE

如果你有一个写得不好的查询,一个临时表可能会填满你的磁盘,所以你需要EXPLAIN在执行时显示的查询SHOW FULL PROCESSLIST来分析这个,并重写/优化/限制此类查询的结果集的大小,寻找using temporary(你有时也可以在磁盘上进行排序:) using filesort慢查询日志会告诉您是否有使用磁盘的查询(如果在您重新启动服务器时它们没有被杀死)。

如果您没有时间优化查询,并且如果它们大大SELECT减慢了您的整个数据库,以向用户显示信息(报告),您可以使用脚本终止查询时间过长:这应该是最后的手段(您的脚本杀死查询花费太长时间可能会编写它们,以便您稍后能够分析它们)。

填充磁盘或使用所有 I/O 的临时表是我看到数据库冻结并在重新启动后重新启动的唯一情况。对于数据库再次冻结的情况,可能用户正在再次(一次又一次)执行相同的查询。

编辑

可能不是您的数据库问题,而是您的 Web 应用程序:错误日志消息表明数据库正在终止某些连接。

查询的组合是发送数据中止的连接对我来说是不寻常的。通常,如果 Web 应用程序没有关闭连接并且它们处于睡眠状态,则会发生连接中止。你可以检查这篇文章中的所有内容

  • 检查网络问题(防火墙)
  • 检查 Web 应用程序日志中的错误
  • 检查是否max_allowed_packet足够大(如果您SELECT返回一行,那应该不是问题)

如果有睡眠查询,那么您没有正确关闭连接,然后您达到max_connection限制,并且不会发生新的连接。有些事情还不清楚:数据库是不是很慢,还是什么都没有发生?Web 服务器端发生了什么?

也可能是驱动程序(mariadb 客户端)使连接和查询处于发送数据状态,并且没有获取数据的结尾。如果它正在缓冲输出,并且在它实际可以之前被杀死(并且它也没有关闭连接),这可能会发生。它不符合LIMIT 1,但这可以解释为什么在发送数据状态中有中止的连接和SELECT查询。您的 Web 应用程序是什么语言的?我可以想到 php无缓冲查询,其中 php 进程崩溃以重新创建这种情况,但这可能是另一种特定于语言的问题。无论如何,这将是非常罕见的。

于 2020-08-25T21:39:03.613 回答
0

因此,我一直在努力解决挂在非常高的写入配置文件系统上的“发送数据”查询,我发现使用了上述解决方案以及降低脏页阈值并使用FORCE INDEX (blah)查询指令(由于 MariaDB漏洞)。在可能的情况下,MariaDB 版本在 10.5.x 系列中,特别是现在的 10.5.13。解决方案如下:

# -------------------------------------------------------------------
# Flush as often as possible to increase performance on high
# update tables
# -------------------------------------------------------------------
innodb_max_dirty_pages_pct_lwm = 0.0001
innodb_max_dirty_pages_pct     = 0.0001

# -------------------------------------------------------------------
# Thread handling
# -------------------------------------------------------------------
thread_handling             = pool-of-threads
thread_pool_size            = 112

在解决方案之前,我很容易就有超过 50GB 的脏页,现在它平均在 7-10GB 左右。由于该系统完全是 NVMe,因此更频繁地刷新页面不会导致任何明显的延迟增加,但两者的结合有所帮助。

注意:如前所述,MariaDB 目前存在一个查询优化器错误,优化器不会选择正确的索引来运行查询。有一些变通方法,但目前最好的方法是对FORCE INDEX (blah)较大的查询使用查询指令。这是采取的第三步。事实上,我只是在观看来自 MariaDB 基金会的视频,他们建议在升级之前始终在新版本的 MariaDB 上测试您的查询。作为一种解决方法,我现在尽可能多地选择 MariaDB。以下是错误报告:MariaDB 问题 MDEV-25480 MariaDB 问题 MDEV-25830

注意:这个系统在 SMT 模式下有 56 个内核,我根本没有看到 SMT 模式有太多好处。可能会在某个时候将其关闭。

注意:虽然您可以同时运行和查询,但不能EXPLAIN同时运行其中任何一个。所以,这个 bug 确实需要 MariaDB 基金会解决。不过,这将是一个很好的补丁,可以用于这些查询类型。UPDATEDELETEFORCE INDEX (blah)FORCE INDEX (blah)

于 2021-11-16T12:50:23.893 回答