我在 1gb DigitalOcean 液滴上运行 MySQL,并且通过运行的 Laravel 框架有许多计划任务。特别是一项任务(似乎)随机导致 MySQL 处于 100% CPU,我不确定从哪里开始追踪原因。
该作业下载一个包含 360 个值的 JSON 文件,并将结果存储(或更新)到数据库中。完成后,它会调用另一个函数来获取过去 4 小时(大约 240 行)的所有结果并将其转换为静态图像。这从 cron 作业每两分钟运行一次,如果作业失败,它会在放弃之前重试作业最多 10 次。
根据show processlist;
,查询是:
mysql> show processlist;
+-----+-------+-----------+---------------------+---------+------+--------------+-------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-----+-------+-----------+---------------------+---------+------+--------------+-------------------------------------------------------------+
| 271 | dbusr | localhost | sample_database_com | Execute | 0 | Sending data | select * from `kp_minutes` where (`updated_at` = ?) limit 1 |
| 297 | dbusr | localhost | sample_database_com | Execute | 0 | Sending data | select * from `kp_minutes` where (`updated_at` = ?) limit 1 |
| 303 | dbusr | localhost | sample_database_com | Execute | 0 | Sending data | select * from `kp_minutes` where (`updated_at` = ?) limit 1 |
| 308 | dbusr | localhost | sample_database_com | Execute | 0 | Sending data | select * from `kp_minutes` where (`updated_at` = ?) limit 1 |
| 311 | dbusr | localhost | sample_database_com | Execute | 1 | Sending data | select * from `kp_minutes` where (`updated_at` = ?) limit 1 |
| 317 | dbusr | localhost | sample_database_com | Execute | 0 | Sending data | select * from `kp_minutes` where (`updated_at` = ?) limit 1 |
| 318 | dbusr | localhost | sample_database_com | Sleep | 1 | | NULL |
| 324 | dbusr | localhost | NULL | Query | 0 | starting | show processlist |
| 325 | dbusr | localhost | sample_database_com | Sleep | 3 | | NULL |
+-----+-------+-----------+---------------------+---------+------+--------------+-------------------------------------------------------------+
9 rows in set (0.00 sec)
为了解决这个问题,我必须清除 Laravel 中所有排队的作业,然后重新启动 MySQL,我最终每天都会这样做一两次。
我还有其他工作做类似的事情,但数据要多得多。例如,一项作业在数据库中插入(最多)500,000 个项目,然后将这些值拉出并制作成静态图像。这些作业运行得很好,所以我不确定为什么select
240 行(看似)简单会导致问题。
我已经尝试将我的数据库繁重的工作推到列表的末尾,以防数十万行导致事情中断。我已经使用 Laravel 的lockForUpdate()
函数来锁定kp_minutes
行,我在存储数据和生成静态图像之间添加了延迟,我已经阅读了一堆 MySQL 问题试图找出发生了什么,但我已经一无所获。
我将如何追踪 100% CPU 的原因,我能做些什么来使此类“发送数据”进程超时?我的 MySQL 安装是 DigitalOcean LAMP 图像提供的默认设置,所以我认为我没有通过调整值搞砸任何事情。
编辑:回答几个问题:
- Laravel 应用程序与 MySQL 服务器在同一台服务器上运行。我知道我不应该这样做,但这是(希望是临时的)成本节约措施。
- Laravel 的任务调度系统使用单个 cron 作业来检查要运行的任务。然后它将这些任务发送到运行它们的队列(例如 Amazon SQS,或者在我的情况下,作为数据库中的一行)。这个“kp_minutes”任务每两分钟运行一次。
- 有问题的表包含大约 175,000 行,但我只选择了大约 240 个带有 where 子句的行
lockForUpdate()
内部使用for update
:select * from
kp_minuteswhere (
updated_at= ?) limit 1 for update
- 运行
show full processlist
给出的结果与我发布的相同。