2

我拥有一个社区网站,大约有 12.000 名用户(写得很重),在具有 1Gb 内存的单个 VPS 上最多有 100 个并发用户。负载很少超过 3 并且响应非常好。

目前使用简单的文件缓存来存储数据库查询结果以减轻数据库的负载,但网站仍然可以减慢超过 220 个并发用户(负载测试)。

我怎样才能找出瓶颈是什么?

我认为数据库很好,因为缓存工作正常,但是磁盘 IO 可能会导致问题。每个页面加载有大约 10 个包含和来自数据库或文件缓存的 10-20 个查询,以及大量的 php 处理。

我尝试使用内存缓存而不是文件缓存,但令我惊讶的是,负载测试似乎更喜欢文件缓存。

我计划使用 Alternative PHP Cache,但我仍然不明白该缓存是如何失效的。我有一个处理所有请求的单一 index.php。缓存会存储每个单独请求的结果吗?如果我的包含(或缓存中的查询结果)之一发生更改,它会自动清除缓存吗?

寻找瓶颈的任何其他建议(尝试过xdebug)?

谢谢,哈姆雷特

4

5 回答 5

5

我计划使用 Alternative PHP Cache,但我仍然不明白该缓存是如何失效的。我有一个处理所有请求的单一 index.php。缓存会存储每个单独请求的结果吗?如果我的包含(或缓存中的查询结果)之一发生更改,它会自动清除缓存吗?

APC 不缓存输出。它缓存你编译的字节码。

本质上,一个普通的 PHP 请求是这样的:

  1. PHP 文件被解析并编译为字节码
  2. PHP 解释器执行字节码

APC 会缓存第一步的结果,因此您不会一遍又一遍地重新解析/重新编译相同的代码。默认情况下,它仍然stat()是每次请求时的 PHP 文件,以查看文件自其缓存副本编译后是否已被修改——因此对代码的任何更改都会自动使缓存副本无效。

您也可以像使用 memcached 一样使用 APC 来存储任意用户数据。但是请记住:

  1. 一个 memcached 服务器可以为多个服务器提供数据;APC 中缓存的数据只能在本地真正使用。最好从一个 memcached 盒向四台服务器提供一份数据,而不是在每台单独的服务器上的 APC 中拥有该数据的 4 个副本。
  2. 根据我的经验,Memcached 更擅长处理对单个缓存键的大量并发写入。
  3. APC 似乎不能很好地处理缓存被填满的问题。碎片增加,性能下降。

另外,请注意:除非您设置了某种锁定机制,否则基于文件的缓存可能会由于同时写入而损坏。如果您已经实现了锁定,那可能会成为其自身的瓶颈。IMO,并发是棘手的——让 memcached/APC/数据库处理它。

于 2009-11-17T16:32:03.040 回答
1

你提到你使用了XDebug - 你不能做什么?通常,要开始跟踪瓶颈,您需要启用请求分析,然后在KCacheGrindWinCacheGrind中查看生成的“cachegrind”文件。

至于使用缓存系统,像你这样的动态脚本通常会做这样的事情

  • 从脚本的唯一输入构造一个缓存“键”
  • 询问缓存系统是否有该键的数据。如果有,你很高兴去!
  • 否则,请尽一切努力生成数据,并要求缓存系统将其存储在所需的密钥下以备下次使用。

APC 缓存可以通过缓存 PHP 代码的解析版本来帮助进一步加快速度。

于 2009-11-17T16:21:48.353 回答
0

我在测试服务器上开启并配置了APC,得到了大约400%的性能提升

300 个并发用户,响应时间最长为 1.4 秒 :) 很好的开始。


更新:

实时服务器测试结果

原来的:

无 APC: 220 并发用户,服务器负载 20,响应时间 5000ms

无 APC: 250 个并发用户,服务器负载 20+,站点不可用

新的:

启用 APC: 250 个并发用户,服务器负载 2,响应时间为 600ms

启用 APC: 350 个并发用户,服务器负载 10,响应时间为 1500ms

启用 APC: 500 并发用户,服务器负载 20,响应为 5000ms + 站点已完全运行,但有点慢但可以正常使用

感谢您的建议,这是非常好的改进。

查询缓存被禁用,因为站点的写入量很大,因此整个表的缓存将不断失效。

于 2009-11-17T18:10:45.120 回答
0

我会说你的数据库很可能是 IO 绑定的,我不知道“VPS”到底是什么,但如果它是某种 VM,那么几乎可以保证 IO 的性能很差。

尽快将其安装到真正的硬件上;并获得合理数量的内存(1G 很小;16G 听起来更合理)。

然后您可以调整您的数据库,使其正常运行。您的数据总共有多大?如果您可以让所有这些(或大多数)适合您的数据库缓存(不是狡猾的查询缓存,正确的 innodb 缓冲池之一),那么就这样做。

我假设您使用的是 innodb 引擎;如果是这样,那么将缓冲池设置为足够大以容纳所有数据 - 如果您没有足够的内存,请购买更多直到您这样做(不,真的!)。

那么你的数据库查询应该很快,即使它们相当糟糕(是的)。

棘手的一点是,如果您只有一台机器,如何在 mysql 和 PHP 之间划分 ram 使用 - Web 服务器(我假设是 Apache),特别是如果您使用 prefork 和大量 MaxClients,可能会耗尽大量 ram 并剥夺你的数据库。

对工作进行一些体面的监控(带有趋势),仔细进行更改并准确记录您所做的更改。

于 2009-11-17T22:33:09.080 回答
0

MySQL有自己的查询缓存。

您可以通过设置query_cache_size为超过来启用它0

如果查询逐字重复并且不包含某些内容,例如非确定性函数、会话变量和此处描述的其他内容,则查询结果将从缓存中获取:

DML对任何底层查询发出任何操作都会使查询的缓存失效。

于 2009-11-17T16:20:44.717 回答