文章目录
缓存穿透问题表面上看似复杂,实际上它的本质非常简单:当请求数据库中不存在的数据时,由于 Redis 缓存中没有缓存这些结果,查询每次都会直接穿透到数据库。这种情况可能源于恶意攻击或不合理的查询设计。如果不加以控制,将对数据库造成巨大压力,影响系统性能。
常见的解决方案
方案一:ID 校验(检查 ID 是否小于零)
一个直接有效的方案是对传入的 ID 进行简单校验,例如判断 ID 是否小于 0。因为在大多数应用场景中,数据的 ID 通常为非负数。如果 ID 小于零,则可以直接返回错误或空结果。这种方式能够有效减少无效请求穿透缓存和数据库,减轻系统负担。
public boolean isValidId(int id) {
return id >= 0;
}
方案二:缓存空结果
另一种常见的方案是将数据库查询结果为空的情况也缓存到 Redis 中,并设置一个较短的过期时间(例如 5 分钟)。这种方式在一定程度上可以避免重复查询同一个不存在的键值。但是,当大量不同的无效 ID 请求出现时,Redis 会存储大量空数据,从而增加缓存的存储压力,导致 Redis 性能下降。
public void cacheEmptyResult(String key) {
// 假设我们有一个 Redis 工具类 RedisUtil
RedisUtil.set(key, "", 300); // 缓存空值,过期时间为300秒
}
进阶方案:列表验证合法性
在某些复杂场景下,我们可以维护一个合法 ID 列表,查询时先检查这个 ID 是否在合法列表中,如果不在则直接返回错误。这种方式在过滤无效请求方面非常有效,可以极大减少对数据库的访问。
然而,维护如此大规模的 ID 列表是非常耗费内存的,尤其是当系统中存在大量数据时。例如淘宝的商品总量在2011年就已超过10亿个,维护一个如此庞大的列表会带来巨大的内存开销和管理复杂性。
public boolean isIdInValidList(int id, Set<Integer> validIds) {
return validIds.contains(id);
}
使用 Bitmap 优化存储空间
为了优化存储空间,可以使用 Bitmap 结构替代传统列表。Bitmap 是一种高效的位存储结构,特别适合需要存储大量布尔值的场景。其基本思想是将每个合法的数据库 ID 映射到 Bitmap 的某个位上。
具体而言,我们可以通过哈希函数 id % bitmap.size
计算出 ID 在 Bitmap 中的位置,并将该位置的值置为 1,表示该 ID 存在。请求数据时,系统先计算请求 ID 在 Bitmap 中的位置,如果该位为 0,表示该 ID 不存在,可以直接返回结果,避免了对数据库的查询。
Java 实现示例:
import java.util.BitSet;
public class CachePenetrationSolution {
private BitSet bitMap;
private int size;
public CachePenetrationSolution(int size) {
this.size = size;
this.bitMap = new BitSet(size);
}
// 将有效ID标记到Bitmap中
public void addToBitmap(int id) {
int index = id % size;
bitMap.set(index);
}
// 检查ID是否存在于Bitmap中
public boolean isIdInBitmap(int id) {
int index = id % size;
return bitMap.get(index);
}
public static void main(String[] args) {
CachePenetrationSolution solution = new CachePenetrationSolution(1000000);
// 将一些有效ID加入Bitmap
solution.addToBitmap(1001);
solution.addToBitmap(1002);
// 查询ID是否存在
System.out.println(solution.isIdInBitmap(1001)); // true
System.out.println(solution.isIdInBitmap(9999)); // false
}
}
优化提示:结合布隆过滤器减少误判
虽然 Bitmap 非常高效,但它也会带来一些误差。由于哈希函数存在碰撞的可能性,不同的 ID 可能会映射到同一个 Bitmap 位置,导致误判。为了解决这一问题,可以引入布隆过滤器(Bloom Filter),其通过多个哈希函数有效减少误判率,从而进一步提升系统的准确性和效率。
方案总结
缓存穿透问题虽然看似简单,但实际解决过程需要我们针对不同场景选择合适的方案。基础方案如 ID 校验和缓存空值可以解决部分问题,而在面对大规模数据的情况下,Bitmap 提供了一种高效的解决方法。结合布隆过滤器进一步优化后,不仅能够降低存储空间占用,还能有效减少误判,极大提高系统的性能和稳定性。
标签:缓存,id,穿透,ID,Bitmap,public,size From: https://blog.csdn.net/Takumilove/article/details/143144839