16种设计思想–Designforfailure

16种设计思想–Designforfailure
软件质量管理体系⼀直在说互联⽹系统应该是design for failure,今天看到的这篇⽂介绍的虽是简单⼏句话,但妥妥的设计思想,还是蛮契合SRE精髓。作为⼀名designer或者developer,应该要对墨菲定律⼼存敬畏,以下讲⼀下我对这16种设计思想的⼀个⼤致看法吧。
1、防御性设计(Defensive Design)
所谓的防御性设计实际上就是“防呆”,英⽂叫Idiot Proofing。说⽩了就是⽤户有时候会不⾃觉的做⼀些蠢事,我们在设计的时候要尽量考虑到⼀些不规范的交互⾏为,如果你的⽤户是⼀只猴⼦,你要写表单保证系统不被玩坏。例如,在Android开发中使⽤到的Monkey Test 就是⽤于这样的⽬的。
2、边界情况(Edge Case)
这个设计思想在测试领域⽐较常见,就是我们在设计我们的设计案例的时候有没有充分考虑在边界情况下的系统⾏为。⽐较常见的例如,闰年情况、跨⽇情况等边界。想起刚⼊⾏我leader跟我说你的程序在你脑袋有没有跑过⼀遍所有能想到的情况,没有的话重做。
3、防误措施(Mistake Proofing)
怎么保证不会发⽣错误。例如在⼈机交互环节,能不能进⾏输⼊校验?
4、解耦(Decoupling)
设计的时候,哪怕是最基础的代码也应该符合开闭原则。远的不说,就单单Spring的IOC就是为了把对象创建及维护从原来的由引⽤类负责这种强耦合模式转成通过spring容器负责。且解耦⼀般的做法是通过把内部逻辑封装起来,暴露对外统⼀API接⼝,调⽤⽅不需要了解被调⽤⽅的内部逻辑实现,只需要知道提供什么功能即可。这样再引申⼀下,解耦的作⽤就在于复⽤,把所有的⾼内聚功能独⽴成⼀个个模块,然后就可以像乐⾼积⽊⼀样根据调⽤⽅的实际需求进⾏组装。
宏观的系统设计就更是如此,例如微服务中的Eureka。⾸先,Eureka客户端通过把⾃⼰注册到Eureka服务端(如IP、端⼝),然后其他服务在调⽤前通过Eureka获取被调⽤⽅的信息,然后再去调⽤被调⽤⽅,然后他们的调⽤关系就是这样解耦的。
祖国版图上的世界之最
熔断本质上就是⼀种防御性设计或者策略。假设⼀个微服务体系下的系统,其中A服务调⽤B服务。系统的QPS是千级别,当时如果B服务挂掉的话A的线程绝对在短时间内占满耗尽⽽导致假死,从⽽形成⼤量A请求积压⽽导致情况恶化,最终形成雪崩。
在SpringCloud技术体系中,熔断就是Hystrix所体现的另外⼀种思想。Hystrix可以通过监控⼀段事件
内的异常次数和响应速度来判断当前服务的健康状况,若服务健康状况不佳则进⾏熔断,熔断之后新的请求将不会调⽤实际的业务,⽽是通过快速失败或优雅降级的⽅式来快速给⽤户进⾏响应。
5、 舱壁模式(Bulkhead)
渡边淳一
在分布式系统的设计中有⼀种舱壁模式。⽬前⽐较⽕的微服务架构我理解实际上就是隔板模式的⼀个体现。这种模式把系统中的各个功能模块实体进⾏进程、资源上的隔离,使得系统不会因为某个功能模块试题(即微服务)的局部失败⽽导致全局失败。
1)资源隔离:
微服务⾥⾯的Hystrix则是遵守了该模式,通过为每个单独的服务提供独⽴的线程池⽽进⾏资源隔离。在Hystrix中实际上通过两种⽅式进⾏资源隔离:
信号量隔离策略( ExecutionIsolationStrategy.SEMAPHORE)
Semaphores 隔离就是利⽤了urrent.Semaphore 的功能,从信号量获取到许可才允许执⾏,否则不允许执⾏,执⾏完成后要释放之前获取到的许可。同样的每⼀个服务依赖都有⼀个⾃⼰的信号量,当该信号量的许可被获取完之后,再有线程要进⾏依赖调⽤,发现已经没有可⽤的信号量,这时候就会被拒绝调⽤。信号量隔离始终都是运⾏在 Container 线程内的。它的优势就在于造成的开
销更低。
线程隔离策略( ExecutionIsolationStrategy.THREAD)
所谓的线程隔离,实际上就是每⼀个依赖调⽤都有⾃⼰的线程池来负责处理,依赖调⽤都运⾏在⾃⼰线程池中的线程上,当同⼀个依赖调⽤使⽤的线程池中的 Queue size 达到设置的阙值时就会拒绝进⾏依赖的调⽤。
具体⽤法可以通过继承@HystrixCommand实现线程隔离或者交易隔离。
2)数据隔离
上⾯讲的都是线程隔离,当然数据隔离这个⼀般的做法有库隔离、表隔离、按字段区分这三种租户隔离的⽅法。
6、冗余(Redundancy)
所谓的冗余指的通过重复配置关键组件或部件,保证在关键组件失效的情况下还有备份组件运作以便保证系统可以继续提供服务。⽣活中的例⼦请参与飞机的双引擎设计。
主从模式就是冗余的体现。在正常情况下,主实例负责提供全部的服务,从实例在主实例整体或部分不可⽤的情况下,完全替代主实例整体或局部⽽对外提供服务。靳辅
7、重试(Retry)
重试是在分布式系统下处理瞬态故障的⼀个基本⼿段,简单有效(当然重试的前提是要求幂等)。但是重试也是可以很危险的,它能够引起把⼀个局部⼩时间迅速升级为⼀个系统重⼤故障,严重者导致系统假死。
举个简单例⼦:如果我们的链路类似上图,这⾥会发⽣什么问题?在极端情况下,重试次数达到555*5=625次。当链路中的其中⼀个服务故障率异常的时候,那重试风暴便开启了,因为重试为服务器带来额外的开销和线程的占⽤,然后其他新来的请求⼜形成排队,这样的话就形成了类似的DDos恶性事件。根据我们平时的项⽬经验:
相对较好的是选⽤3次;且重试的时间⼀定要设定⼀定的时间间隔(因为很多时候的瞬态故障更多是⽹络抖动)尽量只在应⽤层做重试。
8、撤销(Undo)
这个没什么好说,撤销这个功能应该是标配吧。
9、冷备(Cold Standby)
冷备实际上也是冗余设计的其中⼀种体现,只是它会更侧重于“冷”,意思是当系统发⽣宕机时,这个系统是需要⼿动启动⽤于替换下线的主实例,它是跟热备是不⼀样,热备更多体现在⾃动切换。
10、熔断(Derating)
熔断本质上就是⼀种防御性设计或者策略。假设⼀个微服务体系下的系统,其中A服务调⽤B服务。系统的QPS是千级别,当时如果B服务挂掉的话A的线程绝对在短时间内占满耗尽⽽导致假死,从⽽形成⼤量A请求积压⽽导致情况恶化,最终形成雪崩。
在SpringCloud技术体系中,熔断就是Hystrix所体现的另外⼀种思想。Hystrix可以通过监控⼀段事件内的异常次数和响应速度来判断当前服务的健康状况,若服务健康状况不佳则进⾏熔断,熔断之后新的请求将不会调⽤实际的业务,⽽是通过快速失败或优雅降级的⽅式来快速给⽤户进⾏响应。
11、容错(Error Tolerance)
狭义的容错泛指⼈机交互界⾯的时候需要对⽤户输⼊进⾏输⼊校验,保证数据准确性。
⼴义的容错应该是两个具有明确边界的事物(如服务间,系统间)交互时候针对可能发⽣的⼀切主客观异常情况的防御性⼿段。常见的容错机制有failsafe、failback、failover、failfast。
failfast更多指的是快速失败。当系统遭遇⼀定概率的故障时,可预见这不是偶发性故障,然后就要开启类似断路器开关,让后续打进来的流量直接失败快速返回,避免线程积压导致系统滚雪球式崩溃。
failover指的是失效转移。slie
failsafe指的是失效安全,具体参考以下第12点。
failback指的是失效⾃动恢复,具体是指主实例发⽣故障⽽导致系统切换到备实例,在主实例恢复后⾃动转移回主实例上。这种容错在Hystrix的⾃恢复能⼒可以得到体现(详看下图)。
上图断路器的原理具体看以下三个关键参数,⼤体逻辑如下:
// 这个⽤于设定断路器触发的异常⽐例阈值,正常情况下断路器处于关闭状态。假设阈值为50%,当
在⼀定时间内(如1分钟),异常调⽤次数/总调⽤次数>50%的话,断路器打开,后续所有的请求全部调⽤getFallback()进⾏failfast.
HystrixCommandProperties.Setter().withCircuitBreakerErrorThresholdPercentage(50%)
// 上⾯说的⼀定的采样周期内的流量⾄少要达到100,Hystrix才会进⾏采样统计并计算异常⽐例,再跟上⾯设定的异常⽐例阈值进⾏⽐较。
HystrixCommandProperties.Setter().withCircuitBreakerRequestVolumeThreshold(100)
// 当断路器状态为打开后,在下⾯预设的6000毫秒时间内所有请求被快速failfast;当时间⼀过,Hystrix会试探性允许⼀个请求进来,这个时候断路器处于半开状态;如果调⽤成功,断路器⾃动关闭,然后应⽤恢复正常状态。
HystrixCommandProperties.Setter().withCircuitBreakerSleepWindowInMilliseconds(6000)
12、失效安全(Fail safe)
所谓的失效安全,就是指在特定失效的情况下,⼀个系统或者服务也不会对业务造成损害。实际上,我们使⽤token进⾏安全登录也是⼀种失效安全的体现,如果token失效了(如时间过期),⽤户是⽆
法登录的,因为正常登录需要token有⼀种约束因素,这种因素就是时间。如果时间过了,代表这种约束因素不存在或者不再有效了,登录功能就不能正常⼯作了,这个是⼀个极好的设计理念。
有点抽象?跟你介绍⼀个⽣活的例⼦。电梯之所以可以正常升降,是因为在通电的过程中,正常⼯作的约束因素(brake)是关闭的;如果某个特殊情况(如没电),这个约束因素不存在或不再有效了,brake是打开的,因此电梯是不会因为没电⽽下坠的。这个可以理解了吧?
13、优雅降级(Graceful Degradation)
服务降级跟熔断还是挺像的,只是降级来得更加温和和优雅⼀点。熔断是直接断掉防⽌异常进⼀步扩⼤⽽导致雪崩,但是我们的终极⽬标是提供尽可能多的服务,这个就是优雅降级的理念。在⼀些异常情况或者秒杀场景下,为了保证核⼼服务(如商品下单、⽀付)的正常可⽤,会放弃掉⼀些⾮核⼼服务(如历史账单查询),这就是所谓的服务降级。
在微服务框架中,⼀般会使⽤Hystrix的@HystrixCommand或Feign的@FeignClient对服务进⾏声明,然后为每个服务配置相应的fallback类,最终结合起来进⾏服务降级。
14、监控(Monitoring)
我们的系统有哪⼏个纬度的监控,估计最多就是常规的硬件状态监控。当然这⾥的监控我理解除了技
术指标监控,还更应该有业务指标监控,否则我们都在裸泳,等海⽔退下去后就⼀览⽆遗。
监控实际上是为了更好的主动防御,下图展⽰⼀下本⼈前司的⼀个运维监控与开发协同的机制(从每个序号顺序往下⾛)。⼤家可以看出,⼀套完善的告警监控系统,能够快速通知开发与运维,开发侧能够完成紧急修复并能够协同运维进⾏快速部署。在笔者前司经历中,正是有着完善的监控告警系统,⼤部分故障基本可以在业务发现问题得到有效解决(⿇蛋⼀般在晚上爆问题,那段时间太美好了)。
15、耐⽤性(Durability)
这⾥我理解的是系统或数据的耐受性。例如数据,为什么我们⼀定要持久化到数据库,因为就是要借助数据库硬件各种维度的耐受性。
16、回弹性(Resilience)
这⾥我看到⽹上有⼀个更恰当的翻译,叫“韧性”,就是说我们的设计应该在⼀些特殊情况下还能通过⼀系列的⼿段继续提供尽可能多的服务,你也可以理解为“可靠性”。实际上,我的理解是上⾯说到的基本上都是回弹性的范畴之内。
服务降级
限流
重试
汽车防撞系统
舱壁模式
防御性设计
当然,现在为了提升系统服务的回弹性,部分头部公司也会使⽤⼀些故障注⼊的办法进⾏混沌⼯程式训练,如Netflix的ChaosMonkey,阿⾥的ChaosBlade等。
最后,⼩编想说:我是⼀名python开发⼯程师,整理了⼀套最新的python系统学习教程,
想要这些资料的可以关注私信⼩编“01”即可,希望能对你有所帮助。

本文发布于:2024-09-22 20:14:46,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/364549.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:服务   系统   情况   设计   隔离   时候
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议