# 可降级缓存系统设计 **日期:** 2026-05-22 **状态:** approved ## 1. 概述 设计一个 Server-only 的通用 K-V 缓存系统 `packages/cache`,支持 Redis 主存储 + Memory 内存兜底。当 Redis 不可用时,自动降级到内存缓存,对调用方透明。 ## 2. 架构 ``` packages/cache/ ├── package.json ├── index.ts ← 导出工厂函数和类型 └── lib/ ├── types.ts ← 核心类型定义 ├── managers/ │ └── cache-manager.ts ← CacheManager 实现 └── drivers/ ├── base.ts ← Driver 基类 / 接口 ├── memory-driver.ts ← 内存驱动 └── redis-driver.ts ← Redis 驱动(ioredis) ``` ### 设计原则 - 分层适配器:调用方只跟 `CacheManager` 交互,不感知底层存储 - 手动显式降级:按 `drivers` 数组顺序尝试,返回第一个成功结果 - 扩展性:新增驱动(如 `cloudflare-kv-driver`)只需实现 `CacheDriver` 接口 ## 3. 核心类型 ```typescript // lib/types.ts export interface CacheOptions { ttl?: number // 默认 TTL(秒),0 = 不过期 namespace?: string // key 前缀隔离(未来扩展) } export interface CacheEntry { value: T expiresAt: number | null // Unix ms,null = 永不过期 } export interface CacheDriver { name: string get(key: string): Promise set(key: string, value: T, ttl?: number): Promise del(key: string): Promise exists(key: string): Promise clear(): Promise } export interface CacheManagerOptions { drivers: CacheDriver[] defaultTtl?: number } ``` ## 4. CacheManager **文件:** `lib/managers/cache-manager.ts` ```typescript export class CacheManager { private drivers: CacheDriver[] private defaultTtl: number constructor(options: CacheManagerOptions) async get(key: string): Promise async set(key: string, value: T, ttl?: number): Promise async del(key: string): Promise async exists(key: string): Promise async clear(): Promise withPrefix(ns: string): CacheManager } ``` **降级逻辑(get):** 遍历 `drivers`,返回第一个成功结果,全部失败返回 `null`。 **一致性逻辑(set/del/exists/clear):** 遍历所有 driver 并发写入,确保降级后各层数据一致。 ## 5. MemoryDriver **文件:** `lib/drivers/memory-driver.ts` - 用 `Map` 存储 - TTL = 0 不设置过期时间 - 过期检查在 `get` 时懒清理(检查 `expiresAt` 是否已到) - `clear()` 清空整个 Map ## 6. RedisDriver **文件:** `lib/drivers/redis-driver.ts` - 使用 `ioredis` 客户端 - value 序列化为 `JSON.stringify` 存储 - TTL = 0 时使用 `persist`(不设过期) - `clear()` 使用 `FLUSHDB` 清空当前数据库(假设 prod 使用独立 db) - 需支持 disconnect 关闭连接 **RedisOptions:** ```typescript interface RedisOptions { host: string port: number password?: string db?: number } ``` ## 7. 工厂函数 **文件:** `index.ts` ```typescript interface CacheFactoryOptions { redis?: { host: string port: number password?: string db?: number } memory?: boolean // 是否启用内存兜底,默认 true defaultTtl?: number // 默认 TTL(秒) } function createCache(options: CacheFactoryOptions): CacheManager ``` **行为:** - 如果指定了 `redis`,则将其作为主驱动加入 drivers 数组首位 - 如果 `memory !== false`,则将 MemoryDriver 加入 drivers 数组末位 - 如果既没有 `redis` 也没有内存(`memory: false`),抛出错误 ## 8. 使用方式 ```typescript // 初始化(在 Nitro 插件或 server/utils 中 const cache = createCache({ redis: { host: '127.0.0.1', port: 6379 }, defaultTtl: 300, }) // 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 }) ``` ## 9. 错误处理 - `get` 操作:单个 driver 失败时 warn 并尝试下一个;全部失败返回 `null` - `set/del/exists/clear` 操作:单个 driver 失败时 warn 但不中断(因为是并发写) - Redis 连接失败(如网络不可达):触发降级,不影响服务启动 ## 10. 依赖 ```json { "ioredis": "^5.x" } ``` 内存驱动无外部依赖。