Files
rxthinkcmf-wiki/RXThinkCMF_Laravel13_NaiveVue/zh/architecture/cache.md
T
2026-10-08 17:50:29 +08:00

120 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 4.8 缓存架构设计
:::tip 概述
项目采用两级缓存架构:请求级缓存(内存)+ 持久缓存(Cache 门面,默认 Redis),大幅减少数据库查询;数据变更时由 Observer 自动失效对应缓存,保证一致性。
:::
## 两级缓存架构
```text
┌─────────────────────────────────────────────────────────┐
│ 第一级:请求级缓存(static 变量) │
│ │
│ 生命周期:单次 HTTP 请求 │
│ 存储位置:PHP 内存(static $cache) │
│ 速度:极快(纳秒级) │
│ │
│ 同一请求内多次查询同一数据,只查一次库或缓存 │
└──────────────────────────┬──────────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────────────────┐
│ 第二级:持久缓存(cache() 门面 / Redis) │
│ │
│ 生命周期:跨请求复用 │
│ 存储位置:Redis(CACHE_STORE=redis,必需组件) │
│ 速度:快(毫秒级) │
│ 有效期:1 小时(3600 秒) │
│ │
│ 跨请求复用,减少数据库压力 │
└──────────────────────────┬──────────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────────────────┐
│ 数据库查询 │
│ │
│ 查询后同时写入两级缓存 │
└─────────────────────────────────────────────────────────┘
```
## 使用两级缓存的服务
| 服务 | 缓存键格式 | 说明 |
|------|-----------|------|
| `DictCacheService` | `dict_{code}`(前缀 `dict_`) | 字典项映射(`CACHE_PREFIX = 'dict_'`,TTL 见 `CACHE_TTL`) |
| `MenuService` 等 | 权限/菜单缓存 | 角色权限列表(配合 Observer 失效) |
## 缓存一致性:Observer 自动失效
数据变更时由 Eloquent Observer 精确失效相关缓存(注册于 `AppServiceProvider`):
| Observer | 监听模型 | 触发动作 |
|----------|----------|----------|
| `DictItemObserver` | 字典项 | 清除所属字典缓存(`dict_{code}`) |
| `MenuObserver` | 菜单 | 清除菜单/权限相关缓存 |
| `RoleMenuObserver` | 角色-菜单关系 | 清除角色权限缓存 |
```text
字典项变更 → DictItemObserver → DictCacheService::clearCache(code) → 下次读取回源重建
菜单变更 → MenuObserver → 权限缓存失效 → 前端刷新菜单后生效
```
:::tip 设计要点
缓存写入发生在"读取回源"时,失效只做 `forget` 不做主动重建——**删除缓存比更新缓存更安全**,避免并发下旧数据回写。
:::
## 缓存驱动配置
`.env` 配置:
```ini
# Redis 缓存(项目默认,必需)
CACHE_STORE=redis
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=null # 设置了 requirepass 时必须同步
```
:::warning 不要改回 database/file 驱动
- `CACHE_STORE=database`:数据库脚本**不含** Laravel `cache` 表,会直接报表不存在;
- `file` 驱动:多进程/多服务器环境下无法共享,且本项目 JWT 会话、权限缓存均依赖 Redis;
- 会话 / 缓存 / 队列三者统一使用 Redis(`SESSION_DRIVER` / `CACHE_STORE` / `QUEUE_CONNECTION`)。
:::
## 缓存清除
```php
// 清除指定字典缓存(Observer 已自动调用,此处为手动兜底)
DictCacheService::clearCache('gender');
// 清除所有字典缓存
DictCacheService::clearAllCache();
```
对应接口与命令:
```text
GET /api/dict/refreshCache 刷新字典缓存(需认证)
php artisan dict:clear-cache 命令行清除字典缓存
php artisan config:clear 清除配置缓存(修改 .env 后)
php artisan cache:clear 清除全部应用缓存
```
## Redis 使用全景
| 用途 | 使用方 | 说明 |
|------|--------|------|
| JWT 双令牌会话 | `JwtService` | refresh_token 存 Redis(支持踢下线、改密全端失效、一次性消费) |
| 字典缓存 | `DictCacheService` | 两级缓存第二级 |
| 权限/菜单缓存 | `Authenticate` 中间件 + Observer | 角色权限列表 |
| 验证码 | `CaptchaService` | 图形验证码存取 + IP 限流 |
| 会话/队列 | Laravel 驱动 | `SESSION_DRIVER` / `QUEUE_CONNECTION` |
连接验证:
```bash
php artisan tinker --execute="try { \Illuminate\Support\Facades\Redis::setex('test:key', 10, 'ok'); echo 'OK: '.\Illuminate\Support\Facades\Redis::get('test:key'); } catch (\Throwable \$e) { echo \$e->getMessage(); }"
# 输出 OK: ok 即连接正常
```