[PHP]细说Opcache

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。

留下评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注