我最近将客户的网站(使用 concrete5 CMS)移至运行 Gentoo、Apache 2.2、PHP5 和 MySQL 5 的 VPS,我注意到 Apache 的响应时间非常糟糕(旧服务器上也是如此),有时长达 8-9 秒,但更多时候在 300 毫秒到 3 秒之间(接近 300 毫秒我并不介意)。我知道这不是网络延迟,因为服务器的 ping(从我的位置)大约为 30 毫秒。
以下是时间的一个例子(您可以看到在最初的等待之后它变得很快):
我正在运行 APC(尽管我不确定这是否可行...) 和 SuExec。Apache 模块包括:
core_module (static)
authn_file_module (static)
authn_default_module (static)
authz_host_module (static)
authz_groupfile_module (static)
authz_user_module (static)
authz_default_module (static)
auth_basic_module (static)
include_module (static)
filter_module (static)
deflate_module (static)
log_config_module (static)
env_module (static)
expires_module (static)
headers_module (static)
setenvif_module (static)
version_module (static)
ssl_module (static)
mpm_prefork_module (static)
http_module (static)
mime_module (static)
status_module (static)
autoindex_module (static)
asis_module (static)
info_module (static)
suexec_module (static)
cgi_module (static)
negotiation_module (static)
dir_module (static)
actions_module (static)
userdir_module (static)
alias_module (static)
rewrite_module (static)
so_module (static)
suphp_module (shared)
PHP 模块包括:
bcmath
calendar
ctype
curl
db
dbase
domxml
exif
ftp
gd
gettext
iconv
imap
mbstring
mcrypt
mime_magic
mysql
openssl
overload
pcre
posix
session
standard
sysvsem
sysvshm
tokenizer
xml
xslt
zlib
我已经在所有相关文件上启用了 gzip。
Apache 使用 prefork 运行,httpd.conf 中的设置如下:
<IfModule prefork.c>
StartServers 10
MinSpareServers 10
MaxSpareServers 20
MaxClients 250
MaxRequestsPerChild 4000
</IfModule>
HostnameLookups Off
我注意到(我认为)数据库密集型的页面,例如 CMS 的仪表板,通常速度较慢。我认为这可能意味着 MySQL 可以优化。我还想知道 Apache 模块 - 我对 mod_php5、mod_cgi、mod_fastcgi 等感到困惑 - 网络上关于使用哪个模块最好有相互矛盾的建议。
以下是输出MySQLTuner:
-------- General Statistics --------------------------------------------------
[--] Skipped version check for MySQLTuner script
[OK] Currently running supported MySQL version 5.0.44-log
[OK] Operating on 64-bit architecture
-------- Storage Engine Statistics -------------------------------------------
[--] Status: -Archive -BDB -Federated -InnoDB -ISAM -NDBCluster
[--] Data in MyISAM tables: 35M (Tables: 161)
[!!] Total fragmented tables: 15
-------- Security Recommendations -------------------------------------------
[OK] All database users have passwords assigned
-------- Performance Metrics -------------------------------------------------
[--] Up for: 3d 21h 44m 16s (293K q [0.868 qps], 1K conn, TX: 135M, RX: 90M)
[--] Reads / Writes: 99% / 1%
[--] Total buffers: 58.0M global + 1.6M per thread (100 max threads)
[!!] Maximum possible memory usage: 219.7M (93% of installed RAM)
[OK] Slow queries: 0% (0/293K)
[OK] Highest usage of available connections: 2% (2/100)
[OK] Key buffer size / total MyISAM indexes: 16.0M/20.9M
[OK] Key buffer hit rate: 99.6% (5M cached / 21K reads)
[!!] Query cache is disabled
[OK] Sorts requiring temporary tables: 0% (0 temp sorts / 3K sorts)
[!!] Temporary tables created on disk: 47% (2K on disk / 5K total)
[!!] Thread cache is disabled
[!!] Table cache hit rate: 6% (64 open / 1K opened)
[OK] Open file limit used: 12% (128/1K)
[OK] Table locks acquired immediately: 100% (356K immediate / 356K locks)
-------- Recommendations -----------------------------------------------------
General recommendations:
Run OPTIMIZE TABLE to defragment tables for better performance
Reduce your overall MySQL memory footprint for system stability
Enable the slow query log to troubleshoot bad queries
When making adjustments, make tmp_table_size/max_heap_table_size equal
Reduce your SELECT DISTINCT queries without LIMIT clauses
Set thread_cache_size to 4 as a starting value
Increase table_cache gradually to avoid file descriptor limits
Variables to adjust:
*** MySQL's maximum memory usage is dangerously high ***
*** Add RAM before increasing MySQL buffer variables ***
query_cache_size (>= 8M)
tmp_table_size (> 32M)
max_heap_table_size (> 16M)
thread_cache_size (start at 4)
table_cache (> 64)
我注意到,当加载 DB 密集型页面时,CPU 使用率飙升至 57%(使用 top)——对我来说,这表明要么存在一些优化不佳的 MySQL 内容,要么绝对需要缓存来加快此设置的速度。
任何帮助将非常感激!
答案1
您是否确切知道 Apache 工作进程挂起的原因是什么?尝试以下操作查看:
mkdir /strace; ps auxw | grep httpd | awk '{print"-p " $2}' | xargs strace -o /strace/strace.log -ff -s4096 -r
在浏览器中加载一些新的(即非本地缓存的)页面,按 CTRL+C 停止 strace,然后根据每次调用所花费的时间对 strace.logs 进行排序:
for i in `ls /strace/*`; do echo $i; cat $i | cut -c11-17 | sort -rn | head; done
查看所有调用时间超过 1.0 秒的 strace.log,并根据上一个命令的输出时间进行搜索。这将指出它们挂起的确切步骤。
您是否安装了类似 CSF 的防火墙?我在 VPS 上也看到了同样的问题。使用 strace 调试 httpd 进程时,gettimeofday 调用最多需要 5 秒或更长时间。奇怪的是,我把问题缩小到了 CSF,它试图过滤 venet0 接口,这是 OpenVZ 或 Virtuozzo 容器中的环回接口。在 /etc/csf/csf.conf 中设置此参数基本上可以解决这个问题:
"ETH_DEVICE_SKIP = "venet0,lo"
我之所以说主要是因为有时候仍然需要等待 500-1000 毫秒才能建立连接,但与 5000+ 相比已经有了很大的改进。
答案2
这是一个出色的入门/演练使用 strace 来解决这类问题。
Maximum possible memory usage: 219.7M (93% of installed RAM)
这肯定是一个低端 VPS 盒子?
- 您可能需要调低 MySQL 设置
- 调整 Apache 以减少 httpd 分叉的数量
- 检查是否可以启用交换
- APC 是否设置为自动缓存操作码?使用与 apc 一起分发的“apc.php”脚本进行检查。
答案3
您必须将网络、apache、mysql 和 php 分开作为延迟的来源。
如果您可以快速从 apache 中提取图像(到第一个字节的时间非常短),那么网络和 apache 通常都没有问题。
如果您可以仅使用 phpinfo() 语句来拉取页面,那么通常 PHP 就可以了(可能需要进行一些调整)。
如果您编写了一个简单的 DB 连接测试并且速度很快,那么该层通常也可以。
最后,拉取应用程序页面。如果速度很慢,则问题出在应用程序处理的内部。虽然调整可能会有所帮助,但这个问题更难解决。
如果不分析应用程序,很难找到问题。NewRelic 等工具可以帮助解决这个问题,但不能根治。
您的应用是否有任何类型的内部调试来显示时间花费在哪里?
答案4
我建议添加渲染时间测量并检查服务器渲染纯 HTML 页面需要多长时间。然后你就知道它是在 CMS 中还是其他地方。我敢打赌这不是你的服务器配置。/maddin