Opcache原理
从Operate Code开始
- 当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码。
- 流程:读取文件 => 扫描词典和表达式 => 解析文件 => 创建Opcode
- 生产环境PHP的两种运行模式
- PHP执行流程:
- module_init => request_init => php_execute_script(Opcode) => request_shutdown => module_shutdown
- PHP-FPM:PHP-FPM是对于FastCGI 协议的具体实现。FastCGI是Web服务器和处理程序之间通信的一种协议, 是CGI的一种改进方案,FastCGI像是一个常驻(long-lived)型的CGI, 它可以一直执行,在请求到达时不会花费时间去fork一个进程来处理。
- 生命周期:一直在request_init到request_shutdown之间重复执行,Opcache在服务启动时一直生效。
- PHP-CLI:PHP在命令行下运行的接口。
- 生命周期:从module_init直接执行到module_shutdown,执行一次,进程结束Opcache失效。
- Opcache在一个生命周期内缓存内容
- 存储Opcode(避免重复编译,减少CPU和内存开销)
- 存储Interned String(php请求生命周期中不释放的String:变量名、类名、方法名、字符串、注释等)
- Opcache的一些其他原则
- 基于先到先得的原则进行缓存,不使用诸如最近最少使用(LRU)之类的驱逐策略。
- 每当达到最大内存消耗或最大加速文件时,Opcache 就会尝试重新启动缓存。
- 如果 Opcache 中浪费的内存没有超过 max_wasted_percentage,则 Opcache 将不会重启,对于新的请求Opcache失效。
- wasted memory:被改变的php脚本占用的内存。
- 理想状况永远为0。
- 改变的php脚本在opcache中生成一个新条目,但旧条目不会被释放。
- 手动清空wasted memory只能重启PHP-FPM或使用PHP函数opcache_reset()。
- Opcache对性能的影响。
- 如果性能瓶颈不在于CPU和内存,而在于I/O操作,比如数据库查询带来的磁盘I/O开销,那么Opcode cache的性能提升是非常有限的。
- 刚启动或缓存被清空时,如果服务器流量大可能会导致 thundering herd problem 或缓存猛击,许多请求同时生成相同的缓存条目。
- PHP函数opcache_get_status 统计内存消耗信息 单位Byte”memory_usage”: {
“used_memory”: 91647160,
“free_memory”: 440537232,
“wasted_memory”: 4686520,
“current_wasted_percentage”: 0.8729323744773865
}
计算 memory_consumption 的公式为: ( used_memory + free_memory + wasted_memory) / 1048576
Opcache配置
配置示例
zend_extension=opcache.so # 添加扩展
opcache.enable=1 # 是否开启opcache
opcache.enable_cli=0 # 是否在cli下开启opcache
opcache.max_wasted_percentage=5 # 浪费内存上限 单位百分比 超出后清空全部缓存
opcache.memory_consumption=512 # 共享内存大小 单位是MB
opcache.interned_strings_buffer=128 # 存储字符串 单位是MB 原理是内存驻留
opcache.max_accelerated_files=100000 # 哈希表中存储文件数量上限 最小200 最大1000000
opcache.validate_timestamps=0 # 是否根据时间戳检查文件变更 0 revalidate_freq无效
opcache.revalidate_freq=0 # 根据时间戳检查文件变更的周期 单位秒 0不检查
opcache.save_comments=0 # 缓存里是否加载注释 如框架依赖注释无法正常运行
opcache.fast_shutdown=1 # 快速停止续发事件 一次释放请求变量全部内存 php7.2后无效
opcache.file_cache=/tmp # 启用文件缓存 设置缓存路径
生产环境部署
配置文件
- 仅在PHP-FPM模式下启用Opcache。
- Opcache不设置过期时间。
- php.ini中配置preload(用于缓存预热)
- opcache.preload=/var/www/wonjia/preload.php
- 注意:一台服务器上有多个php项目时,可能会引起未知错误
运维
- 避免在流量高峰期发布代码。
- 发版时清空opcache,二选一,倾向于重启PHP-FPM。
- 调用每台服务器的opcache_clear.php脚本,无法预热。
- 重启每台服务器的PHP-FPM。
- jenkins增加功能(每台服务器)监控opcache状态、重启opcache、重启PHP-FPM。
代码
- api和pc都增加preload.php脚本,require_once文件使用绝对路径。
- api增加opcache_clear.php脚本,用于清空opcache。
- api增加opcache_status.php脚本,用于监控opcache。