零度AI
高级18 分钟阅读

Claude Code 缓存策略

使用 Claude Code 实现 Redis 缓存、内存缓存,提升应用性能

Claude Code缓存Redis性能优化

缓存策略概述

缓存是提升应用性能的关键技术。Claude Code 可以帮助你实现多层次缓存策略,从内存缓存到分布式 Redis 缓存。

缓存适用场景

缓存适用于频繁读取但不频繁修改的数据,如配置信息、用户会话、商品详情等。

内存缓存

Node.js 内存缓存

bash
帮我创建一个简单的内存缓存模块,包含:
- 设置缓存(支持过期时间)
- 获取缓存
- 删除缓存
- 清除所有缓存
javascript
// lib/cache/memory.js
class MemoryCache {
  constructor() {
    this.cache = new Map();
    this.timers = new Map();
  }

  set(key, value, ttl = 0) {
    // 清除已有的定时器
    if (this.timers.has(key)) {
      clearTimeout(this.timers.get(key));
    }

    this.cache.set(key, {
      value,
      timestamp: Date.now(),
    });

    // 设置过期时间
    if (ttl > 0) {
      this.timers.set(
        key,
        setTimeout(() => {
          this.delete(key);
        }, ttl * 1000)
      );
    }
  }

  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;

    return item.value;
  }

  delete(key) {
    this.cache.delete(key);
    if (this.timers.has(key)) {
      clearTimeout(this.timers.get(key));
      this.timers.delete(key);
    }
  }

  clear() {
    this.cache.clear();
    this.timers.forEach((timer) => clearTimeout(timer));
    this.timers.clear();
  }

  // 获取缓存统计
  getStats() {
    return {
      size: this.cache.size,
      keys: Array.from(this.cache.keys()),
    };
  }
}

export const memoryCache = new MemoryCache();
export default memoryCache;

LRU 缓存实现

javascript
// lib/cache/lru.js
class LRUCache {
  constructor(maxSize = 100) {
    this.maxSize = maxSize;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) {
      return null;
    }

    // 将键移到末尾(最近使用)
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  set(key, value) {
    // 如果已存在,删除旧位置
    if (this.cache.has(key)) {
      this.cache.delete(key);
    }
    // 如果缓存已满,删除最旧的项
    else if (this.cache.size >= this.maxSize) {
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }

    this.cache.set(key, value);
  }

  has(key) {
    return this.cache.has(key);
  }

  delete(key) {
    return this.cache.delete(key);
  }

  clear() {
    this.cache.clear();
  }
}

export const lruCache = new LRUCache(100);
export default lruCache;

Redis 缓存

Redis 基础配置

bash
帮我创建一个 Redis 缓存模块,包含:
- 连接管理
- 基础操作(get/set/del)
- 过期时间设置
- 模式匹配删除
javascript
// lib/cache/redis.js
import Redis from "ioredis";

class RedisCache {
  constructor() {
    this.client = null;
  }

  async connect() {
    if (this.client) return this.client;

    this.client = new Redis({
      host: process.env.REDIS_HOST || "localhost",
      port: process.env.REDIS_PORT || 6379,
      password: process.env.REDIS_PASSWORD,
      db: process.env.REDIS_DB || 0,
      retryDelayOnFailover: 100,
      maxRetriesPerRequest: 3,
    });

    this.client.on("error", (err) => {
      console.error("Redis connection error:", err);
    });

    this.client.on("connect", () => {
      console.log("Redis connected successfully");
    });

    return this.client;
  }

  async get(key) {
    const client = await this.connect();
    const value = await client.get(key);
    return value ? JSON.parse(value) : null;
  }

  async set(key, value, ttlSeconds = 0) {
    const client = await this.connect();
    const serialized = JSON.stringify(value);

    if (ttlSeconds > 0) {
      await client.setex(key, ttlSeconds, serialized);
    } else {
      await client.set(key, serialized);
    }
  }

  async delete(key) {
    const client = await this.connect();
    return client.del(key);
  }

  async exists(key) {
    const client = await this.connect();
    return (await client.exists(key)) === 1;
  }

  async deletePattern(pattern) {
    const client = await this.connect();
    const keys = await client.keys(pattern);
    if (keys.length > 0) {
      return client.del(...keys);
    }
    return 0;
  }

  // 哈希操作
  async hget(key, field) {
    const client = await this.connect();
    const value = await client.hget(key, field);
    return value ? JSON.parse(value) : null;
  }

  async hset(key, field, value) {
    const client = await this.connect();
    return client.hset(key, field, JSON.stringify(value));
  }

  async hgetall(key) {
    const client = await this.connect();
    const data = await client.hgetall(key);
    const result = {};
    for (const [k, v] of Object.entries(data)) {
      result[k] = JSON.parse(v);
    }
    return result;
  }

  // 列表操作
  async lpush(key, ...values) {
    const client = await this.connect();
    const serialized = values.map((v) => JSON.stringify(v));
    return client.lpush(key, ...serialized);
  }

  async lrange(key, start, stop) {
    const client = await this.connect();
    const data = await client.lrange(key, start, stop);
    return data.map((v) => JSON.parse(v));
  }

  // 分布式锁
  async lock(key, ttlSeconds = 10) {
    const client = await this.connect();
    const token = Math.random().toString(36).substring(2);
    const result = await client.set(key, token, "EX", ttlSeconds, "NX");
    return result === "OK" ? token : null;
  }

  async unlock(key, token) {
    const client = await this.connect();
    const script = `
      if redis.call("get", KEYS[1]) == ARGV[1] then
        return redis.call("del", KEYS[1])
      else
        return 0
      end
    `;
    return client.eval(script, 1, key, token);
  }
}

export const redisCache = new RedisCache();
export default redisCache;

缓存策略实现

多级缓存

bash
帮我创建一个多级缓存系统,先查内存缓存,没有再查 Redis,都没有就查数据库并回填缓存。
javascript
// lib/cache/multi-level.js
import memoryCache from "./memory.js";
import redisCache from "./redis.js";

class MultiLevelCache {
  constructor(options = {}) {
    this.memoryTTL = options.memoryTTL || 60; // 内存缓存 60 秒
    this.redisTTL = options.redisTTL || 3600; // Redis 缓存 1 小时
    this.enableMemory = options.enableMemory !== false;
    this.enableRedis = options.enableRedis !== false;
  }

  async get(key, fetchFunc) {
    // 1. 尝试从内存缓存获取
    if (this.enableMemory) {
      const memoryValue = memoryCache.get(key);
      if (memoryValue !== null) {
        console.log(`[Cache] Memory hit: ${key}`);
        return memoryValue;
      }
    }

    // 2. 尝试从 Redis 获取
    if (this.enableRedis) {
      try {
        const redisValue = await redisCache.get(key);
        if (redisValue !== null) {
          console.log(`[Cache] Redis hit: ${key}`);
          // 回填到内存缓存
          if (this.enableMemory) {
            memoryCache.set(key, redisValue, this.memoryTTL);
          }
          return redisValue;
        }
      } catch (error) {
        console.error("Redis get error:", error);
      }
    }

    // 3. 从数据源获取
    if (fetchFunc) {
      console.log(`[Cache] Miss: ${key}, fetching from source`);
      const value = await fetchFunc();

      // 回填到缓存
      await this.set(key, value);
      return value;
    }

    return null;
  }

  async set(key, value) {
    // 设置内存缓存
    if (this.enableMemory) {
      memoryCache.set(key, value, this.memoryTTL);
    }

    // 设置 Redis 缓存
    if (this.enableRedis) {
      try {
        await redisCache.set(key, value, this.redisTTL);
      } catch (error) {
        console.error("Redis set error:", error);
      }
    }
  }

  async delete(key) {
    if (this.enableMemory) {
      memoryCache.delete(key);
    }
    if (this.enableRedis) {
      try {
        await redisCache.delete(key);
      } catch (error) {
        console.error("Redis delete error:", error);
      }
    }
  }

  async clear() {
    if (this.enableMemory) {
      memoryCache.clear();
    }
    if (this.enableRedis) {
      try {
        await redisCache.deletePattern("*");
      } catch (error) {
        console.error("Redis clear error:", error);
      }
    }
  }
}

export const multiLevelCache = new MultiLevelCache();
export default multiLevelCache;

缓存预热

javascript
// lib/cache/warmup.js
import multiLevelCache from "./multi-level.js";

export async function warmupCache() {
  console.log("Starting cache warmup...");

  const warmupTasks = [
    // 热门文章
    () =>
      multiLevelCache.get("popular_posts", async () => {
        const posts = await db.query(
          "SELECT * FROM posts WHERE published = true ORDER BY view_count DESC LIMIT 20"
        );
        return posts;
      }),

    // 站点配置
    () =>
      multiLevelCache.get("site_config", async () => {
        const config = await db.query("SELECT * FROM site_config");
        return config;
      }),

    // 分类列表
    () =>
      multiLevelCache.get("categories", async () => {
        const categories = await db.query(
          "SELECT * FROM categories ORDER BY sort_order"
        );
        return categories;
      }),
  ];

  await Promise.all(warmupTasks.map((task) => task()));

  console.log("Cache warmup completed");
}

缓存应用场景

接口缓存

bash
帮我创建一个带缓存的 API 数据获取函数,使用多级缓存。
javascript
// services/postService.js
import multiLevelCache from "../lib/cache/multi-level.js";

export async function getPostBySlug(slug) {
  const cacheKey = `post:${slug}`;

  return multiLevelCache.get(cacheKey, async () => {
    const post = await db.query("SELECT * FROM posts WHERE slug = $1", [slug]);
    return post[0] || null;
  });
}

export async function getUserProfile(userId) {
  const cacheKey = `user:profile:${userId}`;

  return multiLevelCache.get(cacheKey, async () => {
    const user = await db.query("SELECT * FROM users WHERE id = $1", [userId]);
    return user[0] || null;
  });
}

export async function invalidatePostCache(slug) {
  await multiLevelCache.delete(`post:${slug}`);
}

export async function invalidateUserCache(userId) {
  await multiLevelCache.delete(`user:profile:${userId}`);
}

会话缓存

javascript
// lib/session.js
import redisCache from "./redis.js";

const SESSION_TTL = 24 * 60 * 60; // 24 小时

export async function createSession(userId) {
  const sessionId = generateSessionId();
  const sessionData = {
    userId,
    createdAt: Date.now(),
    expiresAt: Date.now() + SESSION_TTL * 1000,
  };

  await redisCache.set(`session:${sessionId}`, sessionData, SESSION_TTL);
  return sessionId;
}

export async function getSession(sessionId) {
  const session = await redisCache.get(`session:${sessionId}`);
  if (!session) return null;

  // 检查是否过期
  if (session.expiresAt < Date.now()) {
    await redisCache.delete(`session:${sessionId}`);
    return null;
  }

  return session;
}

export async function destroySession(sessionId) {
  await redisCache.delete(`session:${sessionId}`);
}

function generateSessionId() {
  return `${Date.now()}-${Math.random().toString(36).substring(2)}`;
}

缓存失效策略

TTL 策略

javascript
// 不同数据使用不同的 TTL
const CACHE_TTL = {
  // 频繁更新但读取也多
  userSession: 60 * 60, // 1 小时

  // 配置类数据,更新不频繁
  siteConfig: 24 * 60 * 60, // 24 小时

  // 内容类数据
  popularPosts: 5 * 60, // 5 分钟
  postDetail: 30 * 60, // 30 分钟

  // 列表类数据
  categoryList: 10 * 60, // 10 分钟
  tagList: 60 * 60, // 1 小时
};

主动失效

javascript
// 发布文章时清除相关缓存
export async function publishPost(postId) {
  // 更新数据库
  await db.query("UPDATE posts SET published = true WHERE id = $1", [postId]);

  // 获取文章信息用于清除缓存
  const post = await db.query("SELECT slug FROM posts WHERE id = $1", [postId]);

  // 清除相关缓存
  await multiLevelCache.delete(`post:${post.slug}`);
  await multiLevelCache.delete("popular_posts"); // 清除热门文章缓存
  await multiLevelCache.delete("categories"); // 清除分类缓存(如果有变化)
}

最佳实践

缓存雪崩

javascript
// 使用随机 TTL 避免雪崩
function getRandomTTL(baseTTL, variance = 0.2) {
  const min = baseTTL * (1 - variance);
  const max = baseTTL * (1 + variance);
  return Math.floor(Math.random() * (max - min) + min);
}

// 使用互斥锁避免缓存击穿
export async function getWithLock(key, fetchFunc) {
  const value = await multiLevelCache.get(key, null);
  if (value !== null) return value;

  const lockKey = `lock:${key}`;
  const lock = await redisCache.lock(lockKey, 10);

  if (lock) {
    try {
      const value = await fetchFunc();
      await multiLevelCache.set(key, value);
      return value;
    } finally {
      await redisCache.unlock(lockKey, lock);
    }
  } else {
    // 等待其他进程加载
    await new Promise((resolve) => setTimeout(resolve, 100));
    return multiLevelCache.get(key, fetchFunc);
  }
}

缓存监控

javascript
// lib/cache/monitor.js
export async function getCacheStats() {
  const stats = {
    memory: memoryCache.getStats(),
    redis: await redisCache.get("stats:cache") || {},
  };

  return stats;
}

缓存优化效果

合理的缓存策略可以提升应用性能 10-100 倍,大幅降低数据库压力。

总结

使用 Claude Code 实现缓存系统:

  • 选择合适的缓存层(内存/Redis)
  • 设计合理的缓存键命名规则
  • 设置适当的 TTL 过期时间
  • 实现多级缓存提高命中率
  • 处理缓存雪崩和击穿问题
  • 监控缓存命中率并持续优化