0. 正常的业务流程
- 用户向web服务器发起请求
- web服务器会先查询redis缓存服务器,缓存有则直接返回
- 若缓存没有,则查询mysql服务器,将结果返回给web服务器,同时将其加入redis缓存(看情况,若是热点就加入)。
1. 缓存雪崩
1. 原因
- redis缓存的key在同一时间大量失效,导致大量请求全部打到数据库服务器,造成数据库服务器响应不及时而挂掉。从而导致整个服务器无法提供服务。
- 两种可能:一种是redis宕机,一种是大量的key设置了相同的过期时间
2. 解决方案
- 设置缓存失效时间,不要让热点数据的缓存在同一时间失效(如随机初始化失效时间)
- 在集群部署中,将不同类别的热点key放到不同的节点上(通过集群提高服务的高可用性)
- 不设置失效时间
- 跑定时任务,在缓存失效前增加缓存失效时间
- 设置互斥锁,缓存失效后,一个时刻只有一个线程可以访问数据库并写缓存。
- 熔断机制和限量降级
- 给业务添加多级缓存
2. 缓存穿透
1. 原因
- 恶意请求redis服务器和数据库服务器都不存在的数据。
- 本来redis可以处理一些请求来降低数据库服务器压力,但是现在redis无法命中,全部打到数据库服务器上去。造成数据库服务器挂掉
- 例子
- 大量请求id为-1的数据
- redis查询不到,放行给数据库服务器
- 数据库查询为空,返回空
- 但是太多这种请求了,导致数据库挂掉
2. 解决方案
- 查询的结果为空,也将这次请求缓存到redis中去(如key是请求id,value是null),但是他可能换不同的请求参数(必要的时候,可以加过期时间,防止缓存过多的null值)
- 拉黑ip,但是他可能换不同的ip
- 对参数进行合法化检查
- 使用布隆过滤器(将数据库所有数据存在信息保存到布隆过滤器,请求来了先用布隆过滤器判断是否放行给数据库)
补充
- 缓存null值
- 布隆过滤器
- 增强id的复杂度,避免被猜测id规律
- 做好数据的基础格式校验
- 加强用户权限校验
- 做好热点数据的限流
3. 缓存击穿
1. 原因
- 某个热点key过期,导致此时(这一瞬间)大量请求打到数据库服务器上,造成数据库挂掉
2. 解决方法
- 设置热点缓存永不过期(不太好)
- 虽然设置永不过期,但是可以添加一个逻辑过期字段,如一个字段,内容是过期的时间戳,拿到缓存后先判断这个时间戳是否超时,超时了则认为是过期了的。
- 当发现过期了之后,可以加分布式锁去更新缓存。(加锁成功后更新缓存这个过程可以让子线程去做)
- 使用分布式锁,(单体应用可以使用互斥锁),让一时刻只能有一个请求访问数据库,查询到结果后也将数据缓存到redis中去,其他线程之后就又可以请求redis服务器了