PHP7 opcache缓存清理问题

PHP7 opcache缓存清理问题


背景

OPcache经过opcode的缓存和优化,提供更快的PHP执行过程。
业务在php7环境运营时,为了提高请求的性能,在PHP7环境中配置OPcache扩展。
业务在更新代码后,访问业务系统时提示没法找到对应的文件或请求的内容仍是更新前的旧内容,
webserver重启之后,请求访问到的文件就都是最新的了,问题就貌似解决了。php


问题分析

根据现象分析,代码更新后请求找不到新增的文件,尤为是还在请求已有文件更新前的内容,那么可能跟缓存有关系,考虑到跟业务代码逻辑无关,关闭opcache的配置问题就再也不出现,基本上能够定位到问题出在opcache的配置上。web

 

wKiom1l0vIPwRrz0AAA6HvSBfs0987.png-wh_50

wKioL1l0u8Kz-X7GAABTlh-FtMc965.png-wh_50

cat /usr/local/php/etc/subconfig/opcache.inizend_extension=opcache.soopcache.enable=1opcache.revalidate_freq=0opcache.validate_timestamps=0opcache.max_accelerated_files=7963opcache.memory_consumption=192opcache.interned_strings_buffer=16opcache.fast_shutdown=1opcache.enable_cli=1


opcache.enable 启用操做码缓存,默认为“1”

若是禁用此选项,则不会优化和缓存代码。 在运行期使用 ini_set() 函数只能禁用 opcache.enable 设置,不能够启用此设置。 若是在脚本中尝试启用此设置项会产生警告。缓存

opcache.enable_cli  仅针对 CLI 版本的 PHP 启用操做码缓存。bash

 一般被用来测试和调试。服务器

opcache.revalidate_freq=0  检查脚本时间戳是否有更新的周期,以秒为单位。php7

设置为 0 会致使针对每一个请求, OPcache 都会检查脚本更新。ide


opcache.validate_timestamps=0  若是启用,那么 OPcache 会每隔 opcache.revalidate_freq 设定的秒数 检查脚本是否更新。函数

若是禁用此选项,你必须使用 opcache_reset() 或者 opcache_invalidate() 函数来手动重置 OPcache,也能够 经过重启 Web 服务器来使文件系统更改生效。php-fpm


最初的配置是:
opcache.revalidate_freq=60,opcache.validate_timestamps=1
即每60秒检测一次更新字节码缓存,业务代码更新后可能须要60秒之后才能访问到最新的内容,也就出现了最初访问不到新增的内容。oop


代码更新方式

php代码的更新方式有两种,一种是覆盖webserver配置的目录下的文件来更新,一种是每次都部署一个全量包目录,而后软连接到webserver指定的目录。

第一种覆盖更新的方式,若是使用在过时时间后自动清理opcache缓存内容的话,更新操做若是有延迟,就会出现新旧代码文件混合在一块儿的状况。

第二种全量包目录发布后,软连接到webserver指定路径的方式,虽然不会存在新旧文件混合的问题,可是在未自动清理时,即使webserver已经连接到webserver对应目录,业务访问的仍是旧文件。


代码缓存的问题

目前使用rsync同步目录文件的方式是咱们更新代码的主要方式,最初使用每60s定时清理opcache的缓存文件,在60s内更新的文件不会生效,就致使了业务反馈代码更新后访问不到的问题。

使用定时更新代码缓存的问题,还有更新文件较多时,代码文件发布的过程当中缓存发生更新,将会有60s新旧文件的缓存混合存在的问题。

根据相关研究人员推荐,若是采用覆盖更新代码文件时,更新操做完毕后,手动清理缓存比较合适。

opcache.validate_timestamps=0

 即,将oopcache.validate_timestamps设置为0。


配置了opcache.validate_timestamps值为0,必须手动清空Zend OPcache缓存的字节码,才能访问到最新的文件内容。适合在生产环境中设置为0,但在开发环境会带来不便,能够在开发环境中这样配置启用自动验证缓存功能:

opcache.validate_timestamps=1
opcache.revalidate_freq=0

手动清理缓存

除了重启php-fpm的进程能够清理opcache缓存外,
手动清理缓存涉及到的opcache函数主要为:opcache_reset()和opcache_invalidate() 。

boolean opcache_reset ( void )
该函数将重置整个字节码缓存。 
在调用 opcache_reset() 以后,全部的脚本将会从新载入而且在下次被点击的时候从新解析。

须要注意的是,当PHP以PHP-FPM的方式运行的时候,opcache的缓存是没法经过php命令进行清除的,只能经过http或cgi到php-fpm进程的方式来清除缓存。

In some (most?) systems,
PHP's CLI has a separate opcode cache to the one used by the web server ,
or PHP-FPM process,which means running opcache_reset() in the CLI,
won't reset the webserver/fpm opcode cache, and vice-versa.

曲线救国,使用命令行清理php-fpm的opcache缓存:

#!/bin/bashcgi-fcgi -v  > /dev/null 2>&1|| yum --enablerepo=epel install fcgi -y  > /dev/null 2>&1echo '<?php opcache_reset(); echo "ok\n";' > /tmp/php-fpm-opcache-reset.php;
SCRIPT_FILENAME=/tmp/php-fpm-opcache-reset.php \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect 127.0.0.1:9000;
rm -f /tmp/php-fpm-opcache-reset.php;

 


opcache_invalidate  废除指定脚本缓存

boolean opcache_invalidate ( string $script [, boolean $force = FALSE ] )
该函数的做用是使得指定脚本的字节码缓存失效。 若是 force 没有设置或者传入的是 FALSE,那么只有当脚本的修改时间 比对应字节码的时间更新,脚本的缓存才会失效。

参数 

script
缓存须要被做废对应的脚本路径

force
若是该参数设置为TRUE,那么无论是否必要,该脚本的缓存都将被废除。


opcache_invalidate能够针对单个或几个脚本进行来清理缓存。

总结


若是代码发布是全量发布,切换软连接的方式,能够设置opcache.validate_timestamps=1和opcache.validate_timestamps=1来定时自动更新缓存。若是代码发布是覆盖更新旧目录,则能够重启php-fpm及在脚本中或代码文件中使用opcache_reset函数来清理全部缓存。若是能够获取到更新的代码文件列表,则可使用opcache_invalidate函数来清理代码,同时也能够避免影响到其余业务的缓存。

相关文章
相关标签/搜索