指的是单个key在缓存中查不到,去数据库查询,这样如果数据量不大或者并发不大的话是没有什么问题的。
如果数据库数据量大并且是高并发的情况下那么就可能会造成数据库压力过大而崩溃
解决思路:
采用锁 + 双重检查机制:某个key只让一个线程查询,阻塞其它线程,在同步块中,继续判断检查,保证不存在,才去查DB。
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @ProjectName demo
* @ClassName App
* @Description TODO
* @Author Wang
* @Date 2020/6/3 9:25 上午
* @Version 1.0.0
**/
@Slf4j
public class App {
/**
* 模拟数据库数据
*/
private static List
一般是出现这种情况是因为恶意频繁查询才会对系统造成很大的问题: key缓存并且数据库不存在,
所以每次查询都会查询数据库从而导致数据库崩溃。
解决思路:
从DB中查询出来数据为空,也进行空数据的缓存,避免DB数据为空也每次都进行数据库查询,过期时间设置短一些
使用布隆过滤器,但是会增加一定的复杂度及存在一定的误判率(判断不存在肯定是不存在,判断存在可能会不存在)
布隆过滤器 (guava库 BloomFilter ,RedisBloom 主要是写一份 redis实现布隆过滤器,另外一个百度很多)
# 因为端口号6379已经在使用,改了下端口映射
docker run -d -p 7001:6379 --name redis-redisbloom redislabs/rebloom:latest
com.redislabs
jrebloom
1.2.0
import io.rebloom.client.Client;
import lombok.extern.slf4j.Slf4j;
/**
* @ProjectName demo
* @ClassName App2
* @Description TODO
* @Author WangDong
* @Date 2020/6/3 4:26 下午
* @Version 1.0.0
**/
@Slf4j
public class App2 {
/**
* 自定义过滤器
*/
private static final String NAME = "specialBloom";
/**
* 初始容量
*/
private static final long INIT_CAPACITY = 10000;
/**
* 错判率
*/
private static final double ERROR_RATE = 0.0001;
public static void main(String[] args) {
Client client = new Client("127.0.0.1", 7001);
//client.delete(NAME);
// 新建一个自定义过滤器
client.createFilter(NAME, INIT_CAPACITY, ERROR_RATE);
// 批量添加
client.addMulti(NAME, "foo", "bar", "baz", "bat", "bag");
String key = "foo";
// 判断key是否存在过滤器中 存在 true 不存在false
boolean result = client.exists(NAME, key);
log.info("判断 [{}]NAME过滤器中,结果为 -> [{}]", key, result);
}
}
17:48:00.131 [main] INFO com.example.demo.App2 - 判断key[foo]是否存在 [specialBloom] 过滤器中,结果为 -> [true]
雪崩指的是多个key查询并且出现高并发,缓存中失效或者查不到,然后都去db查询,从而导致db压力突然飙升,
从而崩溃。出现原因: 1 key同时失效, 2 redis本身崩溃了
- 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。(跟击穿的第一个方案类似,但是这样是避免不了其它key去查数据库,只能减少查询的次数)
- 实现redis高可用
- 不同的key,设置不同的过期时间,具体值可以根据业务决定,让缓存失效的时间点尽量均匀
Bloomfilter.js https://www.jasondavies.com/bloomfilter
Redis文档 https://oss.redislabs.com/redisbloom/
Java Client for RedisBloom https://github.com/RedisBloom/JRedisBloom