1. 什么是服务降级
先来说限流。举个例子: 对于一个景区,平时随便进出,但是一到春节或者十一国庆这种情况客流量激增,那么景区会限制同时进去的人数,这叫限流。
那么什么是服务降级呢?
再举个例子:
将一些不太重要的景区项目砍掉,平时就那么三五八个人,景区可以开放湖中游泳啦,摸鱼啦,捉虾啦,有情况工作人员可以下湖捞你,但是现在客流量大了,工作人员关注不过来,都在湖里晃荡万一沉了不太安全,大手一挥,这个项目砍了,将工作人员分配在其他地方。这就是降级。
再举个电商的例子:
在互联网中也有类似的降级措施,像之前双11, 有段时间是只允许下单不允许退单或者改单,这样做目的是什么呢?
这是为了保证服务的可用性,当硬件软件优化到一定的程度还是有上限,这时候将资源重点倾斜给核心业务,那些不太重要的就砍掉,保证服务的可用性。
2. 服务等级定义
服务等级定义 SLA(Service Level Agreement)是判定压测是否异常的重要依据。压测过程中,通过监控核心服务状态的 SLA 指标数据,可以更直观地了解压测业务的状态。
SLA则是服务商与您达成的正常运行时间保证。
关于这个的详细解释,可以参考阿里云的介绍: 服务等级定义SLA ,这儿不过多描述,SLA 分为网络服务和云服务,提供商的在线保证率通常要求达到6个9。
6个9含义
6个9指99.9999%,也就是一个服务有99.9999%概率是安全的,6个9有多安全呢?
2个9 = (1-99%)X24 X 365 = 87.6 小时 = 3.65天
3个9 = (1-99.9%)X24 X 365 = 8.76 小时
4个9 = (1-99.99%)X24 X 365 = 0.876 小时 = 52.56分钟
5个9 = (1-99.999%)X24 X 365 = 0.0876 小时 = 5.256分钟
6个9 = (1-99.9999%)X24 X 365 = 0.00876 小时 = 0.5256分钟 = 31秒
也就是,一年当中,6个9的安全性最多会有31s服务是不可用,相对来说是极高的。
3. 数据兜底
对一些关键数据设置一些兜底数据,例如设置默认值、静态值、设置缓存等。
默认值: 设置安全的默认值,不会引起数据问题的值,比如库存为0。
静态值:请求的页面或api无法返回数据,提供一套静态数据展示,比如加载失败提示重试,或者寻亲子网,或者跳到默认菜单,给用户一个稍微好一点的体验。
缓存: 缓存无法更新便使用旧的缓存
4. 限流降级
限流顾名思义,提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源,也就是当流量洪峰到达的时候,可能需要丢弃一部分用户来保证服务可用性,对于丢弃的用户可以提供友好的提示,比如提示用户当前繁忙、稍后重试等。
限流需要结合压测等,了解系统的最高水位,也是在实际开发中应用最多的一种稳定性保障手段。当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
5. 超时降级
对调用的数据设置超时时间,当调用失败时,对服务降级,举个例子,当访问数据已经超时了,且这个业务不是核心业务,可以在超时之后进行降级,比如商品详情页上有推荐内容或者评价,但是可以降级显示评价暂时不显示,这对主要的用户功能——购物,不产生影响,如果是远程调用,则可以商量一个双方都可以接受的最大响应时间,超时则自动降级。
6. 故障降级
如果远程调用的服务器挂了(网络故障、DNS故障、HTTP服务返回错误),则可以进行降级, 例如返回默认值或者兜底数据或者静态页面,也可以返回之前的缓存数据。
7. 重试/自动处理
客户端高可用:提供多个可调用的服务地址,这样做
微服务重试:dubbo重试机制
API调用重试:当达到重试次数后,增加访问标记,服务降级,异步探测服务是否恢复。
WEB端:在服务不可用时,web端增加重试按钮或自动重试可以提供更友好的体验。
自动重试需设置重试次数和数据幂等处理
8. 降级开关
在服务器提供支持期间, 如果监控到线上一些服务存在问题,这个时候需要暂时将这些服务去掉,有时候通过服务调用一些服务,但是服务依赖的数据库可能存在,网卡被打满了,数据库挂了,很多慢查询等等,此时要做的就是暂停相关的系统服务,也就是人工使用开关降级。开关可以放在某地,定期同步开关数据,通过判断开关值来决定是否做出降级。
开关降级还有一个作用,例如新的服务版本刚开发处在灰度测试阶段,不太确定里面的逻辑等等是否正确,如果有问题应该可以根据开关的值切回旧的版本。
在服务调用方设置一个flag,标记服务是否可用,另外key可以存储存储在在本地,也可以存储在第三方的配置文件中,例如数据库、redis、zookeeper中。
9. 爬虫和机器人
分析机器人行为:短时间连续操作,agent,行为轨迹、拖拽(模拟登陆/秒杀/灌水)
爬虫:引到到静态页或缓存页
10. 读降级
简而言之,在一个请求内,多级缓存架构下,后端缓存或db不可用,可以使用前端缓存或兜底数据让用户体验好一点。
对于读服务降级一般采用的策略有:
暂时切换读: 降级到读缓存、降级到走静态化
暂时屏蔽读: 屏蔽读入口、屏蔽某个读服务
通常读的流程为: 接入层缓存→应用层本地缓存→分布式缓存→RPC服务/DB
我们会在接入层、应用层设置开关,当分布式缓存、RPC服务/DB有问题时自动降级为不调用。当然这种情况适用于对读一致性要求不高的场景。
页面降级、页面片段降级、页面异步请求降级都是读服务降级,目的是丢卒保帅,保护核心线程,或者因数据问题暂时屏蔽。
还有一种是页面静态化场景。
动态化降级为静态化:比如,平时网站可以走动态化渲染商品详情页,但是,到了大促来临之际可以将其切换为静态化来减少对核心资源的占用,而且可以提升性能。其他还有如列表页、首页、频道页都可以这么处理。可以通过一个程序定期推送静态页到缓存或者生成到磁盘,出问题时直接切过去。
静态化降级为动态化:比如,当使用静态化来实现商品详情页架构时,平时使用静态化来提供服务,但是,因为特殊原因静态化页面有问题了,需要暂时切换回动态化来保证服务正确性。以上都保证了出问题时有预案,用户可以继续使用网站,不影响用户购物体验。
11. 写降级
大家都知道硬盘性能比不上内存性能,如果访问量很高的话,数据库频繁读写可能撑不住,那么怎么办呢,可以让内存(假如是Redis)库来暂时满足写任务,同时将执行的指令记录下来,然后将这个信息发送到数据库,也就是不在追求内存与数据库数据的强一致性,只要数据库数据与Redis数据库中的信息满足最终话一致性即可。
也就是说,正常情况下可以同步扣减库存,在性能扛不住时,降级为异步。另外,如果是秒杀场景可以直接降级为异步,从而保护系统。还有,如下单操作可以在大促时暂时降级,将下单数据写入Redis,然后等峰值过去了再同步回DB,当然也有更好的解决方案,但是更复杂,不是本篇的重点。
还有如用户评价,如果评价量太大,那么也可以把评价从同步写降级为异步写。当然也可以对评价按钮进行按比例开放(比如,一些人看不到评价操作按钮)。比如,评价成功后会发一些奖励,在必要的时候降级同步到异步。
12. 总结
在cap原理和BASE理论中写操作存在于 数据一致性 这个环节,降级的目的是为了提供高可用性,在多数的互联网架构中,可用性是大于数据一致性的。所以丧失写入数据同步,通过上面的理论,我们也能勉强接受数据最终一致性。高并发场景下,写入操作无法及时到达或抗压,可以异步消费数据/cache更新/log等方式。
网友评论