MySql插入高CPU负载

时间:2012-05-04 18:53:52

标签: php mysql insert nginx cpu-usage

我有nginx接收POST请求和一个小的PHP脚本,将请求体放到MySql。当我每秒有300个POST时,问题是MySql CPU使用率非常高。我希望MySql是一个快速的东西,可以处理每秒300次插入更多。我使用Amazon EC2小实例,亚马逊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千字节。尝试过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)

当我在服务器仍然处于压力下时手动执行相同的插入时,这是PROFILE:

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经验。可能我只是想念一些东西。谢谢你的任何想法!

11 个答案:

答案 0 :(得分:6)

通过“后期”处理,您可能意味着1小时或1天后? 如果是这种情况,那么我会将信息写入CSV文件,您每小时左右旋转一次,然后当您需要进行“后期”处理时,可以使用LOAD DATA INFILE <将文件加载到MySQL中/ p>

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

我有LOAD DATA INFILE在不到一分钟的时间内加载了100 MB的信息,这种方法可以加速您的网络响应。

答案 1 :(得分:2)

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

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

如果您在循环中运行,则不需要为每次迭代重复new mysqli()

答案 2 :(得分:2)

  

没有索引,

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

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

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

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

也尝试傻了

SHOW PROCESSLIST;

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

答案 3 :(得分:2)

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

您可以尝试使用hsock module直接将nginx连接到MySQL。

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

答案 4 :(得分:2)

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

编写一个每小时运行一次的cron作业,并在奇数小时内阅读even_rawreports.csv,在偶数小时内阅读odd_rawreports.csv

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

LOAD DATA INFILE 'even_rawreports.csv' INTO TABLE rawreports (col1,col2,...)
    FIELDS TERMINATED BY '|' OPTIONALLY ENCLOSED BY '"';

答案 5 :(得分:2)

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

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

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

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

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

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

答案 6 :(得分:1)

您是否尝试过INSERT DELAYED?

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

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

BTW:您可以使用NOW()插入当前日期 - &gt;插入rawreports(date,data,project_id)值(NOW(),

答案 7 :(得分:1)

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

使用MEMORY Storage Engine创建一个表格,该表格会定期刷新到您的主存储空间。

答案 8 :(得分:0)

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

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

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

您必须批量(排队)数据才能利用这一点。

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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