目录
Redis 缓存
引入了缓存层,就会有缓存异常的三个问题,分别是缓存雪崩、缓存击穿、缓存穿透。
它们的区别如下:
缓存击穿
场景
高并发流量场景下,大量请求同时访问一个热点数据,该热点数据在数据库中存在,但是, Redis 中缓存的数据已经过期了,这时,一瞬间就会有大量的请求同时打到数据库上,导致数据库宕机。
解决方案:
应对缓存击穿可以如下方案:
- 对于热点数据,我们不设置过期时间,或者过期时间设置随机值;
热点数据不设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间。
-
将热点数据,提前预热到缓存中;
-
互斥锁方案
保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
-
后台线程更新
业务线程不更新缓存,通过后台线程监控数据库变化,发生变化就将数据更新到缓存中,如:Canal。
缓存穿透
场景
高并发流量场景下,当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据。由于没办法构建缓存数据,导致大量的这样的请求同时打到数据库上,导致数据库宕机。
解决方案
应对缓存穿透可以如下方案:
-
缓存空值
-
布隆过滤器
在数据写入数据库的同时将这个 ID 同步到到布隆过滤器中,当请求的 id 不存在布隆过滤器中则说明该请求查询的数据一定没有在数据库中保存,就不要去数据库查询了。
BloomFilter 的算法是,首先分配一块内存空间做 bit 数组,数组的 bit 位初始值全部设为 0。
加入元素时,采用 k 个相互独立的 Hash 函数计算,然后将元素 Hash 映射的 K 个位置全部设置为 1。
检测 key 是否存在,仍然用这 k 个 Hash 函数计算出 k 个位置,如果位置全部为 1,则表明 key 存在,否则不存在。
如下图所示:
哈希函数会出现碰撞,所以布隆过滤器会存在误判。
这里的误判率是指,BloomFilter 判断某个 key 存在,但它实际不存在的概率,因为它存的是 key 的 Hash 值,而非 key 的值。所以有概率存在这样的 key,它们内容不同,但多次 Hash 后的 Hash 值都相同。
对于 BloomFilter 判断不存在的 key ,则是 100% 不存在的,反证法,如果这个 key 存在,那它每次 Hash 后对应的 Hash 值位置肯定是 1,而不会是 0。布隆过滤器判断存在不一定真的存在。
缓存雪崩
场景
当 大量缓存数据在同一时间过期(失效) 或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。
出现该原因主要有两种:
-
大量热点数据同时过期,导致大量请求需要查询数据库并写到缓存;
-
Redis 故障宕机,缓存系统异常。
解决方案
大量数据同时过期
应对大量数据同时过期,可以采用如下方案:
-
过期时间添加随机值;
-
互斥锁方案;
当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,就加个互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到 Redis 里),当缓存构建完成后,再释放锁。未获取到互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
实现互斥锁的时候,一定要设置超时时间,避免拿到锁的请求因为发生了某种异常,而一直阻塞,一直不释放锁,而其他请求也一直拿不到锁,导致整个系统就出现无响应的现象。
-
接口限流
当访问的不是核心数据的时候,在查询的方法上加上接口限流保护。
Redis 故障宕机
应对 Redis 故障宕机,可以采用如下方案:
-
服务熔断和接口限流;
-
熔断
如果 Redis 发生故障时,可以启动服务熔断机制,暂停业务应用对缓存服务的访问,直接返回错误,不用再继续访问数据库,从而降低对数据库的访问压力,保证数据库系统的正常运行,然后,等到 Redis 恢复正常后,再允许业务应用访问缓存服务。
-
限流
只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务。
-
-
构建高可用缓存集群系统。
缓存系统一定要构建一套 Redis 高可用集群,如果 Redis 的主节点故障宕机了,从节点还可以切换成为主节点,继续提供缓存服务,避免了由于缓存实例宕机而导致的缓存雪崩问题。
参考:
标签:缓存,请求,宕机,过期,数据库,Redis,失效 From: https://www.cnblogs.com/larry1024/p/17337424.html