数据请求流程。
就拿我熟悉的网站来说。当你访问网站时,前端需要渲染页面,所以要从后端获取到数据。数据哪里来?当然是数据库(关系数据库或者非关系数据库)中。
关系型数据库:mysql
非关系型数据库:redis
而mysql一般相对于redis读写性能较差,所以采用redis来存储数据,而不是直接请求mysql。
当后端接到前端的数据请求,如果redis中有数据缓存,直接拿缓存数据,返回给前端
当redis中的缓存失效,先请求mysql,将数据缓存至redis中。再查询redis获取数据
避免造成大量请求打入mysql中,导致服务器崩溃
缓存雪崩:
大量redis数据缓存在一瞬间(由于设置了过期时间)全部失效,导致所有请求全部直接请求数据库,造成数据库压力太大而雪崩,无法再对外提供服务。
解决方案:
1.设置缓存的失效时间,随机初始化失效时间,不会让所有的redis缓存在同一时间失效。
2.对于集群分布的redis,将热点的key设置在不同的redis节点上
3.设置定时任务,在缓存失效前请求数据库的数据。
4.限流和降级,提前预估系统处理能力
5.对大的热 key, 直接缓存在本地
缓存穿透:
redis查不到id小于0的数据,就去数据库中查。直接穿透进数据库中
解决方案:
1.如果数据库中无法查到结果,也返回给redis,对应的值为空。这样下次同样id小于0的参数请求,不会再请求数据库,而是从redis中拿到空数据。无法穿透redis
2.ip拉黑
3.参数校验(最重要)
4.布隆过滤器
缓存击穿:
基本和缓存雪崩相同,不同的是,缓存击穿指并发查同一条热点数据,而缓存雪崩指的是大量数据同时失效
解决方案:
1.缓存永不过期,但是你觉得好嘛?
2.分布式锁。单体应用则采用互斥锁
(具体分析:如果redis数据为空,请求数据库数据,在请求数据库这一步,给线程加锁,这样就只有一个线程能抢到锁,只有一个线程能操作数据库,压力小,当查询完毕,将数据缓存至redis中,没有抢到锁的线程先睡几秒,然后再次去redis拿数据)
如果真的出现问题。怎么办?
1.项目上线前,(资金足够)采用分布式集群,无论是web服务器,还是redis服务器,数据库服务器。保证服务高可用性
2.项目运行中。及时采取限流措施,手动调整。比如临时租个redis,模拟请求,将数据暂时缓存起来,而不是任由数据直接请求数据库,造成数据库宕机,甚至毁坏
redis RDB机制,aof持久化机制,快速恢复