
PHP框架里开缓存,别只配 cache.driver
光在 .env 里设 CACHE_DRIVER=redis 或 file,根本没跑出缓存真实性能。真正快的关键,在于「缓存键设计」和「生命周期控制」——比如 Laravel 的 Cache::remember() 默认用 60 秒,但很多配置类数据其实该设成 0(永久)或用 Cache::rememberForever(),而用户会话类数据反而要缩到 300 秒以内。
常见错误是把整个 DB::table('users')->get() 直接塞进缓存,结果序列化体积暴涨、反序列化变慢。更轻的做法是只缓存关键字段数组:DB::table('users')->pluck('name', 'id')。
- 避免缓存 Eloquent 模型实例(含关系、访问器、大量私有属性),改用
$model->toArray()或显式 select 字段 - Redis 缓存时,开启
redis.compression = 1(Laravel 9+ 支持 LZ4 压缩)能减小网络传输体积 - File 缓存别放
storage/framework/cache/data/下默认路径——如果磁盘 I/O 高,换成 tmpfs 内存挂载点(如/dev/shm/laravel-cache)
Laravel 的 cache:clear 为什么越清越慢?
因为默认命令会遍历所有缓存文件或 Redis key pattern,尤其当用了 tag 缓存(Cache::tags(['user', 'profile'])->put(...))时,底层要查索引表。生产环境清缓存卡顿,八成是没关掉 debug 模式下的缓存记录日志。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 部署后清缓存,用
php artisan cache:clear --quiet关掉冗余输出 - 禁用调试模式下缓存事件监听:在
config/cache.php中确认'store' => env('CACHE_STORE', 'redis'),且不要在AppServiceProvider::boot()里注册CacheHit/CacheMissed监听器 - Redis 场景下,用
FLUSHDB替代 Laravel 的全量清理逻辑,再配合php artisan config:clear单独刷配置缓存
Hybrid 缓存策略:什么时候该用 APCu + Redis 组合?
APCu 是进程内缓存,读取速度比 Redis 快 5–10 倍,但它不跨 PHP-FPM worker 进程。所以适合缓存「高频读、低更新」的全局静态数据,比如路由定义、配置项、语言包;Redis 则负责「需跨进程一致」的数据,比如用户 session、排行榜、锁。
典型用法(Laravel):
// config/cache.php
'stores' => [
'apcu' => [
'driver' => 'apc',
],
'redis' => [
'driver' => 'redis',
'connection' => 'cache',
],
],
'default' => 'redis',
然后在业务中手动分流:
- 配置类:用
Cache::store('apcu')->get('app.name') - 用户数据:仍走默认
Cache::get('user:123')(即 Redis) - 注意 APCu 在 CLI 模式(如队列 worker)下不可用,得 fallback 到 file 或 redis
缓存穿透和雪崩,不是加个 lock 就完事
缓存穿透(查不存在的 key)会导致大量请求打到 DB;缓存雪崩(大批 key 同时过期)会让 DB 瞬间被压垮。简单用 Cache::lock() 包裹数据库查询,只是把并发请求串行化,治标不治本。
更稳的做法:
- 对空结果也缓存(如
Cache::remember('user:999999', 300, fn() => $user ?: ['__empty__' => true])),并配合布隆过滤器预检(用redis-bloom扩展) - 设置随机过期时间:不要写死
3600,改成3600 + random_int(0, 600) - 关键接口加二级缓存:先查 APCu(短 TTL),未命中再查 Redis(长 TTL),双未命中才查 DB
缓存键里混入版本号(如 "user:123:v2")比盲目清整个 tag 更可控,也更容易做灰度切换。这点很多人忽略,直到改了字段结构,缓存还吐着旧格式数据。











