Redis 高可用、缓存不一致、缓存雪崩
文章目录
缓存雪崩
数据失效
模拟 2000 并发的场景,从缓存中读数据,没有任何问题。而如果 redis 失效了呢?比如硬件升级、突然断电,这种怎么办?原本应该访问缓存的,结果缓存失效了,雪崩…
因为缓存失效,从而导致大量的请求怼到数据库。
- 大量请求,导致数据库处理不过来,整个系统依赖数据库的功能,全部崩溃;
- 单系统挂掉,其它依赖于该系统的应用也会出现不稳定,甚至崩溃;
显然,不能在生产环境出现这个问题。
一般,这么几种情况可能出现缓存失效:
- 数据淘汰,LRU/LFU,最大内存阈值,依据内存使用情况淘汰掉旧的数据;
- 数据过期 expire,超过时间了,缓存就没了。
- 服务重启、宕机、升级,虽然支持全量的文件存储,也支持主从复制。
上面这些问题,是不可避免的,或者无法全部避免。但是可以用一些方式,避免缓存雪崩。
缓存雪崩还是要针对出现的问题原因做解决,最终的目的是防止数据库崩溃导致全盘崩溃。主要方案有:
对数据库访问限流,返回异常码
典型的有Semaphore信号量限流,JUC 中重要的并发编程工具类,可以理解为“手牌”。核心方法有:
- acquire:获取一个许可,如果没有就等待
- release:释放一个许可
使用的方式,在读取数据库之前,给一个 semaphore.acquire() 获取一个令牌,这样就可以控制只有一定数量的线程能够通过,执行数据库访问。访问完之后,再 semaphore.release() 释放一个令牌。
容错降级,返回异常码
限流之后,等待时间太长了,于是就要有一个降级策略。比如告诉前台:网络不给力,请重试。
这时候,可以用 semaphore.tryAcquire(),或者设置超时时间。如果超时了,就返回一个错误,便可以触发降级了。
如果直接在代码里面写这些缓存、限流的代码,就也让业务代码变得复杂了。于是,就可以自定义组件,自定义注解,去扩展原来的功能。
针对内存不足,采用 Redis 集群方案
(见后面的“高可用集群方案”)
缓存击穿
比如,访问不存在的数据。针对高并发的场景,常用的读都会命中缓存。而如果去查不存在的数据呢?如果还照着原来的设计,就会不停的去查数据库。
这样,查询必然不存在的数据,请求透过 Redis,直击数据库,也会导致缓存雪崩。