MySQL 服务器负载非常高

MySQL server very high load

我 运行 一个拥有 ~500 名实时访问者~50k 每日访问者 的网站总用户约 130 万。我在 AWS 上托管我的服务器,我在其中使用了多个不同类型的实例。当我启动该网站时,不同实例的成本大致相同。当网站开始获取用户RDS实例(MySQL DB)CPU不断的顶顶,我不得不升级了好几次,现在已经开始占据性能的主要部分和每月成本(大约 95%(2800 美元/月))。我目前使用具有 16vCPU 和 64GiB RAM 的数据库服务器,我还使用多可用区部署来防止故障。 我想知道数据库这么贵是正常的,还是我做错了什么?

数据库信息

目前我的数据库有 40 个表,其中大多数有 10 万行,一些有 200 万行,1 个有 3000 万行。 我有一个系统,当不再需要它们时,存档行早于 21 天。

网站信息

网站主要使用PHP,也有一些NodeJS和python。

网站的大部分功能是这样的:

  1. 开始交易
  2. 插入行
  3. 获取最后插入的 ID (lastrowid)
  4. 做一些计算
  5. 更新了插入的行
  6. 更新用户
  7. 提交交易

我还 运行 大约 100 个机器人以 10-30 秒的间隔从数据库进行轮询,它们有时也会 inserts/updates 数据库。

额外

我做了几件事来尝试降低数据库的负载。例如启用数据库缓存,对某些查询使用redis缓存,尝试删除非常慢的查询,尝试将存储类型升级为"Provisioned IOPS SSD"。但似乎没有任何帮助。

这是我对设置参数所做的更改:

我想创建一个 MySQL 几个较小实例的集群,但我不知道这是否有帮助,我也不知道这是否适用于事务。

如果您需要更多信息,请询问,非常感谢有关此问题的任何帮助!

根据我的经验,一旦您提出问题 "how can I scale up performance?",您就知道您已经超出了 RDS 的范围(编辑:我承认我的经验导致我得出这个观点可能已经过时)。

听起来您的查询负载非常重。大量的插入和更新。如果可以的话,您应该在您的 RDS 版本上增加 innodb_log_file_size。否则,您可能不得不放弃 RDS 并转移到 EC2 实例,您可以在其中更轻松地调整 MySQL。

我还会禁用 MySQL 查询缓存。在每个 insert/update 上,MySQL 必须扫描查询缓存以查看是否有任何需要清除的缓存结果。如果您的写入工作量很大,那么这是浪费时间。将查询缓存增加到 2.56GB 会使情况变得更糟!将缓存大小设置为 0,将缓存类型设置为 0。

我不知道您有什么查询 运行,或者您对它们的优化程度如何。 MySQL 的优化器是有限的,因此通常情况下您可以从重新设计 SQL 查询中获得巨大收益。也就是说,更改查询语法以及添加正确的索引。

您应该进行查询审核,找出哪些查询导致了您的高负载。 https://www.percona.com/doc/percona-toolkit/2.2/pt-query-digest.html, which can give you a report based on your slow query log. Download the RDS slow query log with the http://docs.aws.amazon.com/cli/latest/reference/rds/download-db-log-file-portion.html CLI 命令是一个很棒的免费工具。

设置你的long_query_time=0,让它运行收集信息一段时间,然后把long_query_time改回你平时使用的值。收集此日志中的所有查询很重要,因为您可能会发现 75% 的负载来自 2 秒以内的查询,但它们 运行 过于频繁以至于对服务器造成负担。

在您知道哪些查询占了负载之后,您可以针对如何解决这些问题制定一些明智的策略:

  • 查询优化或重新设计
  • 应用程序中的更多缓存
  • 横向扩展到更多实例

我认为答案是"you're doing something wrong"。您不太可能达到 RDS 限制,尽管您可能会在其中的某些部分达到限制。

首先启用详细监控。这将为您提供一些 OS 级别的信息,这些信息应该有助于确定您的限制因素到底是什么。查看您的慢速查询日志和数据库统计信息 - 您可能有一些查询导致问题。

一旦您理解了问题 - 这可能是错误的查询、I/O 限制或其他问题 - 然后您就可以解决它们。 RDS 允许您创建多个只读副本,因此您可以将部分读取负载转移到从服务器。

您也可以迁移到 Aurora,这应该会给您带来更好的 I/O 性能。或使用 PIOPS(或分配更多磁盘,这应该会提高性能)。您使用的是 SSD 存储,对吗?

另一项建议 - 如果您的计算(上述第 4 步)需要花费大量时间,您可能需要考虑将其分解为两个或多个事务。

超过50M的query_cache_size是个坏消息。您经常写作——每秒多次 table?这意味着 QC 需要扫描许多 times/second 以清除更改的 table 的条目。当QC为2.5GB时,这对系统来说是一个很大的负担!

query_cache_type 应该是 DEMAND 如果你能证明它是正确的。在这种情况下,用 SQL_CACHESQL_NO_CACHE.

填充 SELECTs

因为你打开了slowlog,用pt-query-digest查看输出。前几个查询是什么?

由于您的典型操作涉及写入,因此我看不到使用只读从站的优势。

机器人 运行 是随机出现的吗?还是他们都同时开始? (后者可能会导致 CPU 等出现可怕的峰值)

你"archiving""old"记录如何?最好使用 PARTITIONing 和 "transportable tablespaces"。使用 PARTITION BY RANGE 和 21 个分区(加上一些额外的分区)。

您的典型交易似乎只处理一行。是否可以将其修改为同时处理 10 个或 100 个? (超过 100 个可能不符合成本效益。)SQL 一次执行大量行比每行执行大量查询效率高得多。向我们展示 SQL;我们可以深入了解细节。

在一个事务中插入一个新行然后更新它似乎很奇怪。你不能在插入之前完全计算它吗?坚持 inserted_id 太久可能会干扰其他人做同样的事情。 innodb_autoinc_lock_mode 的值是多少?

"users" 彼此互动吗?如果是,是什么方式?