本文目录导读:

- 预热 OpCache(最常用、最基础)
- 预热框架(Laravel / Symfony / ThinkPHP)
- 预热数据库连接 & 查询(连接池)
- 预热对象缓存(Redis / Memcached)
- 预热 JIT(PHP 8.0+)
- 多进程/常驻内存框架预热(Swoole / Workerman)
- 总结:你应该怎么做?
在 PHP 中,“预热”(Warmup)通常是指在正式接收用户请求之前,预先加载代码、建立数据库连接、填充缓存(如 OpCache、对象缓存)等操作,以消除第一次请求时的“冷启动”延迟(如编译、文件加载、连接建立)。
根据你的具体场景(Web 应用、CLI 脚本、常驻内存框架),预热的方法不同,以下是几种最常见的 PHP 预热方案:
预热 OpCache(最常用、最基础)
PHP 7/8 内置了 OpCache,默认情况下,第一个请求会触发编译并缓存 Opcode,后续请求直接使用缓存,可以在部署后主动访问所有关键页面来强制生成缓存。
方法:编写一个简单的预热脚本,请求所有重要 URL。
// warmup.php
$urls = [
'https://yoursite.com/',
'https://yoursite.com/api/status',
'https://yoursite.com/product/1',
// ... 所有关键路由
];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_exec($ch);
curl_close($ch);
echo "Warmed: $url\n";
}
部署时执行:
# 在部署脚本的最后运行 php warmup.php
或者直接触发 OpCache 预热(需要 root/CLI 权限):
# 扫描目录并编译所有 PHP 文件
php -d opcache.enable_cli=1 -r "opcache_compile_file('/path/to/your/app/index.php');"
# 批量编译(使用 find)
find /var/www -name "*.php" -exec php -d opcache.enable_cli=1 -r "opcache_compile_file('{}');" \;
预热框架(Laravel / Symfony / ThinkPHP)
现代框架启动时加载大量服务提供者、配置文件,可以通过在部署后执行框架内置的“优化”命令来预热。
Laravel 示例:
# 缓存配置、路由、视图 php artisan optimize php artisan config:cache php artisan route:cache php artisan view:cache # 预热所有服务提供者 php artisan serve --no-reload # 或者通过请求框架入口
Symfony 示例:
php bin/console cache:warmup --env=prod
ThinkPHP 示例:
php think optimize:route php think optimize:config
预热数据库连接 & 查询(连接池)
如果使用持久连接或连接池(如 Swoole、RoadRunner、Hyperf),需要预先建立连接。
原生 PDO 持久连接:
// 在后台进程中预先建立连接
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass', [
PDO::ATTR_PERSISTENT => true
]);
// 模拟一次查询,触发真实连接
$stmt = $pdo->query("SELECT 1");
在 Swoole/Hyperf 中预创建连接池:
// config/autoload/databases.php
return [
'default' => [
'pool' => [
'min_connections' => 10, // 启动时创建 10 个连接
'max_connections' => 50,
],
],
];
预热对象缓存(Redis / Memcached)
如果应用依赖缓存来存储数据(如 Session、配置、API 响应),可以在启动时填充常用键。
// 预热脚本
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 模拟加载热门数据
$hotProducts = getHotProductsFromDB(); // 从数据库获取
foreach ($hotProducts as $product) {
$redis->setex('product:' . $product['id'], 3600, json_encode($product));
}
预热 JIT(PHP 8.0+)
如果使用了 JIT(Just-In-Time 编译),可以预先触发 JIT 编译热点代码。
// 在 php.ini 中配置 opcache.jit = tracing opcache.jit_buffer_size = 100M // 通过运行代表性请求来触发 JIT 编译(JIT 自动执行,无需手动调用)
多进程/常驻内存框架预热(Swoole / Workerman)
这类框架通常以守护进程运行,预热是整个生命周期的一部分。
Workerman 示例:在 onWorkerStart 回调中预热。
$worker->onWorkerStart = function($worker) {
// 仅在工作进程启动时执行一次
if ($worker->id === 0) {
// 预热路由、初始化全局资源
require_once __DIR__ . '/vendor/autoload.php';
// 加载所有必要类
new \App\Controllers\HomeController();
}
};
Swoole 示例:使用 beforeStart 事件。
$server->on('beforeStart', function ($server) {
// 预热代码,比如建立连接池、加载配置文件
echo "Pre-warming database connections...\n";
Database::initPool();
});
你应该怎么做?
| 场景 | 推荐预热方法 |
|---|---|
| 简单的共享主机/FPM | 部署后运行 curl 脚本请求首页 + OpCache 编译 |
| Laravel/Symfony | 运行框架的 optimize:cache 系列命令 |
| 高并发 API(Swoole/Hyperf) | 设置连接池最小连接数,在启动时加载所有服务 |
| 首次请求很慢 | 检查 OpCache 是否开启,并使用 opcache_compile_file 编译所有文件 |
| CI/CD 自动部署 | 在部署脚本中加入预热步骤(curl + artisan cache) |
最后提醒:预热只在部署后第一次启动时有效,如果代码本身有性能缺陷(如 N+1 查询、无索引),预热只能缓解“冷启动”问题,不能替代真正的性能优化。