如何将php5 + MySQL扩展到200请求/秒以上?


16

我正在调整主页的性能,目前在3.14.by上它处理大约200个请求/秒,它吃掉6条SQL查询,在3.14.by/forum上它是phpBB论坛,每秒处理20个请求/秒。

奇怪的是,某些VPS和专用Atom 330服务器上的数字几乎相同。

服务器软件如下:Apache2 + mod_php prefork 4个子代(在此处尝试使用不同的数字),php5,APC,nginx,用于PHP会话存储的内存缓存。

MySQL配置为占用大约30%的可用内存(VPS上约为150Mb,专用服务器上约为700Mb)

看起来某个地方存在瓶颈,不允许我进一步发展,有什么建议吗?(即,我知道执行少于6个SQL会使它更快,但这似乎不是一个限制因素,因为由于缓存的查询,sqld的吃率最高不会超过百分之几)

有没有人测试过踢前叉apache2并只留下nginx + php快得多?

更多基准

Small 40-byte static file: 1484 r/s via nginx+apache2, 2452 if we talk to apache2 directly. 
Small "Hello world" php script: 458 r/s via ngin+apache2.

更新: 瓶颈似乎是MySQL对缓存数据的性能。具有单个SQL的页面显示354req / sec,其中有6个SQL-180 req / sec。您认为我可以在这里进行哪些调整?(我可以为MySQL分出100-200Mb)

[client]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
default-character-set=cp1251
collation-server=cp1251_general_cs

skip-character-set-client-handshake

user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
skip-external-locking

bind-address        = 127.0.0.1

key_buffer      = 16M
max_allowed_packet  = 8M
thread_stack        = 64K
thread_cache_size   = 16
sort_buffer_size    = 8M
read_buffer_size    = 1M

myisam-recover      = BACKUP
max_connections        = 650
table_cache            = 256
thread_concurrency     = 10

query_cache_limit       = 1M
query_cache_size        = 16M

expire_logs_days    = 10
max_binlog_size         = 100M

[mysqldump]
quick
quote-names
max_allowed_packet  = 8M

[mysql]
[isamchk]
key_buffer      = 8M

!includedir /etc/mysql/conf.d/

为什么同时使用Apache和Nginx?
jamieb 2010年

这是常见的配置,Apache2到PHP以及需要apache基础架构的各种应用程序,nginx来减少apache2负载时的内存占用。
BarsMonster 2010年

实际上,我不理解您的问题。您的网站当前运行缓慢吗?如果是这样,它有多慢?您希望加快多少速度?您是否尝试过分析网站的任何部分以确定瓶颈在哪里?
jamieb 2010年

在说明中:现在是每秒180-200个请求。虽然这对于主页来说已经足够了,但我想调整此设置,以使基于相同代码库构建的其他站点更快地工作。理想情况下,我想使100Mbit的动态页面饱和:-)
BarsMonster 2010年

2
在这种情况下,“每秒请求数”并不是一个有意义的指标。我的上网本可以处理“每秒200个请求”。您需要告诉我们在这种连接速率下您希望达到的响应时间。
jamieb 2010年

Answers:


29

显然,您可以尝试很多方法。最好的选择是在日志中查找不使用索引的查询(为那些索引启用日志)和其他未优化的查询。多年来,我已经汇编了许多与性能相关的选项,因此,这里包括一小部分信息供您参考-希望对您有所帮助。以下是一些有关您可以尝试的操作的一般说明(如果尚未尝试):

的MySQL

  • query_cache_type = 1-启用缓存SQL查询。如果设置为2,则仅在将SQL_CACHE提示传递给查询时才缓存查询。与类型1类似,您可以使用SQL_NO_CACHE提示禁用特定查询的缓存
  • key_buffer_size = 128M(默认值:8M)-MyISAM表索引的内存缓冲区。在专用服务器上,目标是将key_buffer_size设置为至少占服务器内存总量的四分之一,但不超过一半
  • query_cache_size = 64M(默认值:0)-查询缓存的大小
  • back_log = 100(默认值:50,最大值:65535)-未完成的连接请求队列。仅在短时间内有大量连接时才重要
  • join_buffer_size = 1M(默认值:131072)-进行全表扫描(无索引)时使用的缓冲区
  • table_cache = 2048(默认值:256)-应为max_user_connections乘以最重的SQL查询所包含的JOIN的最大数量。在高峰时间使用“ open_tables”变量作为指导。还要查看“ opened_tables”变量-它应接近“ open_tables”
  • query_prealloc_size = 32K(默认值:8K)-用于语句解析和执行的持久性内存。如果查询复杂,则增加
  • sort_buffer_size = 16M(默认值:2M)-帮助排序(ORDER BY和GROUP BY操作)
  • read_buffer_size = 2M(默认值:128K)-帮助进行顺序扫描。如果有许多顺序扫描,则增加。
  • read_rnd_buffer_size = 4M-帮助MyISAM表加快排序后的读取速度
  • max_length_for_sort_data-要存储的行大小,而不是排序文件中的行指针。可以避免随机读取表
  • key_cache_age_threshold = 3000(默认值:300)-将密钥缓存保留在热区中的时间(在降级为热区之前)
  • key_cache_division_limit = 50(默认值:100)-启用更复杂的缓存逐出机制(两个级别)。表示要保留在最低级别的百分比。delay_key_write = ALL-不会在每次索引更新时刷新表的键缓冲区,只有在关闭表时才刷新键缓冲区。这样可以大大加快键的写入速度,但是,如果使用此功能,则应通过使用--myisam-recover = BACKUP,FORCE选项启动服务器,从而添加对所有MyISAM表的自动检查。
  • memlock = 1-锁定内存中的进程(以减少换入/换出)

阿帕奇

  • 更改生成方法(例如,更改为mpm)
  • 尽可能禁用日志
  • AllowOverride无-尽可能禁用.htaccess。如果不使用.htaccess文件,它将停止apache的查找,因此可以保存文件查找请求
  • SendBufferSize-设置为操作系统默认值。在拥塞的网络上,应将此参数设置为接近通常下载的最大文件的大小
  • KeepAlive Off(默认设置为On)-并安装lingerd以正确关闭网络连接并且速度更快
  • DirectoryIndex index.php-保持文件列表尽可能简短。
  • 选项FollowSymLinks-简化Apache中的文件访问过程
  • 避免使用mod_rewrite或至少使用复杂的正则表达式
  • ServerToken =产品

的PHP

  • variables_order =“ GPCS”(如果不需要环境变量)
  • register_globals = Off-除存在安全风险外,还影响性能
  • 保持include_path尽可能最小(避免额外的文件系统查找)
  • display_errors = Off-禁用显示错误。强烈建议所有生产服务器使用(在出现问题时不要显示难看的错误消息)。
  • magic_quotes_gpc =关闭
  • magic_quotes _ * =关闭
  • output_buffering =打开
  • 尽可能禁用日志记录
  • exposure_php =关闭
  • register_argc_argv =关闭
  • always_populate_raw_post_data =关闭
  • 将php.ini文件放在php首先要查找的位置。
  • session.gc_divisor = 1000或10000
  • session.save_path =“ N; / path”-对于大型站点,请考虑使用它。将会话文件拆分为子目录

操作系统调整

  • 使用-o noatime选项挂载使用过的硬盘(无访问时间)。还要将此选项添加到/ etc / fstab文件中。
  • 调整/ proc / sys / vm / swappiness(从0到100)以查看效果最佳
  • 使用RAM磁盘-挂载--bind -ttmpfs / tmp / tmp

那是一个不错的列表,我已经拥有了其中的大多数,并且当我添加剩余的东西时,性能并没有提高。看起来瓶颈在PHP和MySQL之间,无法每秒处理来自查询缓存的800多个请求...
BarsMonster 2010年

好的,如何连接数据库(mysql_pconnect()而不是mysql_connect())?您是否使用持久连接?尝试两种方式...
Ivan Peevski

我已经在pconnect上,并且在php.ini中启用了连接池...:
BarsMonster 2010年

仅出于完整性考虑,我将尝试连接。我看过一些案例(尤其是在负载测试中),其效果更好。
伊万·佩夫斯基

1

如果瓶颈不是CPU,则它的IO-网络或磁盘。所以..您需要查看正在进行多少IO。我不会想到它的网络(除非您使用的是10mbps半双工链路,但是如果自动检测不能正常工作,它值得检查一下交换机)。

剩下的磁盘IO可能是一个很大的因素,尤其是在VPS上。使用sar或iostat来查看磁盘,然后在Google大量使用磁盘的情况下使用google如何查找更多详细信息。


是的,网络不是问题-从本地服务器运行ab时,性能是相同的。我已经检查了iowait时间-小于0.01%-基本上所有内容都在磁盘缓存中,并且在处理请求中不涉及任何磁盘写操作(所有日志均已禁用)。
BarsMonster 2010年

1

我会考虑使用Nginxmemcached)或Varnish进行缓存

至少,您应该使用Nginx服务器(如SaveTheRbtz所说的)来处理静态文件。


这些是动态页面,所以我宁愿不缓存它们。
BarsMonster 2010年

1
memcached不是传统的缓存应用程序,可以为动态页面带来奇迹。它位于数据库和您的应用程序之间。您的应用程序首先查询memcached以获取对象,如果该对象不存在,则从数据库中加载该对象。最终结果是,您正在使用RAM来满足数据库请求,而不是数据库上慢得多的持久性存储。
jamieb 2010年

Memcache可与nginx一起使用,这是已知功能。不使用较慢的持久性存储,它们全部在MySQL的查询缓存中。
BarsMonster 2010年

Memcached和MySQL的查询缓存并没有真正的可比性。他们甚至没有做同样的事情。您很快就会拒绝此处发布的几乎所有建议,而无需理会它们。我建议您多开放一些。
jamieb 2010年

我清楚地了解了memcached和MySQL查询缓存之间的区别。但是由于所有内容都位于查询缓存中,命中率为100%,因此我不称其为“慢速持久存储”。昨天的原始答案是关于使用NginX + Memcached的,这是缓存整个页面的非常常见的情况。缓存单个对象是另一种完全不同的方案。在使用MySQL前面的memcached的同时,我正在考虑暂时不使用它(因为这将需要很多代码更改)。
BarsMonster'2

1

由于服务器似乎没有问题,因此负载生成器可能是问题。尝试在多台计算机上运行它。


即使我从服务器本身运行,性能也一样。无论如何手动并发连接-10或50。通过ab -c 10 -t 10进行负载测试
BarsMonster 2010年

1

在我看来,您可能正在达到Apache允许的最大连接数量。请查看您的Apache配置。如果您还没有受到其他限制(例如I / O或内存)的约束,则增加服务器限制和最大客户端数应该会有所帮助。查看存在于mpm_prefork_module或mpm_worker_module的值,并进行相应调整以满足您的需求。

ServerLimit 512
MaxClients 512

好了,我真的需要这个前提是我必须在nginx的Apache2的面前,所以我相信有有更多的没有太大SENCE比物理核心* 2个的Apache2进程....
BarsMonster

刚刚验证了这一点。将Apache2进程的数量从4个增加到16个根本没有改善性能(甚至下降了0.5%)。Nginx工作人员的数量增加到2或4没有任何改善。
BarsMonster 2010年

1
如果您的数据是相当静态的,即它不会更新所有其他页面加载,则可以增加query_cache。MySQL将以这种方式保存结果集并从内存中提取。但是,如果正在缓存的表在此期间未收到任何写入,则会使缓存无效(即使数据不受影响),从而浪费内存。
Erik Giberti 2010年

现在我看到100%的查询缓存命中率,而MySQL仍然感觉很慢...
BarsMonster 2010年

1
将skip-name-resolve添加到您的MySQL配置文件中。这样可以节省与服务器的每个连接的DNS查找。这里的缺点是所有连接都需要通过IP锁定(假设您不使用'%')。如果SQL在同一台服务器上,并且不需要在localhost之外的任何地方访问,则还可以添加跳过网络以杀死整个TCP / IP堆栈。但是,我认为瓶颈是Apache。
Erik Giberti 2010年

0

该负载是由工具还是实际负载生成的?

您可能要检查memcached。我看到过高连接速率的问题会导致应用程序延迟。

如果使用负载生成器,则在碰到一个小的静态页面时会得到什么?

在加载期间,您可能需要检查网络堆栈的TIME_WAIT条件。也许您正在填充连接队列。

您还可以查看100多个原因和项目,但没有更多信息,我只是在此提出猜测。


它是通过ab-c 10 -t 10 URL进行测试的,我正在从服务器本身进行基准测试,因此网络不应该成为问题。我已根据您的要求发布了更多基准测试。
BarsMonster 2010年

我不会花太多的精力来调整ab。您可能会发现它不能很好地转化为现实世界的表现。您可能想要做的就是剖析您的应用程序并测试每个组件。例如,仅用很小的静态页面直接访问apache服务器。这将使您了解后端的最大请求/秒。将nginx放在前面,重新测试调用相同的后端文件。然后用一个简单的“ hello world”类型的php页面进行测试有时所有的层都可以掩盖一些简单的东西。另外,在测试过程中注意连接。确保您的网络堆栈未满。
jeffatrackaid 2010年

我昨天做了这些基准测试,它们在更新的原始问题描述中。另外,测试是在本地主机上完成的,因此网络不是问题。
BarsMonster 2010年

即使在本地主机上,网络也可能成为问题。在您的情况下不太可能,但这可能会引起问题。至少现在您的当前PHP设置的上限为〜450 req / sec。下一步是插入数据库调用,并查看其变化。我喜欢在进行高级调整时将其分开,因为它确实可以帮助您查明导致最多问题的层。
jeffatrackaid 2010年

-1

这样的问题有99%的时间可追溯到数据库。首先确保您的命中索引。如果这不起作用,请开始缓存所有可以缓存的内容。


都是索引,正如我所说,它甚至在100%的情况下都达到了MySQL查询缓存
BarsMonster 2010年

-1

我建议您使用(如果可能的话)连接池来保持数据库与Web应用程序的连接(无需在每次请求时都重新连接)。那会大大改变速度。

另外,尝试使用EXPLAIN分析所有查询(为什么不使用SHOW PROFILE来分析查询?)。


所有查询都使用索引。使用MySQL连接池。
BarsMonster 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.