我们有一个 Drupal 7 站点,其设置如下 - 运行 web vm 和 NFS VM 的 VMware ESXi 4.1 主机服务器。web VM 使用 Apache 和 mod_php。该站点仍在开发中,因此由于文件更新频繁,我们必须关闭所有形式的缓存。
每个页面请求大约需要 15-20 秒才能完成。分析 PHP 代码显示,绝大部分时间(通常超过 90%)都花在了加载模块的所有 is_dir()、is_file() 函数调用上。
我将 PHP 的 realpath 缓存大小增加到几兆,strace 显示 lstat 调用从 200 多个减少到 6 个左右,stat() 也减少了一点(大约 600 个调用)。然而,虽然这节省了不少时间,但我还是无法突破最苛刻的页面每次请求 10 秒的限制。
有没有一种方法可以从不涉及缓存的设置中获得更好的性能?
编辑:MySQL 不是问题,查询缓存意味着请求最多需要一秒钟才能完成。
配置和统计:
VM 主机:单个四核 Xeon CPU
虚拟机:
web - Centos 6 64bt,2.5GB RAM,正常 CPU/HD 优先级(2 核) nfs - Centos 6 64bt,2GB RAM,正常 CPU 优先级(4 核),高 HD 优先级
PHP:32M 真实路径缓存大小(出于测试目的,这个值太高了)
NFS:
~]# egrep -v '#|^$' /etc/nfsmount.conf
[ NFSMount_Global_Options ]
Defaultvers=4
Ac=False
Rsize=32k
Wsize=32k
Bsize=32k
通过 NFS 读取速度不是问题,使用 32k 块对 100M 测试文件进行 dd 返回:
3200+0 records in
3200+0 records out
104857600 bytes (105 MB) copied, 1.84984 s, 56.7 MB/s
real 0m1.857s
user 0m0.007s
sys 0m0.330s
在具有空真实路径缓存的 Apache 进程上进行 Strace:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
50.78 1.157452 337 3434 28 stat
32.58 0.742656 628 1182 425 open
9.29 0.211788 762 278 1 lstat
3.17 0.072322 0 237865 write
2.45 0.055839 490 114 13 access
0.45 0.010262 43 237 brk
0.34 0.007725 10 811 74 read
0.28 0.006340 9 679 fstat
0.22 0.005069 18 281 poll
0.20 0.004533 6 698 getdents
0.09 0.001960 10 190 mmap
0.05 0.001065 14 74 accept4
0.04 0.001000 333 3 chdir
0.03 0.000750 4 190 munmap
0.01 0.000339 0 836 close
0.01 0.000247 3 75 writev
0.00 0.000068 0 611 fcntl
0.00 0.000063 1 77 shutdown
0.00 0.000000 0 1 lseek
0.00 0.000000 0 5 rt_sigaction
0.00 0.000000 0 1 rt_sigprocmask
0.00 0.000000 0 3 setitimer
0.00 0.000000 0 5 socket
0.00 0.000000 0 5 5 connect
0.00 0.000000 0 74 getsockname
0.00 0.000000 0 15 setsockopt
0.00 0.000000 0 5 getcwd
0.00 0.000000 0 1 futex
------ ----------- ----------- --------- --------- ----------------
缓存真实路径后进行 Strace
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
60.14 1.371006 484 2831 28 stat
31.79 0.724705 627 1155 425 open
3.53 0.080354 0 237865 write
2.65 0.060433 530 114 13 access
0.43 0.009913 99 100 brk
0.38 0.008730 11 804 74 read
0.35 0.007910 12 675 fstat
0.30 0.006775 10 654 getdents
0.13 0.003065 11 281 poll
0.09 0.002000 333 6 1 lstat
0.07 0.001545 2 807 close
0.05 0.001063 14 74 accept4
0.04 0.001000 6 179 mmap
0.02 0.000404 2 179 munmap
0.01 0.000271 4 75 writev
0.01 0.000212 0 611 fcntl
0.01 0.000129 2 77 shutdown
0.00 0.000022 0 74 getsockname
0.00 0.000000 0 1 lseek
0.00 0.000000 0 5 rt_sigaction
0.00 0.000000 0 1 rt_sigprocmask
0.00 0.000000 0 3 setitimer
0.00 0.000000 0 3 socket
0.00 0.000000 0 3 3 connect
0.00 0.000000 0 15 setsockopt
0.00 0.000000 0 5 getcwd
0.00 0.000000 0 3 chdir
------ ----------- ----------- --------- --------- ----------------
山:
nfs.xxx.xxx.xxx:/path/to/website/files on /path/to/website/files type nfs (rw,hard,intr,noac,vers=4,addr=xx.xx.xx.xx,clientaddr=xx.xx.xx.xx)
我们当然感谢任何帮助。
答案1
坦率地说,NFS 上的 Drupal 真是个庞然大物。您最多只想通过 NFS 或类似 gluster 的东西来共享“文件”目录。在 NFS 上运行 DocRoot 的问题是,加起来,所有的 lstat(2) 和 access(2) 调用都是杀手级的,更不用说您将在模块目录中看到的 getdents(2) 和朋友了。类似 APC 的东西将大大有助于实际的 read(2) 时间,并消除编译延迟,但 PHP 仍将对每个文件执行 lstat(2) 和 access(2)。为了进一步加快速度,您可以设置 apc.stat=0,但如果您经常更改 PHP 文件,那么这将无济于事,正如您所说的那样,除非您愿意在每次进行此类更改时重新启动 Apache(或通过 apc.php 手动清除 APC 缓存)。
最佳实践建议将 DocRoot 存储在专用的优化设备(例如 SAN)上,或单独存储在每个 Webhead 上。“文件”目录通常应通过 gluster/nfs/etc 共享,但作为替代方案,您也可以定期在服务器之间 rsync 它,具体取决于用例以及前端的 LB 是否支持粘性会话。您还可以通过使用 CDN 或 Amazon 的 S3 或 BlackMesh 的 Swift 等服务完全消除文件目录。
拥有 Drupal 详细专业知识的托管服务提供商可以帮助您解决其中一些架构问题;您可能希望联系 Acquia 或 BlackMesh(我为后者工作)。我不知道 Acquia 是否提供,但我知道 BlackMesh 还提供场外协助,我们与您现有的托管服务提供商或现场托管合作,以优化 Drupal 解决方案。
祝您的网站好运!
答案2
一般情况下,使用 mount 进行挂载noac
都会影响性能。
你为什么要用它?
编辑:我看到上面的评论中说您稍后会添加更多 Web 服务器和负载平衡器。正如 BMDan 所建议的,如果您的应用程序需要使用,您应该研究集群文件系统(例如 OCFS2)noac
。
干杯