高并发缓存预热核心是“不等用户来,数据已就位”,需在CLI环境单次执行、只预热高频低变数据、配合随机TTL与双缓存防雪崩,并通过tinker、redis-cli和监控三重验证。

高并发下预热缓存,核心是“不等用户来,数据已就位”。冷启动雪崩本质是大量请求在应用刚上线或重启后集中触发缓存未命中,回源压垮数据库。解决不是靠运气,而是靠可执行、可验证、可集成的三步动作:选对时机、写对数据、控住节奏。
一、必须在 CLI 环境单次执行,别塞进请求生命周期
预热不能出现在 AppServiceProvider::boot()、中间件、路由或配置文件里——这些地方每次 HTTP 请求都会跑一遍,反而制造性能瓶颈。真正安全的位置只有两个:
- 部署脚本中调用 Artisan 命令(如
php artisan cache:warmup),紧接在php artisan optimize:clear和php artisan config:cache之后 - 容器启动时通过
entrypoint.sh或 Docker 的command字段触发,确保 PHP-FPM 或 Horizon worker 启动前已完成
特别注意:CLI 环境可能无法访问 Web 容器网络(比如 Docker 中 CLI 容器连不上 DB 容器),需统一使用服务名(如 db)而非 localhost,并在 .env 中为 DB_HOST 配置正确值。
二、只预热确定高频、低变更、结构稳定的数据
不是所有数据都值得预热。优先加载以下几类:
- 首页导航菜单、站点全局配置(
site_config)、多语言包元数据 - 分类树(
categories)、标签云、热门文章/产品列表(按固定条件查,如views > 1000) - 聚合统计值(如
total_users、active_orders_today),用Cache::put()显式设 TTL,避免用rememberForever()(已废弃)
示例代码(app/Console/Commands/CacheWarmup.php):
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use App\Models\Category;
use App\Models\Post;
class CacheWarmup extends Command
{
protected $signature = 'cache:warmup';
protected $description = 'Preload critical data into cache';
public function handle()
{
// 分类树:稳定、必读、无分页
$categories = Category::with('children')->get();
Cache::put('categories_tree', $categories, 7200); // 2小时
// 热门文章:带条件、时效性中等
$popular = Post::popular()->take(8)->get();
Cache::put('homepage_popular_posts', $popular, 1800); // 30分钟
$this->info('✅ Categories & popular posts cached.');
}
}
三、配合随机 TTL + 双缓存机制防雪崩叠加
光预热不够,还要防止预热后的缓存集体过期。关键两招:
-
给每个预热项加随机 TTL:例如基础 2 小时,浮动 ±6 分钟:
$ttl = 7200 + rand(-360, 360)。尤其适用于同类键(如category_1,category_2) - 双缓存兜底:对极关键数据(如站点开关、维护状态),用两层缓存 —— 主缓存(Redis,TTL 30 分钟)+ 备缓存(APCu 或 file,永不过期)。主缓存失效时,备缓存仍可应急返回,同时异步重建主缓存
这样即使某批预热数据在同一分钟过期,也不会全量回源;哪怕 Redis 暂不可用,APCu 还能撑住基础可用性。
四、验证是否真生效,别信“运行了就完了”
预热后必须验证,方法有三:
- 登录服务器,直接查缓存:
php artisan tinker→Cache::get('categories_tree'),确认非 null 且结构正确 - 检查 Redis(或对应驱动)实际存储:
redis-cli KEYS "categories*"或用 RedisInsight 查 TTL 剩余时间 - 部署后立即用 curl 模拟首页请求,观察 MySQL 慢日志或 New Relic 监控 —— 若首页 SQL 查询次数为 0,说明预热成功
不复杂但容易忽略。


















