缓存击穿
Redis中的热点数据失效,在数据从MySQL写到Redis的过程有大量请求访问这个数据,导致大量请求直接到达数据库,导致数据库奔溃,服务不可用。
解决方案
过期时间 + 随机值:过期时间 = baes 时间+随机时间。
对于热点数据,我们不设置过期时间,这样就可以把请求都放在缓存中处理,充分把 Redis 高吞吐量性能利用起来。
或者过期时间再加一个随机值。让数据在未来一段时间内慢慢过期,避免瞬时全部过期,对 DB 造成过大压力。
预热
预先把热门数据提前存入 Redis 中,并设热门数据的过期时间超大值。
使用锁
当发现缓存失效的时候,不是立即从数据库加载数据。
而是先获取分布式锁,获取锁成功才执行数据库查询和写数据到缓存的操作,获取锁失败,则说 明当前有线程在执行数据库查询操作,当前线程睡眠一段时间在重试。
这样只让一个请求去数据库读取数据。
缓存穿透
大量请求查询一个不存在的数据,即数据不存在 Redis 也不存在于数据库。导致每次请求都会穿透到数据库,缓存成了摆设,对数据库产生很大压力从而影响正常服务。
解决方案
缓存空值
当请求的数据不存在 Redis 也不存在数据库的时候,设置一个缺省值(比如:None)。当后续再次进行查询则直接返回空值或者缺省值。
布隆过滤器
在数据写入数据库的同时将这个 ID 同步到到布隆过滤器中,当请求的 id 不存在布隆过滤器中则说明该请求查询的数据一定没有在数据库中保存,就不要去数据库查询了。
在高并发用户注册场景下如何防止缓存穿透:
布隆过滤器 + 缓存:当用户名“lihua”成功注册后,同步到布隆过滤器中。当用户注销后,系统将用户名放入缓存结构中。当其他用户查询”lihua”是否被使用时,首先检查布隆过滤器是否包含该用户名。如果布隆过滤器中不存在该用户名,证明该用户名可用,直接返回。如果布隆过滤器中存在该用户名,进一步检查缓存结构中是否包含该用户名,如果存在,表示该用户名已被注销,可以被再次使用;如果缓存中不存在,表示该用户名已被使用且尚未被注销,不可用。
缓存雪崩
Redis中大量的key失效,导致请求直接到达数据库,直接宕机。出现该原因主要有两种:
- 大量的热点数据同时过期
- Redis故障宕机
解决方案
大量数据同时过期
过期时间添加随机值
这样一来,就不会导致同一时刻热点数据全部失效,同时过期时间差别也不会太大,既保证了相近时间失效,又能满足业务需求。
接口限流
当访问的不是核心数据的时候,在查询的方法上加上接口限流保护。
如果访问的是核心数据接口,缓存不存在允许从数据库中查询并设置到缓存中。
这样的话,只有部分请求会发送到数据库,减少了压力。
Redis宕机
服务熔断和接口限流
服务熔断就是当从缓存获取数据发现异常,则直接返回错误数据给前端,防止所有流量打到数据库导致宕机。
服务熔断和限流属于在发生了缓存雪崩,如何降低雪崩对数据库造成的影响的方案。
构建高可用缓存集群系统
主从(masterslave)架构、哨兵(Sentinel)机制、Redis集群