乐趣区

modernPHP专题13ZendOpcache字节码缓存

概述

字节码缓存不是 PHP 的新特性,有很多独立的扩展可以实现,比如 APC、eAccelerator 和 Xache 等,但是截至目前这些扩展都没有集成到 PHP 内核,从 PHP 5.5.0 开始,PHP 内置了字节码缓存功能,名为 Zend Opcache。

开始之前,我们先来看看什么是字节码缓存,以及字节码缓存的作用是什么。

众所周知,PHP 是解释型语言,构建在 Zend 虚拟机之上,PHP 解释器在执行 PHP 脚本时会解析 PHP 脚本代码,把 PHP 代码编译成一系列 Zend 操作码(opcode,由于每个操作码都是一个字节长,所以又叫字节码,字节码可以直接被 Zend 虚拟机执行),然后执行字节码。每次请求 PHP 文件都是这样,这会消耗很多资源,如果每次 HTTP 请求都必须不断解析、编译和执行 PHP 脚本,消耗的资源更多。如果 PHP 源码不变,相应的字节码也不会变化,显然没有必要每次都重新生成 Opcode,结合在 Web 应用中无处不在的缓存机制,我们可以把首次生成的 Opcode 缓存起来,这样下次直接从缓存取,岂不是很快?下面是启用 Opcode 缓存之前和之后的流程图:

字节码缓存能存储预先编译好的 PHP 字节码,这样,下次请求 PHP 脚本时,PHP 解释器不用每次读取、解析和编译 PHP 代码,直接从内存中读取预先编译好的字节码,然后立即执行,这样能省很多时间,极大提升应用的性能。

启用 Zend Opcache

注:如果使用 Windows 开发环境,或者使用 brew 或 apt-get 等命令安装的 PHP 可以略过编译步骤。

默认情况下,Zend Opcache 没有开启,需要我们在编译时使用 --enable-opcache 指定启用 Zend Opcache。

编译好 PHP 后还需要在 php.ini 中指定 Opcache 扩展路径:

zend_extension=/path/to/opcache.so

一般而言 PHP 编译成功后会显示 Zend Opcache 扩展路径,但如果想不起来,可以使用如下命令找到 PHP 扩展所在目录:

php -ini | grep extensions

[info] 注:如果你使用 Xdebug,需要在 php.ini 中先加载 Zend Opcache,再加载 Xdebug。

重启后,查看 phpinfo

php -info | grep Opcache

配置 Zend Opcache

启用 Zend Opcache 后还需要在 php.ini 中配置 Zend Opcache,下面是一份配置示例作为参考:

opcache.validate_timestamps=1    // 生产环境中配置为 0
opcache.revalidate_freq=0    // 检查脚本时间戳是否有更新时间
opcache.memory_consumption=64    //Opcache 的共享内存大小,以 M 为单位
opcache.interned_strings_buffer=16    // 用来存储临时字符串的内存大小,以 M 为单位
opcache.max_accelerated_files=4000    //Opcache 哈希表可以存储的脚本文件数量上限
opcache.fast_shutdown=1         // 使用快速停止续发事件

官网配置参考

使用 Zend Opcache

Zend Opcache 使用起来很简单,因为启用之后它会自动运行,Zend Opcache 会自动在内存中缓存预先编译好的 PHP 字节码,如果缓存了某个文件的字节码,就执行对应的字节码。

如果 php.ini 中配置了 opcache.validate_timestamps 值为 0,需要小心,因为 Zend Opcache 将不能觉察 PHP 脚本的变化,必须手动清空 Zend OPcache 缓存的字节码,才能让它发现 PHP 文件的变动。这个配置适合在生产环境中设置为 0,但在开发环境会带来不便,我们可以在开发环境中这样配置启用自动验证缓存功能:

opcache.enable=1 # 启用操作码缓存, 默认为“1”, 如果禁用此选项,则不会优化和缓存代码。opcache.revalidate_freq=0 #  检查脚本时间戳是否有更新的周期,以秒为单位。设置为 0 会导致针对每个请求,OPcache 都会检查脚本更新。opcache.validate_timestamps=1 # 如果启用,那么 OPcache 会每隔 opcache.revalidate_freq 设定的秒数 检查脚本是否更新。

手动清理缓存

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

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

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

退出移动版