⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 www.cnblogs.com/Courage129/p/14427020.html 「等不到的口琴」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

什么是服务降级

如果看过我前面对服务限流的分析,理解服务降级就很容易了,对于一个景区,平时随便进出,但是一到春节或者十一国庆这种情况客流量激增,那么景区会限制同时进去的人数,这叫限流,那么什么是服务降级呢?

简单来说就是,将一些不太重要的景区项目砍掉,平时就那么三五八个人,景区可以开放湖中游泳啦,摸鱼啦,捉虾啦,有情况工作人员可以下湖捞你,但是现在客流量大了,工作人员关注不过来,都在湖里晃荡万一沉了不太安全,大手一挥,这个项目砍了,将工作人员分配在其他地方。

在互联网中也有类似的降级措施,像之前双11, 有段时间是只允许下单不允许退单或者改单,这样做目的是什么呢?

还是为了保证服务的可用性,当硬件软件优化到一定的程度还是有上限,这时候将资源重点倾斜给核心业务,那些不太重要的就砍掉,保证服务的可用性。

服务等级定义

服务等级定义 SLA(Service Level Agreement)是判定压测是否异常的重要依据。压测过程中,通过监控核心服务状态的 SLA 指标数据,可以更直观地了解压测业务的状态。

SLA则是服务商与您达成的正常运行时间保证。

关于这个的详细解释,可以参考阿里云的介绍:服务等级定义SLA(https://help.aliyun.com/document_detail/111729.html),这儿不过多描述,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服务是不可用,相对来说是极高的。

降级处理

兜底数据

这方面有很多例子,比如某些页面挂了会返回寻亲子网。可以对一些关键数据设置一些兜底数据,例如设置默认值、静态值、设置缓存等。

默认值: 设置安全的默认值,不会引起数据问题的值,比如库存为0

静态值:请求的页面或api无法返回数据,提供一套静态数据展示,比如加载失败提示重试,或者寻亲子网,或者跳到默认菜单,给用户一个稍微好一点的体验。

缓存: 缓存无法更新便使用旧的缓存

限流降级

限流顾名思义,提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源,也就是当流量洪峰到达的时候,可能需要丢弃一部分用户来保证服务可用性,对于丢弃的用户可以提供友好的提示,比如提示用户当前繁忙、稍后重试等。

限流需要结合压测等,了解系统的最高水位,也是在实际开发中应用最多的一种稳定性保障手段。当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。

超时降级

对调用的数据设置超时时间,当调用失败时,对服务降级,举个例子,当访问数据已经超时了,且这个业务不是核心业务,可以在超时之后进行降级,比如商品详情页上有推荐内容或者评价,但是可以降级显示评价暂时不显示,这对主要的用户功能——购物,不产生影响,如果是远程调用,则可以商量一个双方都可以接受的最大响应时间,超时则自动降级。

故障降级

如果远程调用的服务器挂了(网络故障、DNS故障、HTTP服务返回错误),则可以进行降级, 例如返回默认值或者兜底数据或者静态页面,也可以返回之前的缓存数据。

重试/自动处理

客户端高可用:提供多个可调用的服务地址,这样做

微服务重试:dubbo重试机制

API调用重试:当达到重试次数后,增加访问标记,服务降级,异步探测服务是否恢复。

WEB端:在服务不可用时,web端增加重试按钮或自动重试可以提供更友好的体验。

自动重试需设置重试次数和数据幂等处理

降级开关

在服务器提供支持期间, 如果监控到线上一些服务存在问题,这个时候需要暂时将这些服务去掉,有时候通过服务调用一些服务,但是服务依赖的数据库可能存在,网卡被打满了,数据库挂了,很多慢查询等等,此时要做的就是暂停相关的系统服务,也就是人工使用开关降级。开关可以放在某地,定期同步开关数据,通过判断开关值来决定是否做出降级。

开关降级还有一个作用,例如新的服务版本刚开发处在灰度测试阶段,不太确定里面的逻辑等等是否正确,如果有问题应该可以根据开关的值切回旧的版本。

在服务调用方设置一个flag,标记服务是否可用,另外key可以存储存储在在本地,也可以存储在第三方的配置文件中,例如数据库、redis、zookeeper中。

爬虫和机器人

分析机器人行为:短时间连续操作,agent,行为轨迹、拖拽(模拟登陆/秒杀/灌水)

爬虫:引到到静态页或缓存页

读降级

简而言之,在一个请求内,多级缓存架构下,后端缓存或db不可用,可以使用前端缓存或兜底数据让用户体验好一点。

对于读服务降级一般采用的策略有: 暂时切换读: 降级到读缓存、降级到走静态化 暂时屏蔽读: 屏蔽读入口、屏蔽某个读服务

通常读的流程为: 接入层缓存→应用层本地缓存→分布式缓存→RPC服务/DB

我们会在接入层、应用层设置开关,当分布式缓存、RPC服务/DB有问题时自动降级为不调用。当然这种情况适用于对读一致性要求不高的场景。

页面降级、页面片段降级、页面异步请求降级都是读服务降级,目的是丢卒保帅,保护核心线程,或者因数据问题暂时屏蔽。

还有一种是页面静态化场景。 动态化降级为静态化:比如,平时网站可以走动态化渲染商品详情页,但是,到了大促来临之际可以将其切换为静态化来减少对核心资源的占用,而且可以提升性能。其他还有如列表页、首页、频道页都可以这么处理。可以通过一个程序定期推送静态页到缓存或者生成到磁盘,出问题时直接切过去。 静态化降级为动态化:比如,当使用静态化来实现商品详情页架构时,平时使用静态化来提供服务,但是,因为特殊原因静态化页面有问题了,需要暂时切换回动态化来保证服务正确性。以上都保证了出问题时有预案,用户可以继续使用网站,不影响用户购物体验。

写降级

大家都知道硬盘性能比不上内存性能,如果访问量很高的话,数据库频繁读写可能撑不住,那么怎么办呢,可以让内存(假如是Redis)库来暂时满足写任务,同时将执行的指令记录下来,然后将这个信息发送到数据库,也就是不在追求内存与数据库数据的强一致性,只要数据库数据与Redis数据库中的信息满足最终话一致性即可。

也就是说,正常情况下可以同步扣减库存,在性能扛不住时,降级为异步。另外,如果是秒杀场景可以直接降级为异步,从而保护系统。还有,如下单操作可以在大促时暂时降级,将下单数据写入Redis,然后等峰值过去了再同步回DB,当然也有更好的解决方案,但是更复杂,不是本篇的重点。

还有如用户评价,如果评价量太大,那么也可以把评价从同步写降级为异步写。当然也可以对评价按钮进行按比例开放(比如,一些人看不到评价操作按钮)。比如,评价成功后会发一些奖励,在必要的时候降级同步到异步。

总结 在cap原理和BASE理论中写操作存在于数据一致性这个环节,降级的目的是为了提供高可用性,在多数的互联网架构中,可用性是大于数据一致性的。所以丧失写入数据同步,通过上面的理论,我们也能勉强接受数据最终一致性。高并发场景下,写入操作无法及时到达或抗压,可以异步消费数据/cache更新/log等方式

前端降级

当系统出现问题的时候,尽量将请求隔离在离用户最近的位置,避免无效链路访问, 在后端服务部分或完全不可用的时候,可以使用本地缓存或兜底数据,在一些特殊场景下,对数据一致性要求不高的时候,比如秒杀、抽奖等可以做假数据。

JS降级

在js中埋降级开关,在访问不到达,系统阈值的时候可以避免发送请求

主要控制页面功能的降级,在页面中,通过JS脚本部署功能降级开关,在适当时机开启/关闭开关。

接入层降级

可以在接入层,在用户请求还没到达服务的时候,通过、Nginx + Lua、Haproxy + lua过滤无效请求达到服务降级的目的, 主要控制请求入口的降级,请求进入后,会首先进入接入层,在接入层可以配置功能降级开关,可以根据实际情况进行自动/人工降级。这个可以参考第17章,尤其在后端应用服务出问题时,通过接入层降级从而给应用服务有足够的时间恢复服务。

应用层降级

主要控制业务的降级,在应用中配置相应的功能开关,根据实际业务情况进行自动/人工降级。

SpringCloud中可以通过Hystrix配置中心可以进行人工降级,也可以根据服务的超时时间进行自动降级, Hystrix是Netflix开源的一款针对分布式系统的延迟和容错库,目的是用来隔离分布式服务故障。它提供线程和信号量隔离,以减少不同服务之间资源竞争带来的相互影响;官网讲Hystrix提供优雅降级机制;提供熔断机制使得服务可以快速失败,而不是一直阻塞等待服务响应,并能从中快速恢复。Hystrix通过这些机制来阻止级联失败并保证系统弹性、可用。下图是一个典型的分布式服务实现。

图片

片段降级

例如打开淘宝首页,这一瞬间需要加载很多数据,有静态的例如图片、CSS、JS等,也有很多其他商品等等,这么多数据中,如果一部分没有请求到,那么就可以片段降级,意思是就不加载这些数据了,用其他数据顶替,例如其他商品信息或者等等。

提前预埋

这个很容易理解,大家应该都记得,每次双十一之前,淘宝总会提醒你下载更新,按道理来讲,活动还没开始,更新啥呢?

做法是对于一部分静态数据可以提前更新到你手机上,当你双十一时就不用再远程连接服务器加载了,避免了消耗网络资源。

文章目录
  1. 1. 什么是服务降级
  2. 2. 服务等级定义
    1. 2.1. 6个9含义
  3. 3. 降级处理
    1. 3.1. 兜底数据
  4. 4. 限流降级
  5. 5. 超时降级
  6. 6. 故障降级
    1. 6.1. 重试/自动处理
  7. 7. 降级开关
    1. 7.1. 爬虫和机器人
    2. 7.2. 读降级
    3. 7.3. 写降级
  8. 8. 前端降级
    1. 8.0.1. JS降级
    2. 8.0.2. 接入层降级
    3. 8.0.3. 应用层降级
  • 9. 片段降级
  • 10. 提前预埋