7

我有 nginx 接收 POST 请求和一个将请求正文放入 MySql 的小型 PHP 脚本。当我每秒有 300 个 POST 时,问题是 MySql CPU 使用率非常高。我希望 MySql 是一个快速的东西,每秒可以处理超过 300 次插入。我使用 Amazon EC2 小型实例,Amazon Linux。

top - 18:27:06 up 3 days,  1:43,  2 users,  load average: 4.40, 5.39, 5.76
Tasks: 178 total,   4 running, 174 sleeping,   0 stopped,   0 zombie
Cpu(s): 24.6%us, 13.4%sy,  0.0%ni,  0.0%id,  1.1%wa,  0.0%hi,  4.9%si, 56.0%st
Mem:   1717480k total,  1640912k used,    76568k free,   193364k buffers
Swap:   917500k total,     5928k used,   911572k free,   824136k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 7677 mysql     20   0  313m 153m 6124 S 39.0  9.2 393:49.11 mysqld
16529 nginx     20   0  157m 151m  820 R 15.2  9.0  28:36.50 nginx
29793 php       20   0 36780 3240 1896 S  2.5  0.2   0:00.34 php-fpm
29441 php       20   0 36780 3204 1892 S  2.2  0.2   0:00.78 php-fpm
29540 php       20   0 36780 3204 1900 S  2.2  0.2   0:00.82 php-fpm
29603 php       20   0 36780 3220 1892 S  2.2  0.2   0:00.61 php-fpm
29578 php       20   0 36780 3200 1900 S  1.9  0.2   0:00.42 php-fpm
29950 php       20   0 36780 3192 1900 S  1.9  0.2   0:00.48 php-fpm
30030 php       20   0 36780 3180 1888 S  1.9  0.2   0:00.08 php-fpm
30025 php       20   0 36780 3200 1888 S  1.6  0.2   0:00.11 php-fpm
29623 php       20   0 36780 3184 1892 S  1.3  0.2   0:00.49 php-fpm
29625 php       20   0 36780 3236 1900 S  1.3  0.2   0:00.46 php-fpm
29686 php       20   0 36780 3364 1900 R  1.3  0.2   0:00.51 php-fpm
29863 php       20   0 36780 3184 1892 S  1.3  0.2   0:00.23 php-fpm
30018 php       20   0 36780 3192 1892 S  1.3  0.2   0:00.19 php-fpm
29607 php       20   0 36780 3224 1900 S  1.0  0.2   0:00.42 php-fpm
29729 php       20   0 36780 3180 1888 R  1.0  0.2   0:00.41 php-fpm

这是我的PHP代码:

<?php
    $mysqli=new mysqli("localhost", "root", "", "errorreportsraw");
    $project_id=$_REQUEST["project_id"];
    $data=$_REQUEST["data"];
    $date=date("Y-m-d H-i-s");
    $mysqli->query("insert into rawreports(date, data, project_id) values ('$date', '$data', '$project_id')")
?>

我试过 mysql_connect, mysql_pconnect, mysqli("localhost",...), mysqli("p:localhost", ...) - 还是一样。除了这些插入之外,没有对数据库运行任何查询。

这是我的桌子:

CREATE TABLE `rawreports` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `date` datetime NOT NULL,
  `data` mediumtext NOT NULL,
  `project_id` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
);

这很简单,没有索引,只是为了存储 POST 数据以供以后处理。在大多数情况下,“数据”字段大约为 3 KB。尝试过 innodb 和 myisam - 还是一样。

这是我的 SHOW PROCESSLIST,除了多个插入之外什么都没有:

mysql> show processlist;
+---------+----------------------+-----------+-----------------+---------+------+------------------+------------------------------------------------------------------------------------------------------+
| Id      | User                 | Host      | db              | Command | Time | State            | Info                                                                                                 |
+---------+----------------------+-----------+-----------------+---------+------+------------------+------------------------------------------------------------------------------------------------------+
| 3872248 | root                 | localhost | NULL            | Query   |    0 | NULL             | show processlist                                                                                     |
| 3901991 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902003 | root                 | localhost | errorreportsraw | Sleep   |    0 |                  | NULL                                                                                                 |
| 3902052 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902053 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902054 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902055 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902056 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902057 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902058 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902059 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902060 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"protocol_version":" |
| 3902061 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902062 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902063 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902064 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902065 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902066 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902067 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902068 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902069 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902070 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902071 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902072 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902073 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902074 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902075 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902076 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902077 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902078 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902079 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902080 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902081 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902082 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902083 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902084 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902085 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902086 | root                 | localhost | errorreportsraw | Query   |    0 | update           | insert into rawreports(date, data, project_id) values ('2012-05-05 17-01-37', '{"exceptions":[{"stac |
| 3902087 | unauthenticated user | localhost | NULL            | Connect | NULL | Reading from net | NULL                                                                                                 |
+---------+----------------------+-----------+-----------------+---------+------+------------------+------------------------------------------------------------------------------------------------------+
39 rows in set (0.00 sec)

这是我在服务器仍处于压力下手动执行相同插入时的配置文件:

set profiling=1;
insert into rawreports(date, data, project_id) values('2012-05-04 00:58:08','[3000-chars-data-here]','5');
show profile ALL for query 1;

Status                          Duration    CPU_user    CPU_system  Context_voluntary    Context_involuntary    Block_ops_in    Block_ops_out   Messages_sent   Messages_received   Page_faults_major   Page_faults_minor   Swaps   Sourc
starting                        0.000231    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       NULL    NULL    NULL
checking permissions            0.000030    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       check_access    sql_parse.cc    4745
Opening tables                  0.000057    0.001000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       open_tables     sql_base.cc     4836
System lock                     0.000030    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       mysql_lock_tables       lock.cc 299
init                            0.000037    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       mysql_insert    sql_insert.cc   721
update                          0.075716    0.001999    0.011998    166                  2                      0               0               0               0                   0                   0                   0       mysql_insert    sql_insert.cc   806
Waiting for query cache lock    0.000087    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       lock    sql_cache.cc    552
update                          0.000037    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       NULL    NULL    NULL
end                             0.000024    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       mysql_insert    sql_insert.cc   1049
query end                       0.000042    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       mysql_execute_command   sql_parse.cc    4434
closing tables                  0.000031    0.000000    0.001000    0                    0                      0               0               0               0                   0                   0                   0       mysql_execute_command   sql_parse.cc    4486
freeing items                   0.000126    0.000000    0.000000    0                    1                      0               0               0               0                   0                   0                   0       mysql_parse     sql_parse.cc    5634
logging slow query              0.000030    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       log_slow_statement      sql_parse.cc    1460
cleaning up                     0.000024    0.000000    0.000000    0                    0                      0               0               0               0                   0                   0                   0       dispatch_command        sql_parse.cc    1416

我使用 MySql 5.5.20。尝试了 InnoDB 和 MyISAM - 都一样。
这是我的 iostat 输出:

# iostat -x
Linux 3.2.12-3.2.4.amzn1.i686 05/15/2012      _i686_  (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          23.67    0.03   18.39    4.09   52.87    0.95

Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
xvdap1            0.00     1.74    0.03    0.78     1.50    25.12    32.85     0.01   14.03   5.92   0.48
xvdap3            0.00     0.00    0.01    0.01     0.05     0.08    10.47     0.00    5.72   1.09   0.00
xvdf              0.40    18.59   23.14  117.55   753.12  3465.25    29.98     0.53    3.74   2.38  33.46

最明显的事情是批量插入并将它们全部提交,而不是一一提交。但我不能这样做,因为每个插入都是一个单独的 POST 请求,单独的 PHP 脚本执行。它们都是同时执行的,互不干扰。

看似很简单的任务,我的CPU究竟在做什么这么辛苦?对mysql、php、linux没有太多经验。可能我只是想念一些东西。感谢您的任何想法!

4

11 回答 11

6

通过“稍后”处理,您可能是指 1 小时或 1 天后?如果是这种情况,那么我会将信息写入一个 CSV 文件,您大约每小时轮换一次,然后当您需要进行“稍后”处理时,您可以使用将文件加载到 MySQL LOAD DATA INFILE

http://dev.mysql.com/doc/refman/5.1/en/load-data.html

我已经让 LOAD DATA INFILE 在不到一分钟的时间内加载了 100 MB 的信息,这种方法将是加快您的 Web 响应的好方法。

于 2012-05-11T04:33:54.723 回答
2

您是否在循环中运行该 PHP 代码?您可以在单个查询中一次插入多行,这可能有助于降低 CPU 负载。您需要做的就是提供一个逗号分隔的值列表,如下所示:

insert into rawreports(date, data, project_id) values (('$date1', '$data1', '$project_id1'),('$date2', '$data2', '$project_id2'), .....)")

此外,如果您在循环中运行,则无需new mysqli()为每次迭代重复。

于 2012-05-04T19:02:23.937 回答
2

没有索引,

这并不完全正确。
我会首先删除一个索引。
在日志类型表中,它没有任何意义。

顺便说一句,您也可以使用文本日志。用于后期处理。

要获得一些详细信息,您可以在服务器处于正常负载下时从 mysql 控制台运行这些命令:

> SET profiling = 1;
> INSERT an example query
> SHOW PROFILE ALL

也试试傻

SHOW PROCESSLIST;

这无疑会揭示一些有用但至少值得尝试的东西

于 2012-05-05T11:06:28.410 回答
2

从所有答案中我可以看出,您可以在分析后有以下选择来处理问题:

1) Amazon EC2 或任何云服务器的写入速度将低于常规专用服务器,因为 HDD iops 在物理节点上托管的所有虚拟服务器之间共享。因此,为 DB 配备单独的机器是个好主意,您甚至可以尝试使用 Amazon Simple DB。应该值得一试。

2)您可以尝试使用最简单的基于文档的 NoSQL 数据库,例如 MongoDB,与 MySQL 相比,它的写入操作速度快很多。我在本地机器上进行了基准测试,发现了令人惊讶的结果。因此,您可以真正将数据库存储在 NoSQL DB 中,而不是使用 CSV 方法,如果以后需要,可以将其推送到 MySQL 以使用批处理作业进行任何关系查询。

3) 如果您不使用任何 PHP 操作码/加速器,请使用它。

但我认为由于磁盘空间写入速度,MySQL 会保持并减慢甚至增加 CPU 使用率......

看看下面的文章是否对你有帮助:http: //kevin.vanzonneveld.net/techblog/article/improve_mysql_insert_performance/

于 2012-05-11T18:56:52.420 回答
2

不要直接使用插入数据到 MySQL。而是创建两个 csv 文件。说even_rawreports.csvodd_rawreports.csv。现在在偶数小时内(2:00 或 2:59 之间)继续记录每个 POST 请求,even_rawreports.csv并在奇数时间登录odd_rawreports.csv

even_rawreports.csv编写一个每小时运行并在奇数小时和偶数小时读取的 cron 作业odd_rawreports.csv

在 cron 中使用以下查询在一个查询中直接从 CSV 文件加载数据到 mysql。

LOAD DATA INFILE 'even_rawreports.csv' INTO TABLE rawreports (col1,col2,...)
    FIELDS TERMINATED BY '|' OPTIONALLY ENCLOSED BY '"';
于 2012-05-11T06:32:37.287 回答
2

虽然我同意使用纯文本日志文件或 NoSQL 数据库是更好的选择,但如果您要使用 MySQL,我认为您的瓶颈是 PHP。您是否使用持久连接和准备好的语句?如果没有,那就太浪费时间了。

您可以尝试使用hsock 模块nginx直接连接到 MySQL 。

另请注意,EC2 小型实例没有良好的 I/O 性能。您需要升级到 large 才能获得支持每秒 300 个帖子所需的 I/O 性能。

于 2012-05-10T06:59:44.197 回答
1

引入另一个数据库/二进制文件来支持 MySQL 似乎是最后的选择。在你到达那里之前,我希望你考虑一下:

MEMORY Storage Engine使用您定期刷新到主存储中的表创建一个表。

于 2012-05-16T03:52:25.407 回答
1

你试过插入延迟吗?

我读到您有来自不同客户端的 300 个帖子/秒,但无论如何您可以使用 bundle 一次插入多行。

收集帖子和插入行的单独逻辑。因此,您需要 2 个脚本 - 例如,第一个脚本只是收集所有帖子并将数据保存到文件中。Second 每秒定期运行一次,并将所有数据插入到表中。

顺便说一句:您可以使用 NOW() 插入当前日期 -> 插入 rawreports(date, data, project_id) 值 (NOW(),

于 2012-05-04T21:47:24.853 回答
0

您可以使用准备好的语句尝试 PDO,以利用客户端和服务器之间的二进制通信。

只需每次更改参数并执行即可。

除了传输到服务器的开销较低之外,这可能有助于 CPU 争用,因为 MySQL 不必每次都解析查询。

您必须对数据进行批处理(排队)才能利用这一点。

于 2012-05-04T19:14:44.833 回答
0

您是否尝试过使用存档存储引擎?如果您不需要更新/删除/替换,您应该尝试该选项。有关详细信息,请参阅http://dev.mysql.com/doc/refman/5.0/en/archive-storage-engine.html 。

于 2012-05-16T11:55:20.393 回答
0

基于 iostat,您在 5.5 上,我认为您受到亚马逊实例的 CPU 和磁盘 I/O 的限制。你能暂时转移到更快的实例,测量结果吗?没有太大的改进空间。MySQL 的 75ms 更新阶段显示它的 MySQL 杀死了你,而不是 PHP。我很惊讶300也是极限。我不确定数据完整性要求,但 MongoDB 可能适合您,甚至有受支持的 PHP 库。

于 2012-05-15T13:59:26.447 回答