缓存穿透:
高并发的环境之下去查询缓存中没有的数据导致直接穿透缓存,给数据库造成极大的压力。
缓存雪崩:
给缓存设置了同样的失效时间,导致缓存同一时间失效,在某一个时间点给数据库造成极大的并发。
缓存击穿:
缓存击穿就是特别热点的数据在缓存设置时间失效之后被大量访问直接击穿缓存到数据库。
缓存穿透怎么解决:
解决方法1.缓存空的数据设置失效的时间。
解决方法2.配置一个布隆过滤器。
缓存雪崩怎么解决:
设置缓存的失效时间为一个随机值。
缓存击穿怎么解决:
单台服务器:本地锁;sychronize JUC(lock)
多台服务器:分布式锁 ·redisson解决分布式锁的问题
方案1.简易的分布式锁实现
加锁和解锁保证原子性,缓存和操作数据库保证在锁里面,加锁的时候必须使用原子性的setNX方法
解锁的时候可以使用lua脚本编写。(这是redis官网提到可以实现的简易分布式锁)
方案2.Redisson实现分布式锁
最佳实践方法就是
给锁设置一个过期的时间,再去写try catch语句。
缓存的一致性问题:
对数据的实时性要求不高的情境之下就用缓存削峰
缓存一致性的问题:
1.缓存设置过期时间(不设置过期时间但是用cannel监控mysql的binlog日志更新数据库)
2.双写模式:先删缓存再更新数据库
这两种方式在多线程的场景下也会有bug出现
有读到脏数据的可能性所以加上读写锁可以解决这种问题,但是对性能的限制也是大的。
读写锁不适用于经常读写多的引用场景,但是对读多写少的场景问题不是很大
*****缓存就是用来抗并发的****:
*****所以使用了缓存就有可能出现缓存数据的一致性问题。所以在实时性要求不高的场景,并且允许读取到脏数据的情况下:定义一个较短的超时时间、写数据库的时候更新缓存都是最优解、延时双删。
*****在实时性要求高的场景,就只能损耗性能:
方案1.加上读写锁:写时有锁、读时无锁。适用于读多写少的情况。(但读写锁是本地锁只能锁住当前进程,在分布式环境下还是会出现脏数据的读取)
spring cache简化开发使用:
可以使用Springcache简化redis开发,直接存进缓存里面