
后端应用缓存策略
缓存旁路(惰性加载)
应用程序手动管理缓存。最常见的模式。
class UserService {
constructor(
private userRepo: UserRepository,
private cache: RedisCache
) {}
async getUser(userId: string): Promise<User> {
const cacheKey = `user:${userId}`;
// 1. 先检查缓存
const cached = await this.cache.get<User>(cacheKey);
if (cached) return cached;
// 2. 缓存未命中 - 从数据库获取
const user = await this.userRepo.findById(userId);
if (!user) throw new UserNotFoundError(userId);
// 3. 存入缓存并设置 TTL
await this.cache.set(cacheKey, user, { ttl: 3600 }); // 1 小时
return user;
}
async updateUser(userId: string, dto: UpdateUserDto): Promise<User> {
const user = await this.userRepo.update(userId, dto);
// 更新后使缓存失效
await this.cache.delete(`user:${userId}`);
return user;
}
}

直写缓存
同时写入缓存和数据库。
async setUser(user: User): Promise<void> {
const cacheKey = `user:${user.id}`;
// 同时写入两者
await Promise.all([
this.userRepo.save(user),
this.cache.set(cacheKey, user, { ttl: 3600 }),
]);
}

Redis 缓存实现
import { createClient } from 'redis';
class RedisCache {
private client = createClient({ url: process.env.REDIS_URL });
async get<T>(key: string): Promise<T | null> {
const data = await this.client.get(key);
if (!data) return null;
return JSON.parse(data) as T;
}
async set<T>(key: string, value: T, options: { ttl?: number } = {}): Promise<void> {
const serialized = JSON.stringify(value);
if (options.ttl) {
await this.client.setEx(key, options.ttl, serialized);
} else {
await this.client.set(key, serialized);
}
}
async delete(key: string): Promise<void> {
await this.client.del(key);
}
async deletePattern(pattern: string): Promise<void> {
const keys = await this.client.keys(pattern);
if (keys.length > 0) {
await this.client.del(keys);
}
}
async getOrSet<T>(key: string, factory: () => Promise<T>, ttl = 3600): Promise<T> {
const cached = await this.get<T>(key);
if (cached !== null) return cached;
const value = await factory();
await this.set(key, value, { ttl });
return value;
}
}

缓存失效策略
// 基于标签的失效
class TaggedCache {
async setWithTags(key: string, value: unknown, tags: string[], ttl = 3600): Promise<void> {
await this.cache.set(key, value, { ttl });
// 存储反向映射:tag -> keys
for (const tag of tags) {
await this.client.sAdd(`tag:${tag}`, key);
await this.client.expire(`tag:${tag}`, ttl);
}
}
async invalidateByTag(tag: string): Promise<void> {
const keys = await this.client.sMembers(`tag:${tag}`);
if (keys.length > 0) {
await this.client.del([...keys, `tag:${tag}`]);
}
}
}
// 当用户更新时,使相关缓存失效
await taggedCache.setWithTags(
`user:${userId}`,
user,
[`user:${userId}`, 'users:list'],
3600
);
await taggedCache.invalidateByTag(`user:${userId}`);
缓存雪崩预防
// 互斥锁防止多个同时重建
async getWithLock<T>(key: string, factory: () => Promise<T>): Promise<T> {
const cached = await this.cache.get<T>(key);
if (cached !== null) return cached;
const lockKey = `lock:${key}`;
const lockAcquired = await this.client.set(lockKey, '1', { NX: true, EX: 5 });
if (!lockAcquired) {
// 另一个进程正在重建,等待并重试
await new Promise(resolve => setTimeout(resolve, 100));
return this.getWithLock(key, factory);
}
try {
const value = await factory();
await this.cache.set(key, value, { ttl: 3600 });
return value;
} finally {
await this.client.del(lockKey);
}
}
缓存命中率监控
class MonitoredCache extends RedisCache {
private hits = 0;
private misses = 0;
async get<T>(key: string): Promise<T | null> {
const result = await super.get<T>(key);
if (result !== null) {
this.hits++;
metrics.increment('cache.hit', { key: key.split(':')[0] });
} else {
this.misses++;
metrics.increment('cache.miss', { key: key.split(':')[0] });
}
return result;
}
get hitRate(): number {
const total = this.hits + this.misses;
return total > 0 ? this.hits / total : 0;
}
}
对于频繁访问的数据,目标缓存命中率达到 95% 以上。监控并根据需要调整 TTL。