缓存不是「加个 Cache::set 就完事」。键怎么命名、什么时候失效、Redis 挂了业务还能不能跑,这些决定缓存是帮忙还是添乱。

ThinkPHP 缓存与 Session 上 Redis:配置、键设计与失效策略 示意图

配置 Redis 连接

// config/cache.php
return [
    'default' => 'redis',
    'stores'  => [
        'redis' => [
            'type'       => 'redis',
            'host'       => env('REDIS_HOST', '127.0.0.1'),
            'port'       => env('REDIS_PORT', 6379),
            'password'   => env('REDIS_PASSWORD', ''),
            'select'     => 0,
            'prefix'     => 'app:',
            'expire'     => 3600,
            'persistent' => true,
        ],
    ],
];

prefix 很重要:同一台 Redis 往往被多个项目共用,没有前缀很容易与别的业务撞键。多环境共用时再加一层环境名,例如 app:prod:。

常用 API 与 remember

use think\facade\Cache;

// 手动读写
Cache::set('post:hot', $list, 600);
$list = Cache::get('post:hot', []);

// 读不到时执行闭包并写入,最常用的写法
$list = Cache::remember('post:hot', function () {
    return Post::where('status', 'published')
        ->order('views', 'desc')
        ->limit(10)
        ->select()
        ->toArray();
}, 600);

remember 把「查询 + 写入」合成一步,减少忘记写缓存的概率。删除时用 Cache::delete($key),不要用 set($key, null) —— 后者会让 get 返回 null,与「不存在」难以区分。

键命名规范

建议统一成「模块:对象:标识:维度」的形式,例如:

  • post:detail:1024:文章详情;
  • post:list:category-3:page-2:分类列表第 2 页;
  • user:profile:88:用户资料;
  • stat:visit:2026-10-21:按天统计。

好处是能用 keys 或扫描定位同模块的键,也方便在后台做「清空某模块缓存」。注意生产环境不要频繁使用 keys *,它会阻塞 Redis,改用固定前缀 + 维护一份键清单。

穿透、击穿与雪崩

  • 穿透:查询不存在的数据,缓存永远不命中。做法是缓存空值(短过期)或在入口做参数校验;
  • 击穿:热点键过期瞬间大量请求打到数据库。做法是加互斥锁(Cache::store('redis')->handler() 用 setnx)或逻辑过期;
  • 雪崩:大批键在同一时刻过期。做法是过期时间加随机抖动,例如 600 秒 + 0~120 秒随机。

Session 放 Redis

// config/session.php
return [
    'type'       => 'redis',
    'store'      => 'redis',
    'expire'     => 7200,
    'prefix'     => 'sess:',
];

几个注意点:

  • Session 的过期时间要和前端登录态一致,否则会出现「页面还显示已登录,接口却返回未登录」;
  • 多台机器共享 Session 时必须用同一个 Redis 库与前缀;
  • Redis 重启若未开启持久化,所有用户会被登出,做运维操作前先评估影响。

Redis 挂了怎么办

缓存层不应成为单点。读取缓存失败时捕获异常并回退到数据库查询,同时打日志告警;写缓存失败则忽略,不要因为缓存写不进去导致业务失败。

try {
    $data = Cache::get($key);
} catch (Throwable $e) {
    logger()->warning('缓存读取失败', ['key' => $key, 'error' => $e->getMessage()]);
    $data = null;
}

小结

把 Redis 引入项目,收益来自「少查数据库」,风险来自「键管理」与「故障兜底」。键名规范、过期抖动、失败降级这三件事做到位,缓存才算可控。想看数据库层面的配套优化,可以接着读模型关联与预载入。