记一次接口性能测试引发的Linux+Apache+PHP调优过程
一. 概述
项目验收阶段, 需要对部分PHP接口进行性能测试, 性能测试环境架构为如下所示:
image.png
使用ab压力测试, 2000请求, 500并发, 发现性能瓶颈在Apache和PHP之间, 对底层原理不了解, 调优过程曲折迷离, 将其记录下来, 日后再仔细琢磨!
- PHP版本: 7.0.4
- Apache版本: 2.4.18
- MySQL版本: 5.7.11
二. 优化Linux内核参数
vim /etc/sysctl.conf
, 在末尾加入如下内容
net.core.somaxconn = 2048
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 20000
net.ipv4.ip_local_port_range = 5000 65000
net.ipv4.tcp_rmem = 4096 4096 16777216
net.ipv4.tcp_wmem = 4096 4096 16777216
net.ipv4.tcp_mem = 786432 2097152 3145728
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_max_orphans = 131072
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_syncookies = 1
fs.nr_open = 1000000
执行sysctl -p
生效
需要根据自己机器配置做相应的调节
参考博客如下
https://blog.csdn.net/aresiii/article/details/48374987
https://blog.csdn.net/leonpengweicn/article/details/50477530
https://blog.csdn.net/tallercc/article/details/52823075
三. 优化Apache
1. Apache工作模式调优,
- 查看Apache工作模式
/usr/local/apache2/bin/apachectl -l
core.c
mod_so.c
http_core.c
event.c(event模式)
- 在主配置文件里开启mpm
vim /usr/local/apache2/conf/httpd.conf
Include conf/extra/httpd-mpm.conf
- 根据各自的不同的工作修改mpm中对应的配置
vim /usr/local/apache2/conf/extra/httpd-mpm.conf
参考博客:
https://blog.csdn.net/STFPHP/article/details/52954303
http://blog.jobbole.com/91920/
http://www.cnblogs.com/fazo/p/5588644.html
2. Apache 重写机制调优
将index.php重写规则写到Apache配置文件里, 而不是使用.htaccess文件, 禁用.htacess文件读取, 配置如下
DocumentRoot "/home/uar/uar/codes/web/uar-web/public"
<Directory "/home/uar/uar/codes/web/uar-web/public">
#Options Indexes FollowSymLinks
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# AllowOverride FileInfo AuthConfig Limit
# 不查找.htaccess文件
AllowOverride None
# 重写需要配置该条
Options FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
#
# Controls who can get stuff from this server.
#
Require all granted
</Directory>
3. 开启KeepAlive On长连接
Include conf/extra/httpd-default.conf
根据需要调节配置文件
四. PHP调优
本次压测系统使用Laravel5.2编写, PHP版本为7.0.4
强烈推荐看<strong>鸟哥博客</strong>:
http://www.laruence.com/2015/12/04/3086.html
https://blog.csdn.net/qq_36031499/article/details/53911734
1. 开启opcache(性能提高了5倍, 强烈推荐)
在php.ini最后加入如下配置, 开启opcache
zend_extension="opcache.so"
; 开关打开
opcache.enable=1
; ; 设置共享内存大小, 单位为:Mb
opcache.memory_consumption=2048
; ;如果启用,那么 OPcache 会每隔 opcache.revalidate_freq 设定的秒数 检查脚本是否更新。 如果禁用此选项,你必须使用 opcache_reset() 或者 opcache_invalidate() 函数来手动重置 OPcache,也可以 通过重启 Web 服务器来使文件系统更改生效。
opcache.validate_timestamps=1
;opcache.enable_cli=0
;求得uar项目PHP文件为35846, opcache.max_accelerated_files应该比项目文件数大
opcache.max_accelerated_files=50000
opcache.interned_strings_buffer=64
opcache.fast_shutdown=1
参考博客: https://www.abcdocker.com/abcdocker/2151
opcache文档: https://www.scalingphpbook.com/blog/2014/02/14/best-zend-opcache-settings.html
2. Laravel层面的优化
- 由于是接口性能测试, 去掉没有必要的中间件
- 关掉debug
- 将无用的日志打印去掉
- 生成配置文件缓存
.....
ab相关博客
https://blog.linuxeye.cn/124.html
https://blog.csdn.net/officercat/article/details/49891809
https://www.cnblogs.com/hedy-x/p/8065802.html
五. MySQL相关调优文档
https://www.cnblogs.com/angryprogrammer/p/6667741.html
https://segmentfault.com/a/1190000011687570
https://segmentfault.com/a/1190000014108616
https://blog.csdn.net/linuxlsq/article/details/52606255
附录: 关于opcache的配置说明
参考博客: https://gywbd.github.io/posts/2016/1/best-config-for-zend-opcache.html
zend opcache的最佳设置
在网上无意中看到的一篇文章,这哥们非常简洁地谈论了zend opcache的最佳设置,他说他为此花了大量的时间探索zend opcache的每个设置选项的细节,甚至是阅读它的源代码,并且在自己的项目中实践(一个每天有117 million的HTTP请求的应用)。个人觉得这种文章相当有指导意义,所以特地把它的设置方式摘译如下(格式有些修改):
opcache.revalidate_freq
这个选项用于设置缓存的过期时间(单位是秒),当这个时间达到后,opcache会检查你的代码是否改变,如果改变了PHP会重新编译它,生成新的opcode,并且更新缓存。值为“0”表示每次请求都会检查你的PHP代码是否更新(这意味着会增加很多次stat系统调用,译注:stat系统调用是读取文件的状态,这里主要是获取最近修改时间,这个系统调用会发生磁盘I/O,所以必然会消耗一些CPU时间,当然系统调用本身也会消耗一些CPU时间)。可以在开发环境中把它设置为0,生产环境下不用管,因为下面会介绍另外一个设置选项。
opcache.validate_timestamps
当这个选项被启用(设置为1),PHP会在opcache.revalidate_freq设置的时间到达后检测文件的时间戳(timestamp)。
如果这个选项被禁用(设置为0),opcache.revalidate_freq会被忽略,PHP文件永远不会被检查。这意味着如果你修改了你的代码,然后你把它更新到服务器上,再在浏览器上请求更新的代码对应的功能,你会看不到更新的效果,你必须得重新加载你的PHP(使用kill -SIGUSR2强制重新加载)。
这个设定是不是有些蛋疼,但是我强烈建议你在生产环境中使用,why?因为当你在更新服务器代码的时候,如果代码较多,更新操作是有些延迟的,在这个延迟的过程中必然出现老代码和新代码混合的情况,这个时候对用户请求的处理必然存在不确定性。
opcache.max_accelerated_files
这个选项用于控制内存中最多可以缓存多少个PHP文件。这个选项必须得设置得足够大,大于你的项目中的所有PHP文件的总和。我的代码库大概有6000个PHP文件,所以我把这个值设置为一个素数7963(译注:不知道这哥们为什么要设置这个数,7963也不是大于6000的最小素数)。
你可以运行“find . -type f -print | grep php | wc -l”这个命令来快速计算你的代码库中的PHP文件数。
opcache.memory_consumption
这个选项的默认值为64MB,我把它设置为192MB,因为我的代码很大。你可以通过调用opcachegetstatus()来获取opcache使用的内存的总量,如果这个值很大,你可以把这个选项设置得更大一些。
opcache.interned_strings_buffer
这是一个很有用的选项,但是似乎完全没有文档说明。PHP使用了一种叫做字符串驻留(string interning)的技术来改善性能。例如,如果你在代码中使用了1000次字符串“foobar”,在PHP内部只会在第一使用这个字符串的时候分配一个不可变的内存区域来存储这个字符串,其他的999次使用都会直接指向这个内存区域。这个选项则会把这个特性提升一个层次——默认情况下这个不可变的内存区域只会存在于单个php-fpm的进程中,如果设置了这个选项,那么它将会在所有的php-fpm进程中共享。在比较大的应用中,这可以非常有效地节约内存,提高应用的性能。
这个选项的值是以兆字节(megabytes)作为单位,如果把它设置为16,则表示16MB,默认是4MB,这是一个比较低的值。
opcache.fast_shutdown
另外一个很有用但也没有文档说明的选项。从字面上理解就是“允许更快速关闭”。它的作用是在单个请求结束时提供一种更快速的机制来调用代码中的析构器,从而加快PHP的响应速度和PHP进程资源的回收速度,这样应用程序可以更快速地响应下一个请求。把它设置为1就可以使用这个机制了。