这个问题是由于热点缓存数据过期而发生的。
有时候如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,同时设置缓存的情况,如果并发确实很大,这也可能造成DB压力过大,还有缓存频繁更新的问题。
单实例下可使用同步锁,如果多实例考虑分布式锁实现方式
List<Map> userinfo = (List<Map> ) redisTemplate.opsForValue().get("userInfo"); //双重校验防止缓存击穿 if(userinfo==null){ synchronized (this) { userinfo = (List<Map> ) redisTemplate.opsForValue().get("userInfo"); if(userinfo ==null){ userinfo = acceptTempDao.getServiceInfo(); redisTemplate.opsForValue().set("userInfo", userinfo, 120, TimeUnit.SECONDS); System.out.println("请求的数据库。。。。。。"); } else { System.out.println("请求的缓存。。。。。。"); } } } else { System.out.println("请求的缓存。。。。。。"); }就是缓存不设置过期时间,但是增加缓存逻辑过期时间字段,在获取缓存代码逻辑中判断逻辑时间过期时异步更新缓存,仍返回本次拿到的结果。
这种方式不保证缓存的一致性,适用于缓存实时性不高且更新缓存耗时耗性能的情况。
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决办法:
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击布隆过滤器过滤无效请求