17 changed files with 269 additions and 12 deletions
@ -0,0 +1,188 @@ |
|||
# Cache System 使用文档 |
|||
|
|||
`packages/cache` 提供一个支持 Redis 主存储 + Memory 内存降级的通用 K-V 缓存系统。 |
|||
|
|||
## 安装 |
|||
|
|||
cache 包已作为 workspace 依赖安装,直接使用即可: |
|||
|
|||
```typescript |
|||
import { createCache } from 'cache' |
|||
``` |
|||
|
|||
## 快速开始 |
|||
|
|||
```typescript |
|||
import { createCache } from 'cache' |
|||
|
|||
// 初始化 |
|||
const cache = createCache({ |
|||
redis: { |
|||
host: '127.0.0.1', |
|||
port: 6379, |
|||
}, |
|||
defaultTtl: 300, // 默认 5 分钟 |
|||
}) |
|||
|
|||
// 在 Nitro API 中使用 |
|||
export default defineEventHandler(async (event) => { |
|||
const key = 'users:list' |
|||
|
|||
// 尝试从缓存读取 |
|||
const cached = await cache.get(key) |
|||
if (cached) return cached |
|||
|
|||
// 缓存未命中,从数据源获取 |
|||
const data = await fetchUsers() |
|||
|
|||
// 写入缓存 |
|||
await cache.set(key, data) |
|||
|
|||
return data |
|||
}) |
|||
``` |
|||
|
|||
## API |
|||
|
|||
### createCache(options) |
|||
|
|||
创建 CacheManager 实例。 |
|||
|
|||
```typescript |
|||
interface CacheFactoryOptions { |
|||
redis?: RedisDriverOptions // Redis 配置,省略则只用内存 |
|||
memory?: boolean // 是否启用内存兜底,默认 true |
|||
defaultTtl?: number // 默认 TTL(秒),默认 0(永不过期) |
|||
} |
|||
|
|||
interface RedisDriverOptions { |
|||
host: string |
|||
port: number |
|||
password?: string |
|||
db?: number |
|||
} |
|||
``` |
|||
|
|||
**行为:** |
|||
- `redis` 配置存在时,Redis 作为主存储(优先尝试) |
|||
- `memory !== false` 时,Memory 作为兜底(Redis 不可用时自动降级) |
|||
- 两者都不配置则抛出错误 |
|||
|
|||
### CacheManager 实例方法 |
|||
|
|||
```typescript |
|||
// 读取缓存,未命中返回 null |
|||
get<T = unknown>(key: string): Promise<T | null> |
|||
|
|||
// 写入缓存 |
|||
// ttl 单位为秒,0 表示永不过期 |
|||
set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> |
|||
|
|||
// 删除指定 key |
|||
del(key: string): Promise<void> |
|||
|
|||
// 检查 key 是否存在 |
|||
exists(key: string): Promise<boolean> |
|||
|
|||
// 清空所有缓存(谨慎使用) |
|||
clear(): Promise<void> |
|||
``` |
|||
|
|||
## 降级策略 |
|||
|
|||
采用**手动显式降级**:按驱动数组顺序尝试,返回第一个成功结果。 |
|||
|
|||
``` |
|||
RedisDriver (优先) |
|||
↓ 失败时 |
|||
MemoryDriver (兜底) |
|||
``` |
|||
|
|||
- `get` / `exists`:遍历 drivers,返回第一个成功结果 |
|||
- `set` / `del` / `clear`:并发写入/删除所有 drivers(保证各层数据一致) |
|||
- 单个 driver 失败时 warn 并继续,不影响整体操作 |
|||
|
|||
## 使用场景 |
|||
|
|||
### 场景一:纯内存缓存(开发/无 Redis 环境) |
|||
|
|||
```typescript |
|||
const cache = createCache({ |
|||
defaultTtl: 60, |
|||
}) |
|||
``` |
|||
|
|||
### 场景二:Redis + 内存降级(生产环境) |
|||
|
|||
```typescript |
|||
const cache = createCache({ |
|||
redis: { |
|||
host: process.env.REDIS_HOST!, |
|||
port: Number(process.env.REDIS_PORT ?? 6379), |
|||
password: process.env.REDIS_PASSWORD, |
|||
db: Number(process.env.REDIS_DB ?? 0), |
|||
}, |
|||
defaultTtl: 300, |
|||
}) |
|||
``` |
|||
|
|||
### 场景三:禁用内存兜底(Redis 专用) |
|||
|
|||
```typescript |
|||
const cache = createCache({ |
|||
redis: { host: '127.0.0.1', port: 6379 }, |
|||
memory: false, |
|||
}) |
|||
``` |
|||
|
|||
### 场景四:Nitro Plugin 全局注入 |
|||
|
|||
`server/plugins/cache.ts`: |
|||
|
|||
```typescript |
|||
import { createCache } from 'cache' |
|||
|
|||
export default defineNitroPlugin(() => { |
|||
const cache = createCache({ |
|||
redis: { |
|||
host: '127.0.0.1', |
|||
port: 6379, |
|||
}, |
|||
defaultTtl: 300, |
|||
}) |
|||
|
|||
// 注入到 H3 event context |
|||
event.context.cache = cache |
|||
}) |
|||
``` |
|||
|
|||
`server/api/users.get.ts`: |
|||
|
|||
```typescript |
|||
export default defineEventHandler(async (event) => { |
|||
const cache = event.context.cache |
|||
|
|||
const cached = await cache.get('users:list') |
|||
if (cached) return cached |
|||
|
|||
const data = await fetchUsers() |
|||
await cache.set('users:list', data) |
|||
return data |
|||
}) |
|||
``` |
|||
|
|||
## 数据结构 |
|||
|
|||
所有值以 JSON 序列化存储到 Redis: |
|||
|
|||
```typescript |
|||
await cache.set('user:1', { id: 1, name: 'Alice' }) |
|||
// Redis: SET 'user:1' '{"id":1,"name":"Alice"}' EX 300 |
|||
``` |
|||
|
|||
## 注意事项 |
|||
|
|||
- **TTL 单位是秒**,Redis `EX` 参数单位也是秒 |
|||
- `clear()` 在 Redis 上执行 `FLUSHDB`,会清空整个数据库,请确认 namespace 隔离 |
|||
- MemoryDriver 使用进程内存,重启进程后缓存丢失 |
|||
- 不支持存储 `undefined`、Symbol 或含循环引用的对象(JSON 序列化限制) |
|||
Binary file not shown.
@ -0,0 +1,22 @@ |
|||
import { createCache } from 'cache' |
|||
|
|||
const cache = createCache({ |
|||
// redis: {
|
|||
// host: process.env.REDIS_HOST ?? '127.0.0.1',
|
|||
// port: Number(process.env.REDIS_PORT ?? 6379),
|
|||
// password: process.env.REDIS_PASSWORD,
|
|||
// db: Number(process.env.REDIS_DB ?? 0),
|
|||
// },
|
|||
// defaultTtl: 300,
|
|||
memory: true |
|||
}) |
|||
|
|||
if (import.meta.dev) { |
|||
console.log('plugin: 04.cache') |
|||
} |
|||
|
|||
export default defineNitroPlugin((nitroApp) => { |
|||
nitroApp.hooks.hook('request', async (event) => { |
|||
event.context.cache = cache |
|||
}) |
|||
}) |
|||
@ -0,0 +1,7 @@ |
|||
import type { CacheManager } from 'cache' |
|||
|
|||
declare module 'h3' { |
|||
interface H3EventContext { |
|||
cache: CacheManager |
|||
} |
|||
} |
|||
Loading…
Reference in new issue