相对来说,考虑的比较完善的一套方案,分为事前,事中,事后三个层次去思考怎么来应对缓存雪崩的场景
1、事前解决方案
发生缓存雪崩之前,事情之前,怎么去避免redis彻底挂掉
redis本身的高可用性,复制,主从架构,操作主节点,读写,数据同步到从节点,一旦主节点挂掉,从节点跟上
双机房部署,一套redis cluster,部分机器在一个机房,另一部分机器在另外一个机房
还有一种部署方式,两套redis cluster,两套redis cluster之间做一个数据的同步,redis集群是可以搭建成树状的结构的
一旦说单个机房出了故障,至少说另外一个机房还能有些redis实例提供服务
2、事中解决方案
redis cluster已经彻底崩溃了,已经开始大量的访问无法访问到redis了
(1)ehcache本地缓存
所做的多级缓存架构的作用上了,ehcache的缓存,应对零散的redis中数据被清除掉的现象,另外一个主要是预防redis彻底崩溃
多台机器上部署的缓存服务实例的内存中,还有一套ehcache的缓存
ehcache的缓存还能支撑一阵
(2)对redis访问的资源隔离
(3)对源服务访问的限流以及资源隔离
3、事后解决方案
(1)redis数据可以恢复,做了备份,redis数据备份和恢复,redis重新启动起来
(2)redis数据彻底丢失了,或者数据过旧,快速缓存预热,redis重新启动起来
redis对外提供服务
缓存服务里,熔断策略,自动可以恢复,half-open,发现redis可以访问了,自动恢复了,自动就继续去访问redis了
基于hystrix的高可用服务这块技术之后,先讲解缓存服务如何设计成高可用的架构
缓存架构应对高并发下的缓存雪崩的解决方案,基于hystrix去做缓存服务的保护
redis集群崩溃的时候,会怎么样?
(1)首先大量的等待,超时,报错
(2)如果是短时间内报错,会直接走fallback降级,直接返回null
(3)超时控制,你应该判断说redis访问超过了多长时间,就直接给timeout掉了
不推荐说用默认的值,一般不太精准,redis的访问你首先自己先统计一下访问时长的百分比,hystrix dashboard,TP90 TP95 TP99
一般来说,redis访问,假设说TP99在100ms,那么此时,你的timeout稍微多给一些,100ms。
1、timeout超时控制
HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(int value)
意义在于哪里,一旦说redis出现了大面积的故障,此时肯定是访问的时候大量的超过100ms,大量的在等待和超时
就可以确保说,大量的请求不会卡住过长的时间,比如说卡住个1s,500ms,100ms直接就报timeout,走fallback降级了
2、熔断策略
(1)circuitBreaker.requestVolumeThreshold
设置一个rolling window,滑动窗口中,最少要有多少个请求时,才触发开启短路
举例来说,如果设置为20(默认值),那么在一个10秒的滑动窗口内,如果只有19个请求,即使这19个请求都是异常的,也是不会触发开启短路器的
HystrixCommandProperties.Setter()
.withCircuitBreakerRequestVolumeThreshold(int value)
我们应该根据我们自己的平时的访问流量去设置,而不是用默认值,比如说,我们认为平时一般的时候,流量也可以在每秒在QPS 100,10秒的滑动窗口就是1000
一般来说,你可以设置这样的一个值,根据你自己的系统的流量去设置
假如说,你设置的太少了,或者太多了,都不太合适
举个例子,你设置一个20,结果在晚上最低峰的时候,刚好是30,可能晚上的时候因为访问不频繁,大量的找不到缓存,可能超时频繁了一些,结果直接就给短路了
(2)circuitBreaker.errorThresholdPercentage
设置异常请求量的百分比,当异常请求达到这个百分比时,就触发打开短路器,默认是50,也就是50%
HystrixCommandProperties.Setter()
.withCircuitBreakerErrorThresholdPercentage(int value)
(3)circuitBreaker.sleepWindowInMilliseconds
设置在短路之后,需要在多长时间内直接reject请求,然后在这段时间之后,再重新导holf-open状态,尝试允许请求通过以及自动恢复,默认值是5000毫秒
HystrixCommandProperties.Setter()
.withCircuitBreakerSleepWindowInMilliseconds(int value)
限流过后,就会导致什么呢,比如redis集群崩溃了,雪崩,大量的请求涌入到商品服务调用的command中,是线程池不够
reject,被reject掉的请求就会去执行fallback降级逻辑
那么nginx本地缓存肯定就没了,redis已经崩溃了,ehcache中找不到这条数据对应的缓存
只能从源头的商品服务里面去查询,但是被限流了,这个请求只能走降级方案
stubbed fallback降级机制,残缺的降级
一般这种情况下,就是说,用请求参数中少量的数据,加上纯内存中缓存的少量的数据来提供残缺的数据服务
冷数据,也就是说你可以这么认为,将一些过时的数据,比如一个商品信息一周前的版本,放入大数据的在线存储中,比如比较合适做冷数据存放的是hbase
hadoop,离线批处理,hdfs分布式存储,yarn分布式资源调度(跟hbase没关系),mapreduce分布式计算
hbase,基于hdfs分布式存储基础之上,封装了一个系统,叫做hbase,分布式在线存储,分布式NoSQL数据库,里面可以放大量的冷数据
hbase,可以做商品服务热数据是放mysql,可以将一周前,一个月前的数据快照,做一份冷备放到hbase来备用
发送请求去访问hbase,去加载冷数据,hbase本身是分布式的,所以也是可以承载高并发的访问的(分布式的特性比mysql),即使这个时候大量并发到了hbase,
多级降级机制,先走hbase冷备,然后再走stubbed fallback
缓存雪崩的回顾
1、事前,redis高可用性,redis cluster,sentinal,复制,主从,从->主,双机房部署
2、事中,ehcache可以抗一抗,redis挂掉之后的资源隔离、超时控制、熔断,商品服务的访问限流、多级降级,缓存服务在雪崩场景下存活下来,基于ehcache和存活的商品服务提供数据
3、事后,快速恢复Redis,备份+恢复,快速的缓存预热的方案