在前端开发中,使用缓存技术是非常常见的。但是,由于缓存数据的有限性,缓存穿透是一个不可避免的问题。缓存穿透是指在缓存中找不到所需数据,导致请求一直访问数据库,使服务器负载过高的情况。这篇文章将介绍 Redis 如何防止缓存穿透问题。
Redis 原理
Redis 是一种基于内存的 key-value 存储系统。它可以存储字符串、列表、集合、哈希等数据结构。Redis 的优点是速度快、可扩展、支持多种数据结构等。
在 Redis 中,缓存数据会被存储在内存中。当客户端请求数据时,Redis 首先会从内存中查找缓存数据。如果找到了,就直接返回数据给客户端。如果没有找到,Redis 会从数据库中查询数据,并将查询结果存储在缓存中。下次客户端请求相同的数据时,Redis 就可以直接返回缓存数据,而不需要再次查询数据库。
缓存穿透问题
缓存穿透是指当客户端请求一个不存在的数据时,Redis 会从数据库中查询数据,但查询结果为空,导致客户端一直请求数据库,使服务器负载过高。这种情况一般是由恶意攻击者构造的请求,目的是让服务器崩溃。
解决方案
布隆过滤器
布隆过滤器是一种数据结构,用于判断一个元素是否在一个集合中。它可以高效地判断一个元素是否在集合中,但无法保证判断结果的准确性。布隆过滤器的原理是将每个元素映射成多个哈希值,然后将哈希值对应的位设置为 1。判断一个元素是否在集合中时,将该元素映射成多个哈希值,然后判断对应的位是否都为 1。
使用布隆过滤器可以将一部分不存在的数据过滤掉,减少对数据库的访问。但是,由于布隆过滤器无法保证判断结果的准确性,会有一定的误判率。
缓存空对象
缓存空对象是指将数据库中不存在的数据存储在缓存中,防止缓存穿透。当客户端请求不存在的数据时,Redis 会从缓存中返回空对象,而不需要访问数据库。如果客户端在一段时间内多次请求不存在的数据,Redis 就可以直接返回缓存中的空对象,而不需要再次查询数据库。
设置过期时间
设置缓存数据的过期时间可以有效地减少缓存穿透的问题。当客户端请求不存在的数据时,Redis 会从缓存中返回空对象,并设置一个较短的过期时间。这样,在过期时间内,客户端再次请求相同的数据时,Redis 就可以直接返回缓存数据,而不需要再次查询数据库。
限制请求频率
限制请求频率可以有效地防止缓存穿透。当客户端请求数据时,先判断该请求是否符合要求。如果请求频率过高,就拒绝请求。这样可以有效地减少对数据库的访问。
示例代码
// www.javascriptcn.com code example
const Redis = require('redis');
const client = Redis.createClient();
function getData(key) {
return new Promise((resolve, reject) => {
client.get(key, (err, data) => {
if (err) {
reject(err);
} else if (data) {
resolve(JSON.parse(data));
} else {
// 缓存数据不存在,从数据库中查询数据
const result = db.query(key);
if (result) {
// 将查询结果存储到缓存中,设置过期时间为 10 分钟
client.setex(key, 600, JSON.stringify(result));
resolve(result);
} else {
// 数据不存在,将空对象存储到缓存中,设置过期时间为 1 分钟
client.setex(key, 60, JSON.stringify({}));
resolve(null);
}
}
});
});
}在上面的代码中,当客户端请求数据时,先从缓存中查找数据。如果缓存中存在数据,则直接返回数据。如果缓存中不存在数据,则从数据库中查询数据,并将查询结果存储到缓存中。如果查询结果为空,则将空对象存储到缓存中。在存储数据时,设置不同的过期时间,以避免缓存穿透问题。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d1e0f9a941bf71343d301f