缓存

缓存技术在微服务架构中扮演着重要角色,能够显著提升系统性能和扩展性。以下以 Node.js 为例,从不同层次介绍缓存技术的应用场景和实现方式:


一、缓存层级与应用场景

1. 客户端缓存

1
2
3
4
5
// Express 设置 HTTP 缓存头
app.get('/products/:id', (req, res) => {
res.set('Cache-Control', 'public, max-age=3600'); // 浏览器缓存1小时
// ...返回数据
});
  • 场景:静态资源、低频变动的 API 响应
  • 工具:HTTP 头(ETag, Last-Modified)、Service Worker

2. API 网关缓存

1
2
3
4
5
6
7
8
// 使用 Redis 实现网关层缓存
const redis = new Redis();
const cacheMiddleware = async (req, res, next) => {
const key = req.originalUrl;
const cachedData = await redis.get(key);
if (cachedData) return res.json(JSON.parse(cachedData));
// ...后续处理并存储到 Redis
};
  • 场景:高频读请求(如商品详情页)
  • 工具:Redis、Memcached、Nginx 缓存

3. 服务层缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用内存缓存库(node-cache)
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 });

function getProduct(id) {
const key = `product_${id}`;
let product = cache.get(key);
if (!product) {
product = await db.query('SELECT * FROM products WHERE id = ?', [id]);
cache.set(key, product);
}
return product;
}
  • 场景:服务内部高频数据(配置信息、热点数据)
  • 工具:node-cache、lru-cache

4. 数据库缓存

1
2
3
4
5
// Sequelize 查询缓存
const result = await Product.findAll({
where: { category: 'electronics' },
cache: true // 启用查询缓存
});
  • 场景:复杂查询结果缓存
  • 工具:MySQL Query Cache、MongoDB 缓存引擎、ORM 内置缓存

二、典型应用案例

1. 会话状态缓存

1
2
3
4
5
6
7
8
9
10
11
// 使用 Redis 存储 JWT 会话
const storeToken = (userId, token) => {
redis.setex(`session:${userId}`, 3600, token);
};

// 验证中间件
const verifySession = async (req, res, next) => {
const token = await redis.get(`session:${req.userId}`);
if (!token) throw new Error('Invalid session');
// ...JWT 验证
};

2. 分布式锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 使用 Redis 实现分布式锁
const acquireLock = async (key, ttl=10) => {
const result = await redis.set(key, 'LOCK', 'PX', ttl*1000, 'NX');
return result === 'OK';
};

// 使用示例
if (await acquireLock('order:123')) {
try {
// 处理订单
} finally {
await redis.del('order:123');
}
}

3. 热点数据预加载

1
2
3
4
5
// 定时任务预加载热门商品
cron.schedule('*/5 * * * *', async () => {
const hotProducts = await getTop10Products();
redis.set('hot_products', JSON.stringify(hotProducts), 'EX', 300);
});

三、缓存策略与注意事项

  1. 失效策略

    • TTL 自动过期(适合最终一致性场景)
    • 主动失效(通过 Pub/Sub 广播更新事件)
      1
      2
      3
      // 数据更新时清除缓存
      redis.publish('cache_invalidate', 'product_123');
      // 订阅端监听并删除对应缓存
  2. 防雪崩策略

    • 随机过期时间(避免同时失效)
    • 互斥锁防止缓存击穿
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      async function getWithMutex(key, fetchData, ttl) {
      const value = await redis.get(key);
      if (value) return value;

      const lockKey = `${key}_lock`;
      if (await redis.set(lockKey, 1, 'PX', 1000, 'NX')) {
      try {
      const data = await fetchData();
      await redis.set(key, data, 'PX', ttl);
      return data;
      } finally {
      await redis.del(lockKey);
      }
      } else {
      await sleep(50);
      return getWithMutex(key, fetchData, ttl);
      }
      }
  3. 监控指标

    • 缓存命中率(Hit Ratio)
    • 缓存大小和内存使用量
    • 缓存操作延迟

四、Node.js 推荐工具链

  1. 内存缓存node-cachelru-cache
  2. 分布式缓存ioredis(Redis)、memcached
  3. HTTP 缓存apicache 中间件
  4. 监控工具:RedisInsight、Prometheus + Grafana

通过合理应用缓存技术,可以在以下方面获得显著收益:

  • API 响应时间降低 50%-90%
  • 数据库负载减少 60% 以上
  • 系统横向扩展能力提升
  • 应对突发流量的弹性增强

实际应用中需要根据数据特性(读写比例、一致性要求)选择合适的缓存策略,并配合监控系统持续优化。