一、缓存穿透的解决方案
为了演示缓存穿透,这里设置的redis是单机单实例。
二、缓存穿透之布隆过滤器
布隆过滤器能够迅速判断一个元素是否存在于集合里。
布隆过滤器缺点:
1.会有1%的误判率,误判概率越低,数组所占用的空间越长。
2.布隆过滤器的数据只能添加,不能移除,主要是由于多个数据可能存在于同一个位置,比如subCat:2、subCat:3。
3.维护起来比较麻烦,代码复杂。
三、缓存雪崩与预防
1.什么是缓存雪崩?
当在同一时刻缓存里有大量的key过期时间结束,此时有大量过期的key请求,这时就会有大量的请求落到数据库,数据库承载不了这么大的数据访问,就会宕机。
2.雪崩预防
对于雪崩来说,我们不可能完全解决,只能对它预防,缓解雪崩的现象
预防方法如下:
(1)永不过期
(2)过期时间错开
比如热点数据可以把过期时间设置久一点,或者永不过期;其他不长访问的数据的过期时间设置短一点;在设置过期时间时,比如设置1小时过期,精确到毫秒就是1*60*60*1000,那么就可以在1分钟之内(60*1000)取随机数,每次在1小时的基础上加或减随机数。
(3)多缓存结合(多级缓存)
Memcache中的key过期时间设置的比redis的过期时间长,这样的话,redis中的key过期了就会去查Memcache
(4)采购第三方Redis
第三方服务还是很牛的,不用自己维护,减少运维成本。
阿里云Redis
HA:就相当于哨兵形式,SlaveN:有很多slave节点,都是哨兵模式
四、缓存穿透和缓存雪崩的区别
穿透是单个的key不存在于redis,雪崩是指大面积的key失效;两者都是由于超高流量的并发打在数据库上,造成数据库不可用。
五、multiGet 批量查询优化
每次get查询,其实就是建立一个连接,等get之后,再关闭连接。(socket通信),这样是会有IO损耗的,我们实现mget,这样对于批量查询,只建立一次连接。
/**
* 批量查询,对应mget
* @param keys
* @return
*/
public List<String> mget(List<String> keys) {
return redisTemplate.opsForValue().multiGet(keys);
}
六、pipeline 批量查询优化
除了用mget批量查询,还可以用管道。
就如keepalive对nginx的作用:建立一次连接,pipeline对redis的作用也是建立一次连接,可以在管道内部进行很多类型的操作,如get,mget,range,set,mset等
/**
* 批量查询,管道pipeline
* @param keys
* @return
*/
public List<Object> batchGet(List<String> keys) {
// nginx -> keepalive
// redis -> pipeline
List<Object> result = redisTemplate.executePipelined(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
StringRedisConnection src = (StringRedisConnection)connection;
for (String k : keys) {
src.get(k);
}
return null;
}
});
return result;
}
为什么实现了mget方法,还要实现pipeline方法批量查询?
因为pipeline支持更多类型的操作,set,get,mget,mset,range等,不仅仅支持String类型,其他类型也支持。