虽然在PHP7更新之后,相对PHP5来说性能提升已经超过了100%+,但其实PHP7依然是可以通过修改配置文件和安装扩展进一步优化性能的。本文以虚拟机集群和ThinkCMF5.1.5(基于ThinkPHP5.1.39开发)框架测试性能。
前言
在上一篇文章《基于nginx实现的负载均衡》 中,我在本地搭建了一个虚拟机集群作为测试机,4台配置皆为2核4线程 3GB内存的服务器。1台作为负载均衡器,2台作为业务服务器,最后1台作为ab压测机器,模拟高并发用户访问。
但ab压测工具无法显示异常率多高(nginx 502之类的),所以本文采用jmeter作为压测工具测试实际效果。
1、安装opcache扩展
PHP7即使不启用Opcache速度也比PHP-5.6启用了Opcache快。
Opcache 的前身是 Optimizer+ ,它是PHP的官方公司 Zend 开发的一款闭源但可以免费使用的 PHP 优化加速组件。
Optimizer+ 将PHP代码预编译生成的脚本文件 Opcode 缓存在共享内存中供以后反复使用,从而避免了从磁盘读取代码再次编译的时间消耗。
同时,它还应用了一些代码优化模式,使得代码执行更快。从而加速PHP的执行。
2、HugePage
全称是”HugePageFy PHP TEXT segment”,默认的内存是以4KB分页的,而虚拟地址和内存地址是需要转换的, 而这个转换是要查表的,CPU为了加速这个查表过程都会内建TLB(Translation Lookaside Buffer), 显而易见如果虚拟页越小,表里的条目数也就越多,而TLB大小是有限的,条目数越多TLB的Cache Miss也就会越高, 所以如果我们能启用大内存页就能间接降低这个TLB Cache Miss。
通过启用这个特性,PHP7会把自身的TEXT段(执行体)”挪“到Huagepage上,之前的测试,我们能稳定的在Wordpress上看到2%~3%的QPS提升。
这个新特性是做在Opcache里的,所以在启用HugePage为PHP加速的前提是,你需要安装Opcache扩展来启用这个特性。
在php.ini配置文件中添加:
opcache.huge_code_pages=1
检查HugePage:
[root@localhost ~]# cat /proc/meminfo | grep Huge AnonHugePages: 378880 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB
可见一个Hugepage的size是2MB, 而当前并没有启用HugePages。
现在让我们配置OS, 分配一些Hugepages:
[root@localhost ~]# sysctl vm.nr_hugepages=128 vm.nr_hugepages = 128
根据你的服务器配置来酌情选择大小,128个*2MB=256MB。
现在让我们再次检查内存信息:
[root@localhost ~]# cat /proc/meminfo | grep Huge AnonHugePages: 387072 kB HugePages_Total: 128 HugePages_Free: 128 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB
可以看到我们分配的128个Hugepages已经就绪了。
然后我们来重启php-fpm:
/etc/init.d/php-fpm-72 reload
现在, 再次检查内存信息:
[root@localhost ~]# cat /proc/meminfo | grep Huge AnonHugePages: 378880 kB HugePages_Total: 128 HugePages_Free: 122 HugePages_Rsvd: 62 HugePages_Surp: 0 Hugepagesize: 2048 kB
可以看到Free减少了,已经启用成功。
3、检查GGC版本号是否大等于4.8
使用新一点的编译器, 推荐GCC 4.8以上, 因为只有GCC 4.8以上PHP才会开启Global Register for opline and execute_data支持, 这个会带来5%左右的性能提升(Wordpres的QPS角度衡量)。
其实GCC 4.8以前的版本也支持, 但是它支持的有Bug, 所以必须是4.8以上的版本才会开启这个特性。
4、测试效果
在2台业务服务器上我同时部署了ThinkCMF5.1.5(基于ThinkPHP5.1.39开发),以 /api/demo/index/index 默认接口作为测试。
cmf.vm20.com 和 cmf.vm30.com这2台为业务服务器,采用PHP7.2,唯一的区别就是cmf.vm20.com安装了opcache、开启了HugePage特性支持。
接口代码:
public function index() { $this->success('请求成功!'); }
接口返回:
{ "code": 1, "msg": "请求成功!", "data": "" }
下面是优化后和优化前的测试对比
4.1、并发线程数量35
持续时间:60秒
CPU使用率:35% / 100%
请求平均返回时间:13ms / 305ms
90% 的请求返回时间小等于:16ms / 431ms
95%的请求返回时间小等于:17ms / 472ms
99%的请求返回时间小等于:31ms / 563ms
请求返回时间最小值:8ms / 122ms
请求返回时间最大值:122ms / 803ms
异常率:0% / 0%
优化后的请求平均返回时间降低至优化前的4.26%
4.2、并发线程数量100
持续时间:60秒
CPU使用率:40% / 100%
请求平均返回时间:16ms / 946ms
90% 的请求返回时间小等于:17ms / 1122ms
95%的请求返回时间小等于:20ms / 1168ms
99%的请求返回时间小等于:179ms / 1255ms
请求返回时间最小值:8ms / 127ms
请求返回时间最大值:372ms / 1399ms
异常率:0% / 0%
优化后的请求平均返回时间降低至优化前的1.69%
4.3、并发线程数量150
持续时间:60秒
CPU使用率:45% / 100%
请求平均返回时间:20ms / 1444ms
90% 的请求返回时间小等于:17ms / 1644ms
95%的请求返回时间小等于:20ms / 1696ms
99%的请求返回时间小等于:324ms / 1799ms
请求返回时间最小值:9ms / 172ms
请求返回时间最大值:535ms / 2025ms
异常率:0% / 0%
优化后的请求平均返回时间降低至优化前的1.38%
4.4、并发线程数量200
持续时间:60秒
CPU使用率:100% / 100%
请求平均返回时间:89ms / 625ms
90% 的请求返回时间小等于:141ms / 2137ms
95%的请求返回时间小等于:160ms / 2200ms
99%的请求返回时间小等于:227ms / 2309ms
请求返回时间最小值:10ms / 0ms
请求返回时间最大值:576ms / 2517ms
异常率:0.20% / 69.17% (nginx 502)
优化后的请求平均返回时间降低至优化前的14.24%
4.5、一些现象和个人理解
以并发200线程的测试举例,开启了opcache后,异常都是在请求峰值到来时出现,后续响应平稳。而没有开启opcache时,随着时间推移,异常率会逐渐升高,比较符合实际情况。
由于opcache的特性,在内容相对固定时避免重复编译,减少 CPU 和内存开销。所以我认为在某种情况下,opcache是一定会增加CPU和内存开销的。如同mysql8.0抛弃了mysql5.7版本的查询缓存这个功能,因为缓存频繁失效反而会引起性能下降。
紧接着,我在接口中写了一些常用的业务代码进行实际测试,随即发现了一个很有意思的现象:当链接数据库读取数据时,若数据库在本地,则安装了opcache带来的性能提升依旧非常明显,虽无本文中示例代码测试结果那么夸张,却仍然可以达到10倍!但若是从远程数据库读取数据,则安装了opcache带来的则是性能的明显下降。我反复测试了几次之后,这个数值大概在110%~140%浮动,反而是负优化。
参考资料
https://www.laruence.com/2015/12/04/3086.html
https://www.laruence.com/2015/10/02/3069.html