42 lines
2.0 KiB
Markdown
42 lines
2.0 KiB
Markdown
# Redis Cache — 实现细节
|
||
|
||
> 主流程见 SKILL.md,本文档为连接、Cache-Aside、CachedRepository、TTL、分布式锁、穿透/击穿防护的完整代码。
|
||
|
||
## 连接配置
|
||
|
||
```php
|
||
// config/autoload/redis.php
|
||
return [
|
||
'default' => ['host' => env('REDIS_HOST'), 'auth' => env('REDIS_AUTH'), 'port' => (int) env('REDIS_PORT', 6379), 'db' => (int) env('REDIS_DB', 0), 'pool' => ['min_connections' => 5, 'max_connections' => 30, ...]],
|
||
'cache' => ['db' => (int) env('REDIS_CACHE_DB', 1), 'pool' => [...]] // 独立连接池
|
||
];
|
||
```
|
||
|
||
## Cache-Aside 模式
|
||
|
||
CacheService:`withCache($key, $ttl, $fetcher)` — get 命中则返回,否则 fetcher() 后 setex,TTL 加 jitter 防 stampede。`invalidate($keys)`、`invalidatePattern($pattern)` 用 scan 分批 del。
|
||
|
||
## CachedRepository 装饰器
|
||
|
||
实现 RepositoryInterface,包装 baseRepo。getById/getPageList 用 withCache,key 格式 `{entity}:{id}` 和 `{entity}:list:{params_hash}`。invalidateDetail/invalidateList/invalidateAll。DI 注册时用 closure 返回 new CachedRepository(baseRepo, cacheService, 'order', detailTtl, listTtl)。Service 写操作后判断 `$repository instanceof CachedRepository` 则 invalidateAll。
|
||
|
||
## TTL 规范
|
||
|
||
Profile 30m、列表 5m、配置 1h、JWT 2h、Session 24h、限流与窗口对齐、验证码 5m、锁 任务时长+30s。
|
||
|
||
## Key 命名
|
||
|
||
`<namespace>:<entity>:<id>:<field>`,如 user:profile:123、orders:list:page:1、rate:limit:ip:api、session:user:456、lock:order:789、ws:connection:fd:100。
|
||
|
||
## 分布式锁
|
||
|
||
RedisLockService:withLock($lockKey, $ttlMs, $fn)。SET NX PX。释放用 Lua 脚本原子校验 value 后 DEL。
|
||
|
||
## 缓存穿透/击穿
|
||
|
||
穿透:不存在 key 缓存 NULL_PLACEHOLDER(TTL 30s)。击穿:热点 key 用 withLock 互斥,double-check 后 fetcher 再 setex。
|
||
|
||
## 装饰器 vs 直接缓存 决策
|
||
|
||
读写比 > 10:1 → CachedRepository。读写比 < 10:1 → Service 内 CacheService。热点数据(排行榜)→ Redis 原生 ZSET/INCR。
|