您现在的位置是:网站首页 > 缓存策略文章详情
缓存策略
陈川
【
Node.js
】
65227人已围观
4485字
缓存策略的基本概念
缓存策略是提升应用性能的关键手段之一,通过减少重复计算或数据请求来优化响应速度。在Node.js中,缓存可以应用于多个层面,包括内存缓存、分布式缓存以及HTTP缓存等。不同的场景需要不同的策略,合理选择能显著降低服务器负载并提高用户体验。
内存缓存
内存缓存是最简单的缓存形式,数据直接存储在进程内存中。Node.js的Map
或普通对象常被用作内存缓存容器。例如:
const cache = new Map();
function getData(key) {
if (cache.has(key)) {
return cache.get(key);
}
const data = fetchDataFromDB(key); // 模拟耗时操作
cache.set(key, data);
return data;
}
这种方式的优点是速度快,但缺点也很明显:进程重启后缓存会丢失,且不适合多实例部署的场景。
缓存过期与淘汰策略
时间过期(TTL)
通过设置缓存项的存活时间(Time To Live)自动失效:
const cache = new Map();
function setWithTTL(key, value, ttl) {
cache.set(key, {
value,
expire: Date.now() + ttl
});
}
function getWithTTL(key) {
const item = cache.get(key);
if (!item || item.expire < Date.now()) {
cache.delete(key);
return null;
}
return item.value;
}
LRU算法
当缓存空间不足时,Least Recently Used算法会优先淘汰最久未使用的数据:
class LRUCache {
constructor(maxSize) {
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) {
this.cache.delete(this.cache.keys().next().value);
}
this.cache.set(key, value);
}
}
分布式缓存
对于多实例部署的场景,需要使用Redis或Memcached等分布式缓存方案:
const redis = require('redis');
const client = redis.createClient();
async function getProduct(id) {
const cacheKey = `product:${id}`;
const cachedData = await client.get(cacheKey);
if (cachedData) return JSON.parse(cachedData);
const dbData = await fetchFromDatabase(id);
await client.setEx(cacheKey, 3600, JSON.stringify(dbData)); // 1小时过期
return dbData;
}
HTTP缓存策略
强制缓存
通过Cache-Control头实现:
app.get('/static/image.jpg', (req, res) => {
res.setHeader('Cache-Control', 'public, max-age=31536000');
res.sendFile('image.jpg');
});
协商缓存
使用ETag或Last-Modified:
app.get('/data', async (req, res) => {
const data = await fetchData();
const etag = generateETag(data);
if (req.headers['if-none-match'] === etag) {
return res.status(304).end();
}
res.setHeader('ETag', etag);
res.json(data);
});
缓存穿透与雪崩防护
布隆过滤器
防止缓存穿透的典型方案:
const { BloomFilter } = require('bloom-filters');
const filter = new BloomFilter(1000, 0.01);
// 预热合法键
validKeys.forEach(key => filter.add(key));
function getData(key) {
if (!filter.has(key)) return null; // 快速拦截非法请求
// ...正常缓存逻辑
}
缓存预热与错峰过期
防止雪崩的解决方案:
// 启动时预热
async function warmUpCache() {
const hotData = await getHotDataFromDB();
await Promise.all(
hotData.map(item =>
client.setEx(`item:${item.id}`,
Math.floor(3600 + Math.random() * 600), // 随机过期时间
JSON.stringify(item))
)
);
}
多级缓存架构
大型系统常采用多级缓存策略:
async function getDataWithMultiCache(id) {
// 1. 检查内存缓存
const memCached = localCache.get(id);
if (memCached) return memCached;
// 2. 检查Redis缓存
const redisCached = await redisClient.get(`data:${id}`);
if (redisCached) {
localCache.set(id, redisCached); // 回填内存缓存
return redisCached;
}
// 3. 查询数据库
const dbData = await db.query('SELECT * FROM data WHERE id = ?', [id]);
// 异步更新缓存
redisClient.setEx(`data:${id}`, 300, JSON.stringify(dbData));
localCache.set(id, dbData);
return dbData;
}
缓存一致性处理
双删策略
async function updateData(id, newData) {
// 先删缓存
await redisClient.del(`data:${id}`);
// 更新数据库
await db.update('data', newData, { where: { id } });
// 延迟后再删一次
setTimeout(async () => {
await redisClient.del(`data:${id}`);
}, 1000);
}
发布订阅模式
// 更新数据时发布消息
redisClient.publish('cache-invalidate', `data:${id}`);
// 其他服务订阅
redisClient.subscribe('cache-invalidate', (channel, key) => {
localCache.delete(key.split(':')[1]);
});
性能监控与调优
缓存命中率监控示例:
const cacheStats = {
hits: 0,
misses: 0
};
function getDataWithStats(key) {
if (cache.has(key)) {
cacheStats.hits++;
return cache.get(key);
}
cacheStats.misses++;
// ...正常获取逻辑
}
// 定时上报指标
setInterval(() => {
const hitRate = cacheStats.hits / (cacheStats.hits + cacheStats.misses);
metrics.report('cache.hit_rate', hitRate);
}, 60000);