PHP OPcache
什么是 PHP OPcache?
OPcache(操作码缓存)是 PHP 内置的一个字节码缓存引擎。它的主要目的是通过将预编译的脚本字节码存储在共享内存中,来显著提高 PHP 的性能。这消除了 PHP 在每次请求时都需要加载、解析和编译脚本的需要。
OPcache 解决的问题
在没有 OPcache 的情况下,每次请求 PHP 脚本时都会发生以下步骤:
- 读取: Zend 引擎从文件中读取 PHP 源代码。
- 解析和编译: 它解析代码,检查语法错误,并将其编译成一种称为操作码 的中间格式。
- 执行: 然后引擎执行该操作码。
步骤 1 和 2 对每个请求都会重复执行,这在流量高的站点上是一个巨大的开销。
使用 OPcache 后:
- 在脚本首次被请求后,编译好的操作码会被存储在共享内存(即 OPcache)中。
- 对于所有后续的请求,引擎可以跳过读取、解析和编译步骤,直接执行内存中的操作码。
这会带来:
- 更快的响应时间
- 更低的 CPU 使用率
- 更高的吞吐量(每秒可服务更多请求)
关键配置指令
OPcache 在 php.ini 文件中进行配置。以下是一些最重要的设置:
1. 启用 OPcache
; 启用 Zend OPcache
opcache.enable=1
; 为 CLI 版本的 PHP 启用 OPcache(对 Composer 等一些工具有用)
; opcache.enable_cli=02. 内存设置
; 用于存储预编译 PHP 文件的内存量(以 MB 为单位)。
; 一个好的起点是 128 或 256。根据您的应用程序大小进行调整。
opcache.memory_consumption=256
; 可以存储在缓存中的 PHP 文件的最大数量。
; 请确保此数量大于您项目中的文件数。
opcache.max_accelerated_files=100003. 验证和重新验证
这些设置控制 OPcache 如何检查您的源代码是否已更改。
; OPcache 检查脚本更新的频率(以秒为单位)。
; 0 表示每次请求都检查(对性能不利)。
; 在生产环境中,设置较高的值对性能更有利。
opcache.revalidate_freq=60
; 如果启用,OPcache 将检查文件时间戳以了解更改。
; 禁用它(设为 0)可以稍微提升性能,但需要手动重置才能看到更改。
opcache.validate_timestamps=1
; 如果启用,OPcache 将使用更积极的文件存在性检查,这有助于解决一些边缘情况。
opcache.revalidate_path=04. 性能优化
; 通过优化内部字符串缓冲区来节省少量内存并可能提高性能。
opcache.interned_strings_buffer=16
; 通过单个内存释放调用来实现更快的关闭。
opcache.fast_shutdown=15. 预加载(PHP 7.4+)
这是一个强大的功能,可以在服务器启动时将您最重要的代码加载到内存中。
; 启用预加载
opcache.preload=/path/to/your/preload.php
; 用于预加载的用户 ID。通常需要与您的 Web 服务器用户(例如 www-data)相同。
; opcache.preload_user=www-data您的 preload.php 文件应包含 opcache_compile_file() 语句来预加载特定的类和脚本。
// preload.php
<?php
$files = /* 指向您关键 PHP 文件路径的数组 */;
foreach ($files as $file) {
opcache_compile_file($file);
}检查 OPcache 状态
您可以通过几种方式检查 OPcache 是否在工作并查看其统计信息:
1. 使用 phpinfo()
创建一个简单的 PHP 文件并在浏览器中查看。
<?php phpinfo();寻找标题为 "Zend OPcache" 的部分。如果存在,则表示 OPcache 已启用。
2. 使用内置的 OPcache 状态页面(如果可用)
许多发行版在编译 PHP 时启用了 opcache.file_cache_only=0,这允许您使用 opcache_get_status() 函数。您可以创建一个简单的脚本来显示它:
<?php
$status = opcache_get_status(false);
echo '<pre>';
print_r($status);
echo '</pre>';这将显示详细信息,如内存使用情况、命中率、缓存的脚本等。
3. 使用图形界面
有一些优秀的开源工具可以为监控 OPcache 提供漂亮的 GUI:
- OPcache GUI(非常简洁干净)
- OPcache Status(由 PHP 创建者 Rasmus Lerdorf 开发)
常见问题及解决方案
1. "我看不到我的代码更改!"
这是因为 OPcache 正在提供旧的缓存版本。
- 解决方案 1(开发环境): 在您的开发环境中,设置
opcache.validate_timestamps=1和opcache.revalidate_freq=0。这会使其在每次请求时都检查更改。 - 解决方案 2(生产环境): 在生产环境中部署新代码的正确方法是在文件更新后重置 OPcache。
- 通过代码: 您可以从 CLI 脚本或应用程序中安全、隐藏的 URL 调用
opcache_reset()。 - 通过重启: 重启您的 PHP-FPM 池或 Apache 模块。
- 通过部署工具: 大多数现代部署工具(如 Deployer, Capistrano)都有钩子来运行
opcache_reset()。
- 通过代码: 您可以从 CLI 脚本或应用程序中安全、隐藏的 URL 调用
2. "我的缓存总是满的!"
您可能会在日志中看到警告,或者在 opcache_get_status() 中看到 opcache_hit_rate 为 false。
- 解决方案: 增加
opcache.memory_consumption和/或opcache.max_accelerated_files。
3. "脚本没有被缓存。"
检查 opcache_get_status() 的输出。查看 scripts 部分以了解实际缓存了什么。确保您的 opcache.memory_consumption 没有设置得过低。
总结:一个适用于生产环境的基础配置
以下是一个适用于生产服务器的可靠起始配置:
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=300 ; 5 分钟
opcache.validate_timestamps=1 ; 如果您能做到,可以设置为 0 并手动重置缓存
opcache.fast_shutdown=1
; opcache.preload=/path/to/preload.php总结来说,OPcache 不仅仅是一种优化;它是任何严肃的 PHP 部署中必不可少的组件。正确启用和调优它是您可以进行的最高影响力的性能更改之一。
