MENU

PHP开启Opcache后的一些坑

October 30, 2019 • PHP

众所周知,PHP5.5以后官方自带了一个组件叫Zend Opcache,具体可以参看官方文档。开启此扩展后可以提高PHP的执行效率,具体提升多大我会在最后给一个简简单单的测试,提供给大家参考。

Opcache的执行流程大致如下,

E390.png

Opcache 的目地是避免重复编译,减少 CPU 和内存开销。

由于这篇文章的本意是想记录以及备注一下开启opcache后出现的一些问题,所以这篇文章不会记录如何安装opcache以及如何配置,推荐这篇文章大家参考一下就可以了,配置说的都很明确了。

正文

在配置中有2个配置很重要,需要重点关注

opcache.validate_timestamps=0;
opcache.revalidate_freq=60;

validate_timestamps用于验证是否要重新生成缓存脚本, 如果设置为 0(性能最佳),需要手动在每次 PHP 代码更改后手动清除 OPcache。 如果此值为0,那么revalidate_freq将失去作用。

revalidate_freq用于控制opcache多久生成一次缓存字节码,默认60s。所以一般我们在开发环境中将上面两个值配置为

opcache.validate_timestamps=1;
opcache.revalidate_freq=1;

或者干脆直接关闭opcache。

上面提到了,如果将validate_timestamps配置为0以后,我们每次部署PHP的时候默认是不会自动生成缓存。这句话其是是不严谨的,因为部署PHP的时候有两种方式,一种是直接覆盖就文件,另一种是使用CI发布会自动生成新的部署目录,并通过软连接的方式指定到web目录

如果是第一种部署方式的话,opcache确实不会自动生成缓存,因为opcache通过文件的真实路径进行缓存,如果文件存在就不会再次缓存,也就导致了部署后线上并没有看到新的功能代码。

而另一种方式的确会主动生成缓存,因为上面说了,opcache是通过文件的真实路径进行缓存的,这就导致了每次部署都会生成缓存字节码,那么就导致了旧的缓存没有被清理,那么迟早有一天会撑爆内存。

所以,在部署代码的时候如何清理opcahce生成的缓存就成为了关键所在。

解决方案

通过搜索实践发现了几种方式,分别为

  1. 平滑重启php-fpm
  2. 通过opcache_reset()函数
  3. 第三方库

平滑重启的方式就类似下面这样,通过部署钩子实现

cd /www/myproject
sudo -u www git reset --hard
sudo -u www git pull origin master
sudo -u root /etc/init.d/php-fpm-73 reload

使用opcache_reset()函数需要注意的问题就是在cli命令行下执行此函数并不能清理php-fpm下生成的缓存字节码,所以可以通过一种曲线救国的方式

curl http://example.com/op.php

这个op.php文件里面就专门执行opcache_reset()函数,但是这种方式总感觉有点怪怪的。

通过第三方库(推荐)的方式,大佬推荐cachetool

.

.

.

简单测试

下面的几次简单测试是在我们的预生产环境上测试的,使用了微擎框架,而并不是简单的打印helloworld方式。

未开启opcache情况

ECqU.png

ET8A.png

Ecch.png

开启opcache情况

Ef46.png

EuoH.png

EBrp.png

从上面的截图中就可以看出,未开启opcache的情况下,基本稳定在70-90左右,但是开启opcache后,由于第一次请求需要生成缓存字节码所以耗时有点久,达到了140ms,但是第二次以及后面的请求都稳定在50ms左右,所以可以看出提升性能还是很明显的。

参考资料

https://xueyuanjun.com/post/7522.html
https://juejin.im/entry/5aec2313f265da0b9526f899

Last Modified: November 10, 2019