深入了解PHP8 opcache JIT(即时编译)功能
opcache常见的配置
以下为默认值,阅读opcache的配置可以帮助你了解opcache的行为。
# 启用操作码缓存,默认开启
opcache.enable=1
# 仅针对 CLI 版本的 PHP 启用操作码缓存。 通常被用来测试和调试。
opcache.enable_cli=0
# OPcache 的共享内存大小,以兆字节为单位。
opcache.memory_consumption = 128
# 用来存储预留字符串的内存大小,以兆字节为单位
opcache.interned_strings_buffer=8
# OPcache 哈希表中可存储的脚本文件数量上限。 真实的取值是在质数集合 { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987 } 中找到的第一个大于等于设置值的质数。 设置值取值范围最小值是 200,最大值为1000000。
opcache.max_accelerated_files=10000
# 浪费内存的上限,以百分比计。 如果达到此上限,那么 OPcache 将产生重新启动续发事件。
opcache.max_wasted_percentage=5
# 如果启用,OPcache 将在哈希表的脚本键之后附加改脚本的工作目录, 以避免同名脚本冲突的问题。 禁用此选项可以提高性能,但是可能会导致应用崩溃。
opcache.use_cwd =1
# 布尔值,OPcache 会每隔 opcache.revalidate_freq 设定的秒数 检查脚本是否更新。 如果禁用此选项,你必须使用 opcache_reset() 或者 opcache_invalidate() 函数来手动重置 OPcache,也可以 通过重启 Web 服务器来使文件系统更改生效。
opcache.validate_timestamps=1
# 检查脚本时间戳是否有更新的周期,以秒为单位。 设置为 0 会导致针对每次请求OPcache 都会检查脚本是否更新。如果 opcache.validate_timestamps 配置指令设置为禁用,那么此设置项将会被忽略。
opcache.revalidate_freq =2
# 如果禁用此选项,在同一个 include_path 已存在的缓存文件会被重用。 因此,将无法找到不在包含路径下的同名文件。
opcache.revalidate_path = 0
# 如果禁用,脚本文件中的注释内容将不会被包含到操作码缓存文件, 这样可以有效减小优化后的文件体积。 禁用此配置指令可能会导致一些依赖注释或注解的 应用或框架无法正常工作, 比如: Doctrine, Zend Framework 2 以及 PHPUnit。
opcache.save_comments =1
# 如果禁用,则即使文件中包含注释,也不会加载这些注释内容。 本选项可以和 opcache.save_comments 一起使用,以实现按需加载注释内容。
opcache.load_comments =1
# 如果启用,则会使用快速停止续发事件。 所谓快速停止续发事件是指依赖 Zend 引擎的内存管理模块 一次释放全部请求变量的内存,而不是依次释放每一个已分配的内存块。从 PHP 7.2.0 开始,此配置指令被移除。 快速停止的续发事件的处理已经集成到 PHP 中, 只要有可能,PHP 会自动处理这些续发事件。
opcache.fast_shutdown =0
# 如果启用,则在调用函数 file_exists(), is_file() 以及 is_readable() 的时候, 都会检查操作码缓存,无论文件是否已经被缓存。 如果应用中包含检查 PHP 脚本存在性和可读性的功能,这样可以提升性能。 但是如果禁用了 opcache.validate_timestamps 选项, 可能存在返回过时数据的风险。
opcache.enable_file_override =0
需要注意:
1、enable_cli:
如果项目框架里有PHP_SAPI === 'cli'类似的判断,请不要开启enable_cli=true。因为开启这个并且设置了file_cache,php-fpm和cli会共用file_cache,如果php-fpm先执行了含有PHP_SAPI === 'cli'的脚本,再用cli方式执行该脚本,那么此时PHP_SAPI的返回并不是’cli’,因为他之前在以fpm模式执行时已经被opcache缓存。
2、opcache.validate_timestamps 和 opcache.revalidate_freq:
每隔若干秒检查1次某个请求到的php脚本是否修改以更新opcache缓存。每次检测都是一次 stat 系统调用,众所周知,系统调用会消耗一些 CPU 时间,并且 stat 系统调用会进行磁盘 I/O,更加浪费性能。
在生产环境中,如果某一次需求迭代更新了大量代码,并且发布到正式环境,可能会出现这样的情况:文件A 的opcache更新了,但是文件B的还没更新,A include B,由于B的opcache没有更新导致报错。
如何解决这个问题:
a. 将opcache.revalidate_freq置为0;每次请求都检查要访问的脚本是否更新。
b. 将 validate_timestamps 置为0,这样即使文件更新,用户访问到的也是缓存中的旧脚本内容。当代码发布到正式环境后,通过http方式手动调用一个含有 opcache_invalidate() 的php脚本重新编译上线的脚本。
c. 将 validate_timestamps 置为0,当新代码发布到正式环境后,平滑重启php-fpm,并运行一个自定义的预执行php脚本将项目中所有php脚本进行 opcache_compile_file()操作,然后才开始接收用户请求。
d. composer安装cachetool清除opcache。
3、max_wasted_percentage:
对于浪费内存我是这样理解的,如果一个文件更新了,opcache中该脚本的缓存就是一个过期缓存,该脚本在opcache中占用的内存就是所谓的“浪费内存”。
如果设置了revalidate_freq和validate_timestamps,并且一次性更新的文件内容和数量太多,就会产生较多的current wasted memory。如果超过了 max_wasted_percentage 的限定值,就会导致opcache被动清空,重新编译和缓存脚本文件。如果在并发量较大的情况下,这会导致系统负载飙升。
如果要避免opcache被动清空,需要做好以下2件事:
a. 配置足够的opcache.memory_consumption和opcache.max_accelerated_files;
b. 合理的代码上线发布策略;
4、memory_consumption:
不合理的发布策略可能会导致实际的脚本缓存内容超过opcache的memory_consumption从而导致opcache内存溢出。
尤其是在使用软链接的发布策略时,具体是指nginx配置项目根目录是一个目录L(是个软链接),它真实指向的是目录A。而代码发布后,新迭代的更新代码不是同步到目录A,而是创建一个新项目目录B,B的代码是最新代码。之后通过shell脚本将软链接目录L指向目录B,于是用户请求就会全部走到目录B。
由于opcache缓存脚本文件是针对文件的真实目录,因此用户请求B的脚本文件时就会将目录B下的脚本也缓存到opcache中。这么一来,opcache中缓存的文件既包含A目录的文件,又包含B目录的文件,导致内存溢出,应用崩溃。
要避免这种情况,要么就不使用软链接的发布策略,要么是设置原先2倍大的memory_consumption。
jit:
function与tracingJIT配置都利用CPU指令集和CPU寄存器分配来充分利用 CPU 功能(C = 1,R = 2)。
opcache.jit=function
function 是C = 1,R = 2,T = 0,O = 5的别名。
与function配置的区别在于,它渴望尽快编译脚本,然后编译整个脚本。这是一种更加冒昧和大胆的方法,类似于使用PHP 7.4中的预加载功能将PHP文件预加载到Opcache。
opcache.jit=tracing
tracing 是C = 1,R = 2,T = 5,O = 4的别名。
启用tracing后,JIT可以更精细,并选择函数中的代码段进行编译。理想的候选对象是循环结构和经常调用的函数。
这是默认配置,可以在性能优势和编译开销之间提供更多的平衡。
https://blog.csdn.net/weixin_39521935/article/details/114464518

浙公网安备 33010602011771号