本地-NGINX-Redis-TomCat-SQL#
缓存问题#
缓存雪崩#
当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。
- 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
- 重建缓存加互斥锁,当线程拿到缓存发现缓存不存在就会尝试加锁,线程争抢锁,拿到锁的线程就会进行查询数据库,然后重建缓存,争抢锁失败的线程,你可以加一个睡眠然后循环重试
缓存击穿#
如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
- 发现缓存失效,重建缓存加互斥锁,当线程查询缓存发现缓存不存在就会尝试加锁,线程争抢锁,拿到锁的线程就会进行查询数据库,然后重建缓存
- 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;
缓存穿透#
既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。
- 第一种方案,非法请求的限制;
- 第二种方案,缓存空值或者默认值;
- 第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在;查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据
缓存一致性#
- 更新MySQL即可,不管Redis,完全以过期时间兜底
- 更新MySQL之后,操作Redis,当然要考虑到Redis更新操作可能会因为网络、进程重启等各种原因失败,所以过期时间兜底还是少不了。
- 异步将MySQL的更新刷入到Redis,比如先更新mysql,通过订阅mysql的binlog记录来异步执行更新redis的操作
