解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题


Posted in PHP onAugust 24, 2020

问题背景

通过启用Opcache的缓存优化,将PHP代码预编译为Opcode缓存到共享内存中供进程反复调用,从而减少了重复从磁盘解析PHP代码的时间消耗,显著的提高了PHP性能,提升了业务性能的调用,但是也引发了一些问题,就是我们每次更新了相应的PHP代码后,web server 无法即时加载到更新后的代码。

解决方案

(一)、设置Opcache脚本验证时间

可以通过更改 Opcache 以下两个配置选项来调整代码重载时间

opcache.revalidate_freq=0 检查脚本时间戳是否有更新的周期,以秒为单位。(如果设置为 0 会导致针对每个请求, OPcache 都会检查脚本更新)

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

PS:在实际生产环境中,为了尽可能达到最优性能,尽量不开启文件更新验证,因为每次验证都会重新预编译PHP代码到共享内存中。

(二)、重启 | 重载 php-fpm 进程

每次重启或重启 php-fpm 进程便会重新解析PHP脚本文件,但是重启 fpm 进程可能会导致请求中断,从而导致写入脏数据 或者 造成事务回滚等一系列异常。

重载相对于重启则平顺很多,不会导致用户请求直接中断,相对来说风险低很多,但是php-fpm 收到reload信号,便会向所有子进程发送SIGGUIT信号,同时注册一个定时器,在规定的时间之内子进程没有退出,接着在发送SIGTERM信号,结束子进程。如果在一秒之内子进程还是没结束 直接发送SIGKILL 强制杀死。

重启php-fpm

service php-fpm restart

重载php-fpm

services php-fpm reload

或 kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

(三)、手动清理缓存

除了上面的两种方式,还有更为稳妥一点的缓存清理,我们可以通过opcache_reset()和opcache_invalidate() 函数来刷新Opcache缓存。

opcache_reset() - 重置整个Opcode缓存,所有的PHP脚本将会被重新解析再预编译为Opcode。

opcache_invalidate() - 清除指定脚本缓存,可以传递两个参数,一个是刷新文件路径,一个是force字段, 如果 force 没有设置或者传入的是 FALSE,那么只有当脚本的修改时间 比对应Opcode的时间更新时,脚本的缓存才会失效。

需要注意的是,当PHP以PHP-FPM的方式运行的时候,opcache的缓存是无法通过php命令进行清除的,只能通过http或cgi到php-fpm进程的方式来清除缓存,我们可以编写一个对外接口,来达到清理缓存的目的。

相关实现如下(框架:laravel):

Route::any('cache-reset', function () {
  //重置整个Opcode缓存
  dd(opcache_reset());
});

Route::any('cache-update', function () {
  //清除掉最近一次更新文件的缓存
  exec('git diff --name-only HEAD~ HEAD', $output);
  foreach ($output as $file) {
    $path = base_path($file);
    opcache_invalidate($path, true);
  }
  dd('刷新完成');
});

总结

通过上面的三种策略,可以实现 Opcache 缓存更新的目的,但是在流量高峰期或者大流量的服务端,每次更新缓存都是一件非常损耗资源的事情,Opcache在重建缓存时,也不会禁止其他进程读取,因此就会造成反复新建缓存,因此想要达到最佳的性能调配:

  • 最好不要在高峰期清理缓存
  • 高峰期不要频繁的更新代码,清理缓存,会造成重复新建缓存
  • 如果需要更新,可以尝试削弱服务端权重,实现逐个更新的目的。
  • 如果需要强制更新,尽量选择手动清除缓存的方式,来重建Opcache缓存,使代价最小化。

以上就是解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题的详细内容,更多关于PHP Opcache 缓存刷新、代码重载的资料请关注三水点靠木其它相关文章!

PHP 相关文章推荐
php标签云的实现代码
Oct 10 PHP
spl_autoload_register与autoload的区别详解
Jun 03 PHP
session在php5.3中的变化 session_is_registered() is deprecated in
Nov 12 PHP
php中\r \r\n \t的区别示例介绍
Feb 08 PHP
PHP函数eval()介绍和使用示例
Aug 20 PHP
php图片处理函数获取类型及扩展名实例
Nov 19 PHP
解读PHP中的垃圾回收机制
Aug 10 PHP
简单的pgsql pdo php操作类实现代码
Aug 25 PHP
thinkPHP框架中执行原生SQL语句的方法
Oct 25 PHP
php实现将数据做成json的格式给前端使用
Aug 21 PHP
使用php的mail()函数实现发送邮件功能
Jun 03 PHP
解决Laravel使用验证时跳转到首页的问题
Nov 17 PHP
WordPress免插件实现面包屑导航的示例代码
Aug 20 #PHP
VSCode+PHPstudy配置PHP开发环境的步骤详解
Aug 20 #PHP
Laravel相关的一些故障解决
Aug 19 #PHP
聊聊 PHP 8 新特性 Attributes
Aug 19 #PHP
php提高脚本性能的4个技巧
Aug 18 #PHP
php判断IP地址是否在多个IP段内
Aug 18 #PHP
PHP 8新特性简介
Aug 18 #PHP
You might like
PHP抽象类 介绍
2012/06/13 PHP
简单的php文件上传(实例)
2013/10/27 PHP
PHP实现获取某个月份周次信息的方法
2015/08/11 PHP
Centos PHP 扩展Xchche的安装教程
2016/07/09 PHP
PHP与SQL语句写一句话木马总结
2019/10/11 PHP
dwr spring的集成实现代码
2009/03/22 Javascript
js闭包实例汇总
2014/11/09 Javascript
JavaScript中检查对象property的存在性方法介绍
2014/12/30 Javascript
EasyUI学习之Combobox下拉列表(1)
2016/12/29 Javascript
微信小程序中的swiper组件详解
2017/04/14 Javascript
js中less常用的方法小结
2017/08/09 Javascript
mpvue中配置vuex并持久化到本地Storage图文教程解析
2018/03/15 Javascript
简单了解Ajax表单序列化的实现方法
2019/06/14 Javascript
Vue Extends 扩展选项用法完整实例
2019/09/17 Javascript
微信小程序wx.getUserInfo授权获取用户信息(头像、昵称)的实现
2020/08/19 Javascript
[45:52]2018DOTA2亚洲邀请赛 4.1小组赛 A组加赛 LGD vs Liquid
2018/04/02 DOTA
[22:07]DOTA2-DPC中国联赛 正赛 iG vs Magma 选手采访
2021/03/11 DOTA
Python 的描述符 descriptor详解
2016/02/27 Python
利用python操作SQLite数据库及文件操作详解
2017/09/22 Python
Python通过调用mysql存储过程实现更新数据功能示例
2018/04/03 Python
利用python修改json文件的value方法
2018/12/31 Python
python 使用plt画图,去除图片四周的白边方法
2019/07/09 Python
使用Python实现图像标记点的坐标输出功能
2019/08/14 Python
python 生成器和迭代器的原理解析
2019/10/12 Python
Pandas对DataFrame单列/多列进行运算(map, apply, transform, agg)
2020/06/14 Python
解决html5中的video标签ios系统中无法播放使用的问题
2020/08/10 HTML / CSS
尤为Wconcept中国官网:韩国设计师品牌服饰
2019/01/10 全球购物
Unix如何在一行中运行多个命令
2015/05/29 面试题
计算机网络毕业生自荐信
2013/10/01 职场文书
小学毕业感言150字
2014/02/05 职场文书
党的群众路线教育实践活动心得体会900字
2014/03/07 职场文书
员工合理化建议书
2014/05/19 职场文书
消防标语大全
2014/06/07 职场文书
Angular CLI发布路径的配置项浅析
2021/03/29 Javascript
解决thinkphp6(tp6)在状态码500下不报错,或者显示错误“Malformed UTF-8 characters”的问题
2021/04/01 PHP
关于redisson缓存序列化几枚大坑说明
2021/08/04 Redis