PHP 作為解釋型語言,每次請求都需「編譯 → 執行」兩階段。字節碼緩存將編譯生成的 Opcode 存儲在共享內存中,省去重複編譯,是 PHP 性能優化的「第一銀彈」。本文回顧從早期 PHP Accelerator 到現代 OPcache 的技術演進。
# 歷史配置示例 (httpd.conf / php.ini)
# 虛擬主機模式
php_value phpa.registration_key 8edfd13946c96309244fcca309415902
php_value phpa.cache_dir /tmp
php_value phpa.shm_size 8
php_value phpa.shm_key 0xc0deb00
# APC 典型配置 (php.ini)
extension=apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size=128M
apc.num_files_hint=10000
apc.user_entries_hint=4096
apc.ttl=7200
apc.user_ttl=7200
apc.gc_ttl=3600
apc.max_file_size=1M
apc.stat=1 # 生產環境建議 0
apc.include_once_override=1
# OPcache 推薦生產配置 (php.ini)
[opcache]
zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.max_wasted_percentage=5
opcache.use_cwd=1
opcache.validate_timestamps=0 # 生產環境關鍵:關閉文件檢查
opcache.revalidate_freq=0
opcache.save_comments=1
opcache.fast_shutdown=1
opcache.enable_file_override=0
opcache.optimization_level=0x7FFFBFFF # 全優化
opcache.blacklist_filename=/etc/php/opcache-blacklist.txt
# JIT 配置 (PHP 8.0+)
opcache.jit_buffer_size=100M
opcache.jit=1255 # tracing + 內聯優化
| 參數 | 含義 | 推薦值 | 調優建議 |
|---|---|---|---|
| memory_consumption | 共享內存大小(MB) | 256-512 | 根據項目文件數估算:文件數 × 1KB ≈ 所需內存 |
| max_accelerated_files | 最大緩存文件數 | 20000-50000 | 設為項目 PHP 文件總數 1.2-1.5 倍,質數最佳 |
| interned_strings_buffer | 駐留字符串緩存(MB) | 16-32 | 大量重複字符串項目可調大 |
| validate_timestamps | 是否檢查文件修改時間 | 0 (生產) | 開發=1,生產=0,部署後需重啟 PHP-FPM 或 opcache_reset() |
| revalidate_freq | 檢查間隔(秒) | 0 | validate_timestamps=1 時生效,0=每次請求檢查 |
| save_comments | 保留註釋 | 1 | Doctrine/註解路由框架必須開啟 |
| fast_shutdown | 快速關閉 | 1 | PHP 7.2+ 已默認啟用並移除此選項 |
| jit_buffer_size | JIT 代碼緩存(MB) | 100-256 | PHP 8.0+,CPU 密集型項目明顯提升 |
| jit | JIT 編譯策略 | 1255 | 1235=tracing, 1255=function 內聯,生產建議 1255 |
# 1. 構建階段
composer install --no-dev --optimize-autoloader --classmap-authoritative
# 2. 部署階段 (原子部署)
# 新版本發布到新目錄 /var/www/releases/20240101_120000
# 原子切換軟鏈接
ln -sfn /var/www/releases/20240101_120000 /var/www/current
# 3. OPcache 失效 (關鍵步驟)
# 方案一: 重啟 PHP-FPM (平滑重啟)
systemctl reload php-fpm
# 方案二: opcache_reset() (需 Web 訪問觸發)
# 創建 reset.php: /dev/null
curl -s https://example.com/api/health > /dev/null
<?php
// opcache_status.php (僅內網訪問)
if (php_sapi_name() !== 'cli') {
header('Content-Type: application/json');
echo json_encode(opcache_get_status(true), JSON_PRETTY_PRINT);
}
?>
// 關鍵指標解讀
$status = opcache_get_status();
echo "內存使用率: " . round($status['memory_usage']['used_memory'] / $status['memory_usage']['free_memory'] * 100, 1) . "%\n";
echo "緩存命中率: " . round($status['opcache_statistics']['hits'] / ($status['opcache_statistics']['hits'] + $status['opcache_statistics']['misses']) * 100, 1) . "%\n";
echo "緩存文件數: " . $status['opcache_statistics']['num_cached_scripts'] . "\n";
echo "廢棄內存: " . round($status['memory_usage']['wasted_memory'] / 1024 / 1024, 1) . " MB\n";
echo "重啟次數: " . $status['opcache_statistics']['restarts'] . "\n";
// 黑名單文件示例 (/etc/php/opcache-blacklist.txt)
/var/www/current/vendor/symfony/var-dumper/*
/var/www/current/vendor/monolog/monolog/*
/var/www/current/storage/*
/var/www/current/bootstrap/cache/*
| 問題 | 現象 | 原因 | 解決 |
|---|---|---|---|
| 代碼更新不生效 | 修改文件後頁面無變化 | validate_timestamps=0 | 部署後執行 opcache_reset() 或 reload php-fpm |
| 內存耗盡 | OOM、緩存命中率低、頻繁重啟 | memory_consumption 過小 | 調大至 512MB+,檢查 max_accelerated_files |
| 類未找到 | Class 'X' not found | OPcache 與自動加載衝突 | composer dump-autoload -o,檢查 blacklist |
| 註解丟失 | 註解路由/驗證失效 | save_comments=0 | 設置 save_comments=1 |
| JIT 崩潰 | Segmentation fault | JIT 編譯器 Bug | 降級 jit 策略或關閉 JIT |
核心建議:
1. 生產環境必開 OPcache,且 `validate_timestamps=0` + 部署時 `opcache_reset()`
2. 內存配置要足夠,寧大勿小,監控命中率 > 95%
3. JIT 適合 CPU 密集型(計算、圖像處理、科學計算),I/O 密集型效果有限
4. 用戶數據緩存用 Redis/APCu,不要混用 OPcache
5. 黑名單排除開發工具、緩存目錄、動態生成文件
6. 部署流程自動化:原子部署 + 自動失效 + 預熱 + 驗證