一、概述
防止缓存穿透有多种方法,如布隆过滤器(Bloom Filter)、缓存空值或默认值,限制访问频率、数据合法性校验、使用数据库层面的保护等。本文主要介绍了BloomFilter在缓存穿透场景的使用,包括单机模式与分布式模式下BloomFilter使用的代码实现、BloomFilter优缺点分析等,如有疑问欢迎讨论沟通。
1. 什么是缓存穿透
缓存穿透是指查询一个缓存和数据库中都不存在的数据,导致每次查询都直接打到数据库,给数据库带来压力。
(另一个概念,缓存击穿(Cache Breakdown)是缓存中没有,但数据库中有的数据被大量并发请求查询时,这些请求都会直接落到数据库上,导致数据库瞬间压力过大甚至崩溃。通常是热点缓存数据过期或缓存被误删除之后发生)
2. 防止缓存穿透有哪些策略
- 布隆过滤器(Bloom Filter):布隆过滤器是一种空间效率很高的概率型数据结构,用于判断一个元素是否在一个集合中。它允许存在一定的误判率,但不会漏判。在数据放入缓存之前,先使用布隆过滤器进行判断,如果该数据不存在于布隆过滤器中,则直接返回,不进行数据库查询。布隆过滤器可以显著减少缓存穿透攻击。
- 缓存空值或默认值:当数据库查询结果为空时,也将这个空结果(或默认值)缓存起来,并设置一个较短的过期时间。这样,当再次查询这个不存在的数据时,可以直接从缓存中返回空结果,而不会再次查询数据库。但是,这种方法需要合理设置过期时间,避免缓存中长时间存储大量无用的空值或默认值。
- 使用更复杂的key:对于某些场景,可以通过改变查询的key来避免缓存穿透。比如,对用户的查询加上用户ID作为前缀,或者对查询的参数进行加密、哈希等处理,确保每个查询的key都是唯一的,从而避免恶意构造不存在的key进行攻击。
- 限制访问频率:通过IP地址、用户ID等维度对访问频率进行限制。当某个IP或用户查询不存在数据的次数达到阈值时,暂时禁止其继续查询,从而保护系统不被过度请求压垮。
- 数据合法性校验:在查询之前,先对数据的合法性进行校验,比如检查用户ID、商品ID等是否合法。对于不合法的查询,直接返回错误,不进行后续处理。
- 使用数据库层面的保护:在数据库层面,可以通过设置合理的索引、使用查询优化技术等方式,提高数据库查询的效率,减少查询时间,从而间接减少缓存穿透对数据库的影响。
二、布隆过滤器防止缓存穿透
布隆过滤器可以帮助你快速判断一个元素是否一定不存在于集合中(注意是“一定不存在”,而不是“一定存在”,因为布隆过滤器存在误判率)
Guava库中布隆过滤器使用(单机版本)
1. 引入布隆过滤器库
布隆过滤器的库比较流行的有Google的Guava库中的布隆过滤器实现,或者你可以使用其他第三方库,如bloom-filter
。
<dependency>
<groupId>com.google.guava</groupId