文章目录
Java缓存的一些使用和体会
公司用到的本地缓存
https://github.com/PhantomThief/zknotify-cache
一直以为用的公司提供的本地缓存是封装的别的缓存模块。结果找到GitHub上一看,这个本地缓存是公司大佬写得一个。瞬间佩服之至,先把源码下下来,回头把这个源码分析一波。
Redis的缓存
一般情况下,针对大型的使用场景,我目前用的最多的缓存方案就两种,第一种是上面提到的本地缓存。第二种就是Redis,Redis就不用说了,非常优秀。针对数据库缓存的话Redis主要的实现方法是,先查Redis,如果有则返回,没有则到数据库里面去查找。有的话返回并且写入到Redis。具体流程:
redis缓存穿透
为什么会出现
正常情况下,我们去查询数据都是存在。
那么请求去查询一条压根儿数据库中根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。
这种查询不存在数据的现象我们称为缓存穿透。
后果
如果产生大量的缓存穿透现象,会给数据库造成大量的压力,加不加缓存都没用了。
怎么办
1. 缓存空值
之所以会发生穿透,就是因为缓存中没有存储这些空数据的key。从而导致每次查询都到数据库去了。那么我们就可以为这些key对应的值设置为null 丢到缓存里面去。后面再出现查询这个key 的请求的时候,直接返回null 。这样,就不用在到数据库中去走一圈了,但是别忘了设置过期时间。
2. BloomFilter
缓存击穿
在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。会造成某一时刻数据库请求量过大,压力剧增。
解决方案
上面的现象是多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。
其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。
缓存雪崩
缓存雪崩的情况是说,当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上面。结果就是DB 称不住,挂掉。
解决热点数据集中失效问题
我们在设置缓存的时候,一般会给缓存设置一个失效时间,过了这个时间,缓存就失效了。
对于一些热点的数据来说,当缓存失效以后会存在大量的请求过来,然后打到数据库去,从而可能导致数据库崩溃的情况。
为了避免这些热点的数据集中失效,那么我们在设置缓存过期时间的时候,我们让他们失效的时间错开。比如在一个基础的时间上加上或者减去一个范围内的随机值。
结合上面的击穿的情况,在第一个请求去查询数据库的时候对他加一个互斥锁,其余的查询请求都会被阻塞住,直到锁被释放,从而保护数据库。