若是这是第二次看到个人文章,欢迎点击文末连接订阅个人我的公众号(跨界架构师)哟~每周五11:45 按时送达。固然了,也会时不时加个餐~前端
本文长度为4069字,建议阅读11分钟。java
也许你对降级已经有了一些认识,认真看完,我想这篇文章可能会给你带来一些新的收获~nginx
前面两篇咱们已经聊过了「熔断」(如何在处处是“雷”的系统中「明哲保身」?这是第一招)和「限流」(想通关「限流」?只要这一篇),此次咱们聊的就是「高可用三剑客」中剩下的「降级」。程序员
不知道这里有多少小伙伴接触过阿里的开放平台。在每次大促的时候,阿里都会发布这样的一个公告。数据库
这些调整就是「降级」工做,目的是为了腾出更多资源给核心程序使用,以最大化保证核心业务的可用性,所以就必然须要对非核心业务执行一些降级处理。后端
降级的目的用一句话归纳就是:将有限的资源效益最大化。浏览器
什么样才是效益最大化呢?就像下面这个例子:缓存
z哥有3个东西要买,一个3000的A、一个700的B、一个1200的C,对z哥的重要程度A>B>C。但此时,z哥手里只有3000块钱,你说z哥该怎么选才能把钱花的最多?必然是选A咯。bash
根据28原则,咱们知道一个系统80%的效益是由最核心的20%的功能产出的。剩下的20%效益须要投入80%的资源才能达到。微信
这就意味着,假如系统平时须要花费100%资源作100%的事情,若是如今访问量增多3倍的话一定扛不住(须要300%的资源)。那么,在不增长资源的状况下,我但愿系统不能宕机,依旧能正常工做,必然须要让出那解决剩下20%问题的80%资源。如此一来,理论上这100%的资源就能够支撑原先5倍的访问量。反作用是功能的完整性上受损80%。
固然,在实际的场景中不会降级掉80%的功能这么夸张,毕竟还得为用户的体验考虑。
举个电商场景典型的例子,在大促的时候,最重要的是什么?转化咯~赚钱咯~ 那么这个时候若是说「评论」功能占用了不少资源,你会怎么处理?其实咱们能够选择临时关闭提交评论入口、关闭翻页功能等等,让下单的过程有更多的资源来处理。
常见的降级方案表现形式无非如下三种类型。
为了减小对「冷数据」的获取,禁用列表的翻页功能。
为了放缓流量进入的速率,增长验证码机制。
为了减小“大查询”浪费过多的资源,提升筛选条件要求(禁用模糊查询、部分条件必选等)。
用通用的静态化数据代替「千人千面」的动态数据。
甚至更简单粗暴的,直接挂一个页面显示「XX功能在XX时间内暂时关闭」。
此类方案虽然或多或少下降了用户的体验,可是在某些时期,有些功能并非「刚需」。以此换取对系统的保护是笔划算的买卖。
还有一些功能是「防护性」的,若是愿意冒险“裸奔”一段时间也会带来可观的资源节约。
好比经过临时关闭「风控」、取消部分「条件是否知足」的判断(如,将积分商品添加到购物车时判断积分够不够)等操做,减小这类「验证」动做以释放更多的资源。
又或者将本来info、warning级别的日志采集关闭或者直接不采集,仅采集error以及fault级别的日志。
一个事件发生后立马看到效果是一个很符合「思惟惯性」的东西。可是根据以前的一篇文章(分布式系统关注点——数据一致性(上篇))咱们知道,时效性这个东西一旦涉及到网络传输是不存在真正的“实时”的。可是为了尽量快的将处理后的结果反映到相关的地方,你会作不少努力。好比库存的及时同步。
若是在特殊时期,可以临时下降对时效性的要求(3秒内生效变成30秒生效),也是一个有不错收益的方案。
好比原先在商品页会显示当前还剩多少个库存,如今能够调整成固定显示「有货」。
以及将一些本来就是异步进行的操做,处理效率放缓,甚至暂缓一段时间。如,送积分、送券等等。
讲了这么多,降级具体实施起来要怎么作呢?
主要分为两个环节:定级定序和降级实现。
就像前面的例子中提到的同样,首先咱们得先肯定每一个功能的「重要程度」,它决定了在什么状况下能够抛弃它以保证剩下的功能可用。
相似于给日志定义级别同样,好比咱们能够定义1~5五个级别,1的级别最高,要拼死保护。5的级别最低最早能够被降级掉。
一旦当系统压力过大的时候,先把级别5的功能降级掉。若是还不够再降级别四、级别3,以此类推。
但实际上光这样定级还不够,好比被定义为4级的有100个功能,须要降级的时候是一块儿降级吗?很明显粒度太粗了。
若是「定级」比如是横着切蛋糕的话,「定序」就是再来竖着切。
咱们也能够来定义一些数字,好比序号1~9,序号9最早被降级。
而后,你能够以每一个程序所支撑的上游程序/功能数量做为一个参考标准。好比,一样是级别5的程序,一个支撑了上游5个功能,一个支撑了10个功能,很显然前者的序号应该更大,更先被降级。
固然,根据所支撑的功能数量只是一个「业务无关性」的通用办法。若是想精益求精,还须要对每一个功能作「做用」上的分析,毕竟不一样功能之间的相对重要性仍是有所差别的。(这里能够扩展了解一下Analytic Hierarchy Process,层次分析法,简称AHP)
对了,定级定序的时候有一点是须要格外注意的:某个程序所依赖的下游程序的级别不能低于该程序的级别。
为何呢?由于一旦所依赖的程序被降级了,天然会致使其所支撑的全部上游程序不可用。因此,其上游程序的等级再高也是没有意义的。
至此,完成了“排兵布阵”,接下来就是“实施运做”了。
首先要制定触发机制。这同熔断、限流同样,何时该触发「降级」这个动做也须要依赖提早制定的一些策略。这部份内容和前面两篇(熔断、限流)相似,无非是接口的超时率、错误率,或者系统的资源耗用率等,这里就不重复展开了。
当程序发现知足了降级条件进入「降级模式」后,程序该如何处理请求呢?
全局变量 int _runLevel = 3; //运行系统级别,默认值5
所有变量 int _runIndex = 7; //运行系统序号,默认值9
//如下是一个level=四、index=8的功能示例。
if(myLevel > _runLevel and myIndex > _runIndex){
// 进入降级模式。
}else{
// do something...
}复制代码
题外话:经过Aop+注解(特性)的方式来作上面的if判断是一个爽的事情。
虽然处理请求的方式有不少,但特别强调的是,要实现的降级策略要尽量的简单。由于「边际效应」的存在,为了应对突发情况把事情反而搞复杂了就得不偿失了。
那么在实现部分,若是是前端。咱们比较常见的是:
在返回的http报文中经过Cache-Control的设置,让后续的请求直接走浏览器缓存。
页面中本来须要异步加载的数据,直接不加载。
禁用部分操做按钮,甚至直接告知“临时关闭”。
动态页面的url经过反响代理切换到静态页面返回。
这里面除了禁用按钮外,大部分事情均可以在接入层,如nginx中处理掉,这样能够避免对业务项目的代码侵入。
若是是后端程序的话,针对「读」类型的操做,能够将“// 进入降级模式”部分代码写成下面的样子:
若是是无返回值方法。默认return或者throw一个异常。
若是是有返回值方法。默认返回本地mock的数据或者throw一个异常。
后端部分若是有使用一些中间件的话,直接在中间件(rpc、mq代理等)中处理掉是极好的(通常会内置一个fallback接口待实现),如此也能够避免对业务代码的侵入。
最后咱们来聊聊后端程序的「写」问题。
缓存是大型系统中的常客,随着系统规模越大,为了在性能和成本上寻求更优,不可避免的会增长复杂度引入多级缓存。如此就会变成:本地缓存 --> 分布式缓存 --> DB/源服务,这样的一个层层递进的关系。
平时的代码多是这样的:
if(write数据库(data) == true){
if(write分布式缓存(data) == true){
write本地缓存(data);
return success;
}
else{
rollback数据库(data);
return fail;
}
}
else{
return fail;
}复制代码
在高负载时期,咱们能够下降对一致性的要求。将耗时的「数据落盘」操做降级为「异步」进行。
if(write分布式缓存(data) == true){
write本地缓存(data);
pushMessage(data); //发出的消息能够经过集中式的MQ、也能够直接写本地磁盘。
return success;
}
else{
return fail;
}复制代码
甚至,若是能够的话能作的更完全,同步到分布式缓存也异步进行。
write本地缓存(data);
pushMessage(data); //发出的消息能够经过集中式的MQ、也能够直接写本地磁盘。
return success;复制代码
数据库是系统的最后一座堡垒,非非很是极端的状况下,咱们能够把一些「写数据」操做在「数据库访问框架」中给禁用了,让给全部资源都给到「读数据」。使得系统从表象上来看至少仍是“活着站在那”的,虽然不少功能操做一下就是返回失败(这不也是实在没办法了嘛,面子得要啊,死撑~)。
至此咱们聊了作降级的思路以及最多见的一些实现方式,可是真正要把降级最好是一个任重而道远的过程。
从方案的角度来讲,若是降级的过程需对每一个功能/程序逐一进行,那么理论上10个功能点就能够产生P(10,10)= 3628800种方案。
再从现实的角度来讲,流量又是不可预测的。某些功能可能此次须要做为level2来看待,下次其实做为level3就够了。
因此这是一个须要长期不断打磨和调优的过程。
最后,但愿近期的「高可用三剑客」能够做为你了解「高可用」的起点,能够先收藏防身(固然再分享一下也是极好的:)),欢迎后续一块儿交流探讨~
Question:
你曾经是否有遇到过什么场景,当时是经过立刻改代码来「降级」呢?欢迎来吐槽~
相关文章:
▶ 关于做者:张帆(Zachary,我的微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。本文首发于公众号:「 跨界架构师」(ID:Zachary_ZF)。 <-- 点击后阅读热门文章
若是你是初级程序员,想提高但不知道如何下手。又或者作程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注个人公众号「 跨界架构师」,回复「 技术」,送你一份我长期收集和整理的思惟导图。
若是你是运营,面对不断变化的市场一筹莫展。又或者想了解主流的运营策略,以丰富本身的“仓库”。欢迎关注个人公众号「 跨界架构师」,回复「 运营」,送你一份我长期收集和整理的思惟导图。
按期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些深度思考。