缓存击穿介绍
什么是缓存击穿
我们通常使用redis作为数据缓存,当请求进来时先通过key去redis缓存查询,如果缓存中数据不存在,需要去查询数据库的数据。当数据库和缓存中都不存在的数据来查询时候,请求都打在数据库的请求中。如果这种请求量很大,会给数据库造成更大的压力进而影响系统的性能。
解决这类问题的方法
方法一:当DB和redis中都不存在
key
,在DB返回null
时,在redis中插入<key,null,expireTime>
当key
再次请求时,redis直接返回null
,而不用再次请求DB。
方法二:使用redis提供的
redisbloom
,同样是将存在的key放入到过滤器中。当请求进来时,先去过滤器中校验是否存在,如果不存在直接返回null
。
过滤器用途
- 判断过滤器中是否存在该数据进而减少没有必要的数据库请求
引入redisbloom
官方文档上面提供docker安装redisbloom和下载编译的方式引入redisbloom的模块。
下面介绍一下编译的方式来引入redisbloom模块
git clone https://github.com/RedisLabsModules/redisbloom.git
cd redisbloom
make # 编译redisbloom
启动redis-server时引入redisbloom模块
./redis-5.0.4/src/redis-server --loadmodule ./redisbloom/rebloom.so
在redis.conf中配置
loadmodule ../redisbloom/rebloom.so
bloom 指令
bf.reserve {key} {error_rate} {size}
127.0.0.1:6379> bf.reserve userid 0.01 100000
OK
- 描述:
创建一个空的布隆过滤器,并设置一个期望的错误率和初始大小。{error_rate}
过滤器的错误率在0-1之间,如果要设置0.1%,则应该是0.001。该数值越接近0,内存消耗越大,对cpu利用率越高。
bf.add {key} {item}
bf.madd {key} {item} [item…]
- 描述:往过滤器中添加元素。如果key不存在,过滤器会自动创建。
127.0.0.1:6379> bf.add userid '101310299'
(integer) 1
127.0.0.1:6379> bf.madd userid '101310299' '101310366' '101310211'
1) (integer) 0
2) (integer) 1
3) (integer) 1
bf.exists {key} {item}
bf.mexists {key} {item} [item…]
- 描述:判断过滤器中是否存在该元素,不存在返回0,存在返回1。
127.0.0.1:6379> bf.exists userid '101310299'
(integer) 1
127.0.0.1:6379> bf.mexists userid '101310299' '10saa' '101310211'
1) (integer) 1
2) (integer) 0
3) (integer) 1
java API
java程序员可以通过RedisBloom类库提供的API实现高性能布隆过滤器
maven引入类库
<dependency>
<groupId>com.redislabs</groupId>
<artifactId>jrebloom</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.0</version>
</dependency>
API使用
public class RedisBloomDemo {
public static void main(String[] args) {
String userIdBloomKey = "userid";
// 创建客户端,jedis实例
Client client = new Client("localhost", 6378);
// 创建一个有初始值和出错率的过滤器
client.createFilter(userIdBloomKey,100000,0.01);
// 新增一个<key,value>
boolean userid1 = client.add(userIdBloomKey,"101310222");
System.out.println("userid1 add " + userid1);
// 批量新增values
boolean[] booleans = client.addMulti(userIdBloomKey, "101310111", "101310222", "101310222");
System.out.println("add multi result " + booleans);
// 某个value是否存在
boolean exists = client.exists(userIdBloomKey, "101310111");
System.out.println("101310111 是否存在" + exists);
//某批value是否存在
boolean existsBoolean[] = client.existsMulti(userIdBloomKey, "101310111","101310222", "101310222","11111111");
System.out.println("某批value是否存在 " + existsBoolean);
}
}
遇到一个坑
jrebloom项目中使用的jedis是3.0.0-m1
,而自己项目中引入的jedis是2.9.0
。
而且发现3.0.0以上版本有些方法找不到了。例如set(String key, String value, String nxxx, String expx, long time)
。
因此如果要在项目中使用redisbloom,要注意jedis的版本信息。
参考文献:
https://oss.redislabs.com/redisbloom/Bloom_Commands/
https://github.com/RedisBloom/JReBloom
https://blog.csdn.net/zeb_perfect/article/details/54135506