系统设计 - 高可用思想简介
一、如何衡量高可用
软件系统在运行过程中,会出现各种各样问题,如何确保系统出问题时,不对客户业务产生影响。业界提出了 SLA 的定量的指标,即服务提供商和客户约定,全年服务的可用性要达到多少分钟。提出 SLA 主要也是给客户信心,同时约束服务厂商提供更可靠的服务;
例如:服务提供商对外承诺 5 个 9(即 99.999%),那全年服务失效时间最大为 365*24*60*0.001%=5.26min,也就是说服务最多允许 5.26 分钟的不可用时间,超过了这个时间的话,可能就涉及对客户赔偿了。
SLA:服务等级协议(简称:SLA,全称:service level agreement)。是在一定开销下为保障服务的性能和可用性,服务提供商与用户间定义的一种双方认可的协定。通常这个开销是驱动提供服务质量的主要因素;
二、高可用的价值
用户价值
用户更放心
毫无疑问,世界上几乎没有不会产生 bug 的软件;那用户在使用软件之前其实心里就会默认这个系统会出 bug,而 5 个 9 以上的 SLA 可用性承诺,能最大程度的减少用户的顾虑
带来最直接的经济价值
每年大家会发现,新闻报道出来某某某云服务中断半小时,上云的客户业务中断半小时,导致直接受损利益千万级别;如果能保证全年的可用性,那客户也就不会由于突然的软件系统失效,导致经济受损
服务质量的好评
这个标准是很灰度的,平时不出问题,大家可能不会喷客户服务;一旦客户服务出问题,可能瞬间就在网上发酵,某某软件烂的惨不忍睹等等
自身价值
全局的系统视野
要想达到 5 个 9 的可用性,需要针对系统中所有的组件进行高可用改造优化,同时需要考虑周边依赖服务的高可用性,一旦有个组件不可用了,如何快速发现并隔离故障,除此之外,还要考虑整体的性能,包括计算资源、网络资源、存储资源等,如果保证可用的基础前提性,尽可能的高性能;这些东西做完后,会发现对技术人员统筹全局的思维大有帮助
减少不必要的 oncall 工作安排
达到 5 个 9 以上的系统,运维自动化做的都很好,包括监控、告警、自恢复、故障应急资料之类的;一般情况下,是不需要很多 oncall 在值守运维工作了
生活质量提升
系统高可用,那大家精力就可以从无止境的修 bug 中,转移到设计更好的软件特性上,确保软件更高的高可用以及性能,实现良性循环,然后就能早点下班了
附加的一些意向不到的收获
专利、论文等
为了达到 99.999%的高可用,总有一些黑科技被引入,这些黑科技如果业界没有人想到的话,就可以转换成专利或者发表论文了
三、高可用的设计思想
1、设计思路
一般从我的经验来说,设计一个系统可用性框架,有三个思路:
正向端到端分析系统的数据流向,然后分析数据经过的所有组件的可用性,针对不可靠的组件,进行改造
参考业界优秀的大型系统的设计理念(比方说可以看操作设计、k8s 或友商等),横向对比一下,业界已经做了哪些能力,我们的差距在哪里
现网 bug 回溯改进,进行举一反三,层层迭代,优化系统可用性
2、常见的故障场景
通常,在正向端到端分析系统可用性的时候,重点会考虑如下的故障场景
网络问题
网络连接异常
网络带宽超时拥塞
性能问题
cpu 高
内存高
硬盘空间快满了
中间件负载太高(数据库、redis、kafka、etcd 等)
安全问题
异常客户大批量请求攻击
网络攻击
运维问题
监控问题
平滑升级问题
硬件问题
硬盘损坏
机房掉电
网卡出问题
周边依赖管理问题
周边依赖服务宕掉,不可用了
周边服务超时了
......
3、方法论
为了防御形形色色的故障,保障系统的高可用性,一般会从如下几个方法进行设计系统
高可靠架构
对系统组件进行容灾架构部署,防止单系统失效,服务整体不可用
集群的使用方式,可以是主备、集群模式,或者自治的单个系统,具体选型,看业务需要
集群的机房最好跨机房、跨地域,鸡蛋不要放到一个篮子里面,最大程度减少单点故障
缓存
针对周边服务的依赖,可以通过缓存进行解耦,当周边服务出问题后,可以通过缓存延缓系统失效时间,给周边服务的修复预留一段时间
针对中间件的访问,可以通过缓存加速访问,提升性能
缓存的话,通常可以使用二级缓存,中间件缓存+本地内存的缓存
过载保护
大型的系统,一般都绕不开过载问题,而常见的现网故障有很大一部分,也是由于过载引发的系统瘫痪,导致用户使用收到影响,如何设计好对过载的防护,是个很重要的工作。主要包含如下几个部分:
过载发现
监控系统的构建,明确监控哪些指标,至关重要,根据自己系统的特性,设计关键的指标
实时流量
系统 cpu、内存指标
系统处理时延
......
过载保护
流控
流控可以分为多个维度,比如系统总体的承载能力是多少,每个用户的流控是多少,每个 api 的流控是多少等,按需选用最合适自己业务的
降级
当系统万一出现问题时,是不是可以考虑降低用户执行速度,确保用户业务最终执行成功;有限保证 vip 客户,在保证普通客户;有限执行核心业务,在执行非核心业务等等,具体选型的话,也是看系统所面向的用户业务具体是什么样的
熔断
这个基本上是迫不得已的手段,走到熔断这里,一般情况下是系统可能由于某一特殊原因,无法在支撑后续大流量的接入,一旦不处理,放任后续流量接入的话,系统负载能力可能会恶化(资源竞争越来越厉害,可能谁都抢不到,陷入死循环),最终导致所有用户都无法使用
这里熔断,断的是导致系统异常的流量,将这类流量拉入黑名单,主动限制该流量的下发频率;如果后续该流量回复正常,系统在自动解开限制
弹性能力
以上几点都是属于防御手段,一般情况下都是会导致用户的请求失败的;而应对这个负载问题,最根本的其实是提升系统面对突发流量的弹性能力,如果系统可以立刻处理掉这些突增流量,那么就不用使用防御手段了。针对弹性能力,有如下考虑点:
系统组件可弹性伸缩
中间件可弹性伸缩
过载预测
以上都是过载流量过来的时候,做的一些方案,可能会由于弹性不及时,导致请求失败;另一种思路,可以从流量过来之前,进行流量的提前预测,将资源提前准备好,最大程度的降低流量对资源的瞬时冲击
重试
万一某次请求在系统中失败了,可以通过增加重试逻辑,让请求多试几次,增加成功率
确保重试接口,幂等的
限制重试次数,防止一直重试,在系统负载过高的时候,失败重试过多压垮系统
平滑升级
系统在演进过程中,需要不断迭代版本,如何保证客户正在运行的业务不受影响,也是一个需要重点考虑的问题,通常实现的时候,会涉及如下几个方法
进程支持优雅退出
正在执行请求的进程,在接收到升级信号时,不要暴力退出,等请求执行完毕后,在推出
灰度切流
支持升级的时候,将某个集群的流量切换到其他集群
滚动升级
多集群的组件,支持一个一个的升级,避免全量升级后,引入 bug,系统不可用
......
以上的设计思想,是实战中的常用一些手段,除此之外,还要重点考虑成本问题,不能因为 5 个 9 的可用性,导致成本骤增,如果这样的话,可能要看一下整体的架构设计是不是出问题了,从架构优化。
评论