我没有更改任何脚本或设置。现在我的 CPU 负载至少高出 4 倍。根据 TOP,Mysqld 占用了大约 360% 的 CPU。这是 Debian,我正在运行一些 MyISAM 表,但大多数是 InnoDB。我已经验证了当使用 InnoDB 的网站上线时负载会很高。即使现在晚上,总负载通常低于 1,也有 12。我不知道出了什么问题。我没有改变任何东西。我已经尝试完全重启机器。
我将 innodb_log_file_size 改为 2047M,而不是 512M,但负载没有明显改善。my.cnf 微调部分的其余部分如下:
key_buffer = 4000M
max_allowed_packet = 32M
thread_stack = 256K
thread_cache_size = 192
myisam-recover = BACKUP
max_connections = 10000
query_cache_limit = 1M
query_cache_size = 256M
innodb_buffer_pool_size=8G
innodb_additional_mem_pool_size=20M
sort_buffer=2M
thread_concurrency=16
record_buffer=2M
tmp_table_size=128M
max_heap_table_size=128M
table_cache=1024
innodb_log_file_size = 2047M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table
innodb_flush_method = O_DIRECT
这是一台 24GB RAM 的机器,运行 Apache 和 MySQL。每天大约有 2 万次访问。目前仍有 20GB RAM 可用(现在是晚上,我刚刚重新启动)。系统硬盘只占用了 8%。所有硬盘似乎都在以适当的速度写入/读取。
我的配置有问题吗?即使我没有更改任何服务器机器设置或 PHP 脚本,负载是否也可能突然升高?还有什么可能导致这种情况?
编辑:vmstat 的输出
vmstat 5 10
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
13 1 868 280368 179164 18089764 0 0 511 579 16 89 87 2 10 1
24 2 868 348948 183916 18136144 0 0 5791 610 1916 7552 89 2 7 1
23 0 868 501744 185972 18169456 0 0 3995 5877 2401 6277 91 3 5 1
6 0 868 694992 186136 18202684 0 0 3385 4783 1006 5958 91 2 7 0
22 0 868 825240 186372 18243540 0 0 4133 4087 1098 5364 91 2 7 0
19 0 868 284452 186540 18281960 0 0 3907 4380 537 6468 91 3 7 0
44 0 868 123408 177236 17022560 0 0 3896 5173 483 6914 88 5 7 0
17 0 868 159388 173236 16729360 0 0 4625 8856 1433 7072 89 3 8 0
14 0 868 248836 173380 16763992 0 0 5284 698 819 7357 88 2 9 0
15 0 868 406092 173592 16809708 0 0 4730 5794 1148 7224 90 2 8 0
ps -eo 命令,pid,ppid,%cpu,%mem,rss,pri,psr,size --sort=-%cpu|head -n 20
COMMAND PID PPID %CPU %MEM RSS PRI PSR SZ
/usr/sbin/mysqld --basedir= 379 342 364 11.1 2747020 19 1 14249120
gzip 5537 5536 30.1 0.0 756 0 3 452
/usr/sbin/apache2 -k start 2435 27735 6.6 0.3 75408 19 1 47184
/usr/sbin/apache2 -k start 2388 27735 6.7 0.3 77928 19 3 48144
/usr/sbin/apache2 -k start 2323 27735 5.9 0.3 79660 19 3 48464
/usr/sbin/apache2 -k start 2363 27735 5.8 0.3 77156 19 4 47256
/usr/sbin/apache2 -k start 2418 27735 5.7 0.3 77248 19 7 46684
/usr/sbin/apache2 -k start 2350 27735 5.8 0.3 78504 19 2 48092
/usr/sbin/apache2 -k start 2437 27735 5.5 0.3 75928 19 3 47436
/usr/sbin/apache2 -k start 2439 27735 5.5 0.3 75716 19 3 47596
/usr/sbin/apache2 -k start 2356 27735 5.7 0.3 78560 19 3 48708
/usr/sbin/apache2 -k start 2284 27735 5.6 0.3 79532 19 3 47896
/usr/sbin/apache2 -k start 2349 27735 5.6 0.3 78248 19 7 48548
/usr/sbin/apache2 -k start 2368 27735 5.6 0.3 77100 19 3 45852
/usr/sbin/apache2 -k start 2387 27735 5.5 0.3 79964 19 7 48952
/usr/sbin/apache2 -k start 2383 27735 5.4 0.3 79212 19 1 48448
/usr/sbin/apache2 -k start 2169 27735 5.4 0.3 81740 19 3 48636
/usr/sbin/apache2 -k start 2411 27735 5.3 0.3 77292 19 3 47628
/usr/sbin/apache2 -k start 1779 27735 5.4 0.3 88876 19 0 48384
mpstat 5 10
Linux 2.6.26-2-amd64 12/12/2014 _x86_64_
03:38:23 PM CPU %user %nice %sys %iowait %irq %soft %steal %idle intr/s
03:38:28 PM all 87.44 3.56 1.44 0.17 0.15 0.40 0.00 6.83 2363.80
03:38:33 PM all 86.82 3.31 1.82 0.12 0.05 0.25 0.00 7.62 1703.00
03:38:38 PM all 88.52 2.39 1.76 0.30 0.15 0.32 0.00 6.56 2552.68
03:38:43 PM all 85.12 3.92 2.17 0.27 0.10 0.42 0.00 7.99 2810.60
03:38:48 PM all 87.72 3.34 1.82 0.10 0.10 0.30 0.00 6.61 2368.00
03:38:53 PM all 85.36 3.83 1.59 0.40 0.05 0.17 0.00 8.59 1589.60
03:38:58 PM all 85.74 4.01 1.50 0.20 0.07 0.17 0.00 8.30 1648.00
03:39:03 PM all 85.26 4.16 1.75 0.20 0.12 0.60 0.00 7.91 1764.20
03:39:08 PM all 87.20 3.62 1.70 0.17 0.10 0.45 0.00 6.76 2221.80
03:39:13 PM all 85.96 3.12 2.67 0.27 0.05 0.52 0.00 7.41 2829.60
Average: all 86.52 3.53 1.82 0.22 0.09 0.36 0.00 7.46 2185.35
编辑,MySQL 5.5
升级到 MySQL 5.5 确实带来了很大的变化。白天负载从 20 降至 10,晚上从 10 降至 6。流量接近零 = 负载 6,高流量 = 负载 10。
=> 现在有趣的是,当前的负载是正好 5 分高于事件发生前的值。无论流量如何。这对我来说真的没有多大意义。几乎没有流量的情况下,8核CPU上没有理由加载6,更奇怪的是,加载仅双倍交通繁忙时。日负荷过去高出 5 倍比夜晚。
==> 要么是 MySQL 5.5 的效率高得惊人(与 5.0 相比),要么是无论如何都有某种东西可以增加这 5 分。但我看不出有什么特殊过程。它一定与 Apache/PHP/MySQL 有关。
编辑,已解决(自行解决)
4天前,负载突然无缘无故地飙升。今天凌晨,负载就这么降到了正常值。
我并不喜欢把所有问题都归咎于 DDOS,事实上,我通过查看网络统计数据排除了这种可能性。但话又说回来,我从未经历过任何攻击,我可能没有意识到。
事实:3 天后,我设法升级到 MySQL 5.5,虽然没有完全解决问题,但降低了负载,使网站在访问者端再次变得顺畅。一天后,问题消失了。这几乎就像有人在网站没有长时间加载时失去了兴趣。
操作系统损坏不会自行消失。没有后台任务。攻击似乎是唯一剩下的解释,尽管我没有注意到任何奇怪的网络活动。我可以说的是,我们的观众正是经常做这种事情的人。
编辑2014年12月29日
我不确定是否有人还在关注这个帖子。我只是想发布一个更新。几天后,高负载又回来了,然后几天后又消失了,又回来了等等。有时负载持续很高,有时突然上升。一天可以下降 50%,另一天又上升 100%。时间不同——与实际流量、后台任务等没有任何关系。虽然它看起来确实像 DDOS,但没有奇怪的网络活动。
不过,最大的不同是 MySQL 5.5,现在机器可以更好地处理消耗其资源的任何事情,保持网站正常运行。瓶颈似乎再次是 CPU,这又没有多大意义。
最“搞笑”的是这种行为的不可预测性。这真的不符合软件/硬件的任何错误,或者??
答案1
毫无疑问,我坚信它是 InnoDB 存储引擎。
它几乎就像一个活生生的、会呼吸的有机体。
以下是 Percona 首席技术官 Vadim Tkachenko 的图示
请注意 InnoDB 缓冲池。如果它有大量脏页(要写回物理表的更改)和相应的索引更改(缓冲池的插入缓冲区部分),请注意以下写入
- 将 I/O 线程从缓冲池写入 .ibd 文件(物理表文件)。这可能需要读/写 I/O,可能通过 LRU 算法打开和关闭表
- 对插入缓冲区写入系统表空间文件 (ibdata1) 的更改
- 由于您有 innodb_flush_log_at_trx_commit = 2,日志缓冲区每秒刷新一次(在休眠系统中这不是问题,因为 innodb_log_buffer_size 为 16,但在大量写入期间可能会出现问题)
- 脏页被写入双写缓冲区(帮助 mysqld 在 mysqld 崩溃时存活下来(或者至少是相当数量的 InnoDB 损害控制))
讨论 InnoDB 存储引擎有什么意义?
如果整个工作日中有大量脏页被写入,那么可能会有一些活动像心脏循环血液一样在引擎周围清除更改。即使是轻微的写入也可以隐藏一段时间。由于您有 2G 缓冲池,InnoDB 可能只是在搜索缓冲池(通过其清除线程)。
从 my.cnf 来看,我认为你可能使用的是 MySQL 5.5 或更高版本。InnoDB 在未进行调整时,往往会更积极地处理清除线程。
现在,令人惊讶的是,您是否知道即使至少 75% 的缓冲区仍是脏的,InnoDB 仍可以保持安静?
这意味着 InnoDB 不会容忍超过 75%(或 90%)的脏页。当脏页超过阈值时,它会启动积极的清除线程活动innodb_max_dirty_pages_pct
。一旦它低于 75% 或 90% 的阈值,InnoDB 将稳定地刷新脏页当一切准备就绪时。即使没有进行 INSERT、UPDATE 和 DELETE,这也表现为写入 I/O、服务器负载和 CPU 增加。尽管如此,InnoDB 仍会决定何时需要清除真正旧的脏页。
您可能需要的只是一些调整。以下是您需要的一些设置的示例。
[mysqld]
innodb_read_io_threads = 16
innodb_write_io_threads = 16
innodb_thread_concurrency = 0
要深入了解如何让 InnoDB 使用更多超线程和 CPU,请参阅我的 DBA StackExchange 帖子:
顺便问一下,你有 24GB 的 RAM,但缓冲池只有 2GB?请参阅我的旧帖子mysql innodb_buffer_pool_size 应该有多大?。为什么?即使对超线程和 CPU 进行了适当的调整,缓冲池过小,仍然可能会出现间歇性写入。
更新时间 2014-12-12 10:30 EST
由于您现在使用的是 MySQL 5.0,因此您可以使用以下设置使所有刷新尽可能彻底:
[mysqld]
innodb_thread_concurrency = 0
innodb_max_dirty_pages_pct = 0
这应该可以最大限度地减少或至少减少负载和 CPU 突然上升的情况
这些都是可选的
[mysqld]
innodb_fast_shutdown = 0
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
为什么这些可选设置?
- 环境innodb_fast_shutdown= 0
- 确保所有事务都刷新到磁盘
- 加快启动速度
- 环境innodb_flush_log_at_trx_commit设置为 1 即可正确刷新到表和重做日志。注意:某些硬件可能仍然不响应此设置。
- 如果你启用了二进制日志记录,sync_binlog将正确刷新二进制日志
从长远来看,您确实需要使用 MySQL 5.6。
答案2
该问题与存储引擎无关,问题可能是因为一些 SQL 查询占用了过多的 CPU 资源来处理该特定站点/应用程序。这可能是因为查询使用了“未索引”列或查询效率不高。更好地理解该问题,请在 mysql 上启用“慢查询”日志。
log_slow_queries=/var/log/mysql/slow-query.log
long_query_time=1
上述设置将导致处理时间超过 1 秒的查询被记录下来/var/log/mysql/slow-query.log
。稍后您可以参考日志来识别查询并对其进行微调。
识别问题的另一种方法是使用SHOW FULL PROCESSLIST
命令检查当前正在运行的查询列表。通过查看它,您可以缩小导致此问题的查询类型范围。
并粘贴 的输出vmstat 5 10
。这将有助于查找是否存在硬件瓶颈。