如何解决 PHP、MySQL 和通用 I/O 的性能问题

如何解决 PHP、MySQL 和通用 I/O 的性能问题

我有一个基于 WordPress 的网站,运行在共享主机上。它的响应时间非常合适(检索 HTML 页面大约需要 2 秒,加载所有资源大约需要 5 秒)。

我计划将其移至专用虚拟服务器 (Ubuntu 12.04 LTS),理论上这应该会改善情况并使它们更加一致,因为它不是共享的。然而,我发现性能严重下降,页面生成需要 10 秒。

/etc/hosts我通过在服务器上编辑并将域映射到来排除网络问题127.0.0.1。我使用 Apache 负载测试器ab来获取 HTML,因此 JS、CSS 和图像都被排除在外。它仍然花了 10 秒。

我在服务器上安装了 Zpanel,该服务器也使用 MySQL,其页面加载速度非常快(1.5 秒),phpMyAdmin 也是如此。直接通过 phpMyAdmin 对 wordpress 数据库执行一些查询,返回结果也非常快,查询时间在 10 到 30 毫秒之间。

内存也足够,1Gb 物理内存中只使用了 800Mb,所以这似乎也不是交换问题。我还安装了 APC 来尝试提高 PHP 性能,但没有任何效果。

我还应该注意什么?什么可能导致性能下降?由于我在基于云的虚拟服务器上运行,这可能是某种 I/O 问题吗?

我希望能够向我的服务提供商提出这个问题,但如果不提供某些诊断的实际数据,我担心他只会责怪我的应用程序。

更新sar当我执行 HTTP 请求时(每秒)有输出:

02:31:29        CPU     %user     %nice   %system   %iowait    %steal     %idle
02:31:30        all      0.00      0.00      0.00      0.00      0.00    100.00
02:31:31        all      2.22      0.00      2.22      0.00      0.00     95.56
02:31:32        all     41.67      0.00      6.25      0.00      2.08     50.00
02:31:33        all     86.36      0.00     13.64      0.00      0.00      0.00
02:31:34        all     75.00      0.00     25.00      0.00      0.00      0.00
02:31:35        all     93.18      0.00      6.82      0.00      0.00      0.00
02:31:36        all     90.70      0.00      9.30      0.00      0.00      0.00
02:31:37        all     71.05      0.00      0.00      0.00      0.00     28.95
02:31:38        all     14.89      0.00     10.64      0.00      2.13     72.34
02:31:39        all      2.56      0.00      0.00      0.00      0.00     97.44
02:31:40        all      0.00      0.00      0.00      0.00      0.00    100.00
02:31:41        all      0.00      0.00      0.00      0.00      0.00    100.00

更新2按照 josten 的建议。

输入/输出:

iotop失败,OSError: Netlink error: No such file or directory (2)并且sar -d也失败Requested activities not available in file /var/log/sysstat/sa14。我认为这是因为这是虚拟机,就像也失败一样。这可能是报告始终为 0% 的iostat原因吗?%iowaitsar 1 10

CPU 负载:

占用 CPU% 最多的进程htop实际上是apache2。我以为这可能是数据库的问题,但事实并非如此。当我发出新的 HTTP 请求时,它会在几秒钟内上升到 94%。看来这就是罪魁祸首。

我做了strace -f -t一个总结strace -c -f。似乎有很多lstat调用(57786),其中 2455 个导致错误。不知道这是否正常。除此之外,最上面的调用是,wait4我认为这是正常的(只是在等待),和munmap。以下是前 5 个。

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 51.06    0.124742         897       139         6 wait4
 14.90    0.036388           1     57786      2455 lstat
  9.67    0.023622          13      1857           munmap
  7.69    0.018790          37       514           brk
  6.70    0.016361         481        34           clone
  2.87    0.006999          74        94        12 select

strace它本身就使 apache 的速度降低了 2 倍。我现在正在尝试了解长跟踪,以查看是否有任何迹象表明是什么导致 CPU 在几秒钟内飙升。

性能良好的服务器的典型时间是多少lstat?我希望收集一些信息,以便我可以以建设性的方式向提供商投诉是否是存储访问故障。

更新fio随机读取测试的输出:

random-read: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
fio 1.59
Starting 1 process
random-read: Laying out IO file(s) (1 file(s) / 128MB)
Jobs: 1 (f=1): [r] [100.0% done] [12185K/0K /s] [2975 /0  iops] [eta 00m:00s]
random-read: (groupid=0, jobs=1): err= 0: pid=24264
  read : io=131072KB, bw=10298KB/s, iops=2574 , runt= 12728msec
    clat (usec): min=119 , max=162219 , avg=380.34, stdev=957.37
     lat (usec): min=119 , max=162219 , avg=380.89, stdev=957.40
    bw (KB/s) : min= 7200, max=13424, per=99.89%, avg=10285.72, stdev=1608.68
  cpu          : usr=2.80%, sys=18.65%, ctx=33511, majf=0, minf=23
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued r/w/d: total=32768/0/0, short=0/0/0
     lat (usec): 250=45.57%, 500=37.17%, 750=3.41%, 1000=7.83%
     lat (msec): 2=5.67%, 4=0.27%, 10=0.08%, 20=0.01%, 250=0.01%

Run status group 0 (all jobs):
   READ: io=131072KB, aggrb=10297KB/s, minb=10545KB/s, maxb=10545KB/s, mint=12728msec, maxt=12728msec

我现在唯一的提示是,与其他系统相比,输出的 CPU 行fio似乎显示出相当多的活动。我在本地 Ubuntu 机器上运行它,输出为:

cpu          : usr=0.19%, sys=0.59%, ctx=32923, majf=0, minf=23

usr百分比似乎只是我的服务器上报告的一小部分。

更新Re PHP APC。是的,它已安装。phpinfo 的输出:

APC Support enabled
Version 3.1.7
APC Debugging   Disabled
MMAP Support    Enabled
MMAP File Mask  no value
Locking type    pthread mutex Locks
Serialization Support   php
Revision    $Revision: 307215 $
Build Date  May 2 2011 19:00:42

我应该检查哪些特定设置?这些是我的设置(本地值、主值):

apc.cache_by_default    On  On
apc.canonicalize    On  On
apc.coredump_unmap  Off Off
apc.enable_cli  Off Off
apc.enabled On  On
apc.file_md5    Off Off
apc.file_update_protection  2   2
apc.filters no value    no value
apc.gc_ttl  3600    3600
apc.include_once_override   Off Off
apc.lazy_classes    Off Off
apc.lazy_functions  Off Off
apc.max_file_size   1M  1M
apc.mmap_file_mask  no value    no value
apc.num_files_hint  1000    1000
apc.preload_path    no value    no value
apc.report_autofilter   Off Off
apc.rfc1867 Off Off
apc.rfc1867_freq    0   0
apc.rfc1867_name    APC_UPLOAD_PROGRESS APC_UPLOAD_PROGRESS
apc.rfc1867_prefix  upload_ upload_
apc.rfc1867_ttl 3600    3600
apc.serializer  default default
apc.shm_segments    1   1
apc.shm_size    32M 32M
apc.slam_defense    On  On
apc.stat    On  On
apc.stat_ctime  Off Off
apc.ttl 0   0
apc.use_request_time    On  On
apc.user_entries_hint   4096    4096
apc.user_ttl    0   0
apc.write_lock  On  On

更新增加到apc.shm_size96M。缓存已满计数现在为 0,在网站刷新几次后,缓存命中率为 96.5%。APC 内存使用量为 25.4MB。

它似乎将加载时间减少了 3 秒左右,现在如果我wget从服务器本身执行纯粹的操作而不获取任何图像等,则减少到大约 4 到 5 秒。仍然比其他托管慢两倍多,但肯定是一个进步。

我仍然觉得奇怪,为什么在服务器完全空闲的情况下,渲染这些页面要花这么长时间(我的开发电脑上没有安装 APC,它没有这种行为)。而且奇怪的是,这些额外的剩余时间被浪费在哪里。

答案1

这看起来和我见过的其他情况一样,Apache 花费大量时间编译 PHP。您是否确定安装了操作码缓存(例如 APC)?phpinfo()如果有帮助的话,它将在 的输出中显示为已加载的模块。否则,要跟踪 Apache 在 mod_php 中执行的操作,最好的选择是 XHProf。

对于除 jbx 之外通过 Google 到达此处的任何人:顺便说一句,其他答案都很棒。去读读它们。但那些答案以及 jbx 对它们的回复帮助我得出了这个结论。

答案2

您必须首先确定问题是什么;如果是 PHP、MySQL、I/O、负载、内存、CPU、内核等,则sar记录系统指标;您必须立即发现问题。您可以配置atop进行进程记帐,这绝对有帮助。

确定是否是 I/O

iotop使用和等工具atop查看磁盘使用情况;这些工具还会告诉您导致 IO 的原因。通常,如果 iowait持续超过 10% 则可能是这个问题。

sar记录磁盘 IO;因此您可以运行sar -d来查看它(查看%util列)。

判断是否负载

使用诸如htoptop、等工具uptime,再次将其与正在运行的进程联系起来,并找出有关进程正在做什么的更多详细信息。请注意,这会报告调度程序上的负载;它并不反映 CPU 使用率。

确定它是否是 CPU

sar再次拯救了局面;您可以使用 查看此信息sar -P ALL。您还可以使用mpstat -P ALL获取实时数据。通常,只有当所有 CPU 都达到 100% 时,CPU 才会成为问题;80% 以上意味着它们正在被利用(但不一定饱和)。

确定是否是内存(VM)

您需要使用vmstatvmstat -S M 1并观察swapiosystem列。显然,大量的交换会影响性能。还有部分system;大量的中断也会产生同样的效果。

判断是否是中断

您可以使用vmstat -S M 1。不幸的是,如果你的系统没有基线正常情况下。大量中断(由需要内核操作的硬件引起)将使系统运行缓慢。故障 NIC 因造成这种情况而臭名昭著。

确定是否是内核

这比较棘手,但通常需要straceperfsysdig工具。 其中一个工具是perf topstrace带有摘要(-c)的工具很好,但它不会将其与系统资源进行分解(因此提供的数据只是推测); 最好使用它perf top来得出它是内核的结论。stap如果您的机器支持,您也可以使用(SystemTap)。 我还应该指出,这strace会影响性能;sysdig如果系统非常重要,您应该使用它。

确定是否是 MySQL/PHP

您基本上必须遵循我上面发布的内容(perf例如,可以提供有关哪些命令导致内核时间过长的信息,,,可以iotop提供与使用系统资源相关的信息);基本上,您正在使用上述工具来确定导致负载的原因。atophtop

一旦确定它是 MySQL

这可能是您正在运行的查询(因此您需要EXPLAIN在 MySQL 中使用该查询)。您还需要确保您的数据库已优化,并且您正在执行的查询也已优化。您还必须确保您使用的表引擎适合您正在做的事情(我见过许多大型表使用 MyISAM,而它们应该是 InnoDB)。如果您确定以上都不是问题,但仍然怀疑 MySQL,您可能需要存档受影响表中的数据以减少对该表的访问(表扫描)。您可能还需要验证约束一致性、启用缓存缓冲并确保索引处于最佳状态。

有助于完成此过程的一个好工具是mytop;但提供的所有信息都mytop可以在mysql客户端轻松访问。运行一些有用的语句:

  • SHOW FULL PROCESSLIST\G获取当前正在执行的 SQL 语句的完整列表以及它们向服务器的状态。
  • SHOW ENGINE INNODB STATUS\G(仅限 InnoDB)
  • EXPLAIN EXTENDED <QUERY>解释您看到 MySQL 执行的查询。
  • SHOW GLOBAL STATUS\G服务器范围的状态

一旦你确定它是 PHP

您可以使用工具来分析您的 PHP 代码(例如xdebug),然后打开生成的配置文件以KCacheGrind查看所分析的 PHP 代码的性能分析。

如果您发现这些都不是,那么您可能只需要升级您的服务器。

答案3

查看我对另一个问题的回答与此类似,作为线索。

问题是,如果 WordPress 区域之外的其他页面加载正常,但 WordPress 本身却很卡,那么除了我推荐的一般方法之外,我还想到了三件事。

  1. 当您将 WordPress 代码迁移到新设置时,您是否确保在 中正确设置了文件系统上的所有路径wp-config.php?原因是,如果在 MySQL DB for WordPress 选项中设置了错误的路径,有时 WordPress 仍可以工作。确保它们在 中可wp-config.php强制 WordPress 使用正确的目录并确保临时和缓存文件夹按预期工作。
  2. 数据库变慢?这是我能想到的唯一一个 WordPress 特有的问题,但其他页面仍能加载。你确定你的 MySQLmy.cnf能够满足你网站的数据库需求吗?
  3. 您的 WordPress 代码中是否有启用 Gzip 压缩的插件或设置?一般来说,Gzip 压缩应该通过 Apache 或 Ngnix 在服务器端进行,因为它们可以比 PHP 代码更有效地处理 Gzip 压缩。因此,如果您在 WordPress 中启用了缓存,请禁用它,因为 PHP(WordPress 使用的)不擅长 Gzip 压缩。

总的来说,我在云服务器上设置了大量 CMS 网站(最近是 WordPress),没有出现任何问题。10 秒的页面加载时间并不是云主机不足的症状。我建议查看我在这里和我在其他答案中推荐的内容。我还建议通过在有问题的设置上进行干净的 WordPress 安装进行调试,看看它如何反应。如果与您的完整网站相比,它运行良好,那么很明显您的网站特定代码中存在一些配置问题。

编辑:这是另一个想法。您的设置中是否有 Apache 授权 (htaccess)?您是否将其设置为允许来自localhost?见下文。有时此设置有效,但如果Allow from localhost是列表中的第一个Allow或列表中的唯一项目,Allow它可能会因反向 DNS 怪异而阻塞。我建议尝试禁用它(如果可以的话),并查看与启用它相比站点的加载速度有多快。

Order Deny,Allow
Deny from all
Allow from 127.0.0.1 ::1
Allow from localhost

答案4

对于流量很大的网站来说,最大的 I/O 来源之一是/tmp来自以下位置的 I/O:

  1. /tmp读取 php 会话数据,对于许多 CMS 系统,例如 WordPress,每次页面转换时都会确定访问者是否有权访问新页面

  2. /tmp对于任何 SQL SELECT 来说,都会被写入/读取多次,其中返回的数据或创建的任何临时选择集都位于 /tmp 中

将一台慢速机器的客户端迁移到一台新机器(希望是更快的机器)时,我做的第一件事就是调整内存大小。我的快速 30 秒算法是:

(顶部内存使用量 + 交换区使用量) * 2

然后在新机器上设置/tmp运行临时文件(记忆)+使用mysqltuner(每隔几天)+ 调整 mysql(实际上是 mariadb)直到mysqltuner总体来说比较安静。

有时,这个简单的技巧就足以让性能缓慢的服务器焕发新的生机。

一旦完成,如果机器仍然运行缓慢,我就会开始研究调整每个子系统。

在进行调整时,我总是从一个可以告诉我当前状态的工具开始。

因此,对于内存调整大小,请使用 top (memory + swap + load)。

为了阿帕奇,检查日志以确保没有超出 MaxRequestWorkers 之类的消息。

对于老PHP版本使用 APC 监视器来确保 APC 确实在工作 + 有足够的内存 + 命中率高 - 90%+ 是一个很好的目标。

对于现代 PHP 版本,对 Opcache 执行相同的操作,它在几年前取代了 APC。

为了MySQL,首先切换到 MariaDB(以我的经验来说速度更快)+每隔几天使用 mysqltuner 直到获得相当安静的输出。

为了内容管理系统就像 WordPress 一样,永远不要轻信任何人关于缓存插件是否有效的言论。使用 ab 测试网站速度,首先不使用任何缓存 + 添加缓存插件 + 重新测试。

提示:从 ZenCache + 开始,您会感到惊讶。

最后,我模拟了一只懒猴分布式拒绝服务攻击我设置的每台新服务器,因为 DDOS 行为会根据网络布局 + 适配器速度 + 机器资源而有所不同。我调整系统以抵御 DDOS 攻击,使 Apache 4xx 状态代码(通常为 400 + 408)能够显示在 Apache 日志中 + 使用 fail2ban 阻止这些 IP。

I/O 调优的一个重要部分是在将任何站点部署到机器上之前生成异常负载情况,例如 slowloris DDOS。这样,您就可以在闲暇时进行调优,而不是尝试在实际负载下进行调优,例如 Ad Spend 或 Slashdotted... 或在攻击负载下进行调优,例如 DDOS 或高价值攻击,或者只是一个忽略您的robots.txt+ 的邪恶抓取者会从您的机器中吸走所有资源。

相关内容