一次高可用架构设计实战总结

Posted 云原生Lab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一次高可用架构设计实战总结相关的知识,希望对你有一定的参考价值。

一、引言


说起高可用架构,印象最深的是小时候看TVB港剧《冲上云霄》其中的一个片段,当时男主问培训的学员们,为什么一般大型飞机2个引擎其实也可以飞,但要装4个引擎呢,那样岂不是更贵?后来女主回答道,因为在飞机飞行到高空的时候,如果其中的一个引擎发生了故障,这时就不用进行紧急迫降,在降低因为故障所造成的影响同时,还能够完成整个航线。虽然说从表面上看成本确实是提升了,但是因飞机自身可靠性的提升所带来的收益更是正比提升。
回到系统高可用架构设计,人的认知思维逻辑往往是局限在正向思考能力的延展,我们很少会去思考所开发的系统是否真的在故障时,能够具备足够的容错性。另一方面,大多数时候其实也知道架构或业务逻辑是不合理的,但是在业务驱动的过程中,直到业务受损前是没有足够的精力或资源对系统架构优化。
最近给一家头部客户从零到一完整的对业务中台系统设计高可用解决方案,在准备阶段翻阅了大量相关书籍,现在在回过头来看,书中提及的那些理论及方法论,不结合业务来看,是这么的纸上谈兵。理想中的架构是一方面,但其更多的对软件架构“应然”是怎样的所做出的解释说明。现实情况错综复杂,架构往往是在业务发展、时间、投入成本等综合因素的权衡利弊之下,得出的结果,说架构设计是平衡的艺术也不为过。下文中结合这次的方案设计,记录下这次在整个方案设计中的一些个人反思总结。

二、序章

年前接到组织交下来的任务,国内一家新零售客户要对他们的架构做高可用改造,把当前云上单可用区的应用部署到两个可用区去,这活现在交付项目组上几个技术Leader都搞不定,老大让我把这活接了去。原先也做过一些类似的工作,心里暗爽,看上去这活不难啊,不就是把原先申请在一个可用区的服务器资源,在另外一个可用区也部署一些实例节点么,火速定了机票酒店,以一种“救世主”来carry全场的心态到了客户现场,大概和项目上的同事梳理了下他们架构现状。客户使用的架构大多是基于阿里云的中间件PaaS服务,大致用到了如slb负载均衡器、csb网关、edas服务治理中间件、ack云托管kubernetes集群、drds分布式数据库、还有包括redis、rocketmq这些缓存、消息中间件等。

既然是云托管服务,那也没什么可做的,直接把ack接入的ecs服务器实例一半迁移到另外一个可用区,这事就搞定了啊。于是就把PPT大笔一画,和客户约了时间跟客户做汇报去了。

回忆起当天的汇报情况,简直可以用灾难来形容了,即使事情已经过去了将近2个月,但这场噩梦始终挥之不去。客户看了眼架构图开始提问:“我们现在用的springcloud框架开发的分布式架构,整个链路至少10多次的服务链路请求,跨可用区所带来的响应时间增加你有考虑过吗,改造后的性能和现在的性能你们有评估过差异吗?” “跨可用区部署访问redis的延迟是多少测过吗?” “跨可用区部署之后,你的负载均衡器是不同可用区各接一个还是共用一个”,经过一连串的灵魂拷问之后,客户已经略显不耐烦了,质问我说,“你连最基本的业务场景,系统架构都不了解,这方案怎么证明我们线上不会出问题呢?”。回忆起当时的场景,当时的语气用词会可怕十倍,于是当下连声向客户致歉,表示一定会结合客户的实际场景出发在做改进。


三、思过

在被客户的一连串问题无所应对吓得冷汗直流之后,又经历了大概1-2周的时间和项目组的同事、客户反复沟通,此时项目上的进展并不顺利,对于各个云产品的专业度也缺乏了解。终于挨到了过年。这次的春节可能是我工作以来最丧的一次,我开始复盘有哪些问题是之前没有考虑到的,慢慢地之前没理清楚的问题开始逐渐问题变得清晰,然后也开启了整个项目逆风翻盘之旅。


1. 定义目标

犯的第一个错是没有和客户对齐关于高可用的定义。关于系统架构高可用,从业务开发来看,可能是如何通过服务治理框架对业务进行限流降级;从系统架构师的角度看,则是当发生未知故障时,如何保障系统对于真实世界各种异常事件的容错能力。在分布式架构中,可以是小到云服务的一个实例挂了如何保障高可用,又或是当一个机房、一个地区、甚至是一朵云挂了如何做整个的架构高可用。对客户究竟要做到什么程度的高可用,这是先决要达成的核心要素。基于客户目标,然后逐一确认当前云产品的高可用能做到什么程度。


2. 架构分层

其次,在做解决方案时没有从全局视角出发看整体架构,当第一时间拿到客户的整体应用部署架构图时,觉得分布式架构长得都差不多,并没有想太多如何从架构视角看应用部署图。而在绝大多数的应用部署图上,并不会清晰呈现出链路的走向,云服务具备到怎样的高可用能力等细节。


3. 性能

客户反复提到的的性能问题,可以明确是其关注的核心问题。一开始我便遗漏了一个重要的细节,即客户作为新零售电商有自己的门户,并且平均每个月都会做大促活动,这次要做的高可用架构优化针对的也是业务中台系统。在过往的项目经历中,我确实认为性能的提升一定是在分布式架构是在应用多可用区部署的前提下去设计的,而跨可用区本身带来的网络延迟几乎是可以忽略不计的,而从没有思考过一个核心的问题,即云厂商是否应该为客户的业务系统提供高可用的能力前提下做性能的兜底。


4. 服务成本
高可用必然会带来一定的成本预算的增加,即便是先不将代码改造、运维管理等软性成本计算在内,对于做多活还是容灾架构,也会造成稳定性、资源成本上的巨大差异;除了底层资源成本的提高以外,另外需要考虑的是架构设计中是否包含了需要依赖于其他服务或服务功能特性。

5. 故障恢复时间

单从分布式理论CAP,结合业务场景来看,阿里内部核心业务的高可用最佳实践实际上已经实现了单元化,即某一个机房因为故障整体不可用,通过流量切换,几乎能够对应用在秒级-分钟级完成切换。恢复时间依赖于目前正在做商业化的可用区工具实现,这又回到了关于服务成本的话题。客户最终愿意为整套架构快速恢复,支付多少预算?


6. 运维管理


运维管理无论是在任何情况下,都必须要去考虑的事情,如果设计的高可用方案对整体软件发布流程会有很强的侵入性,充斥着大量的手动操作,在遇到问题时难以定位,故障恢复时需要人工校验恢复,那整个架构必然是存在诸多问题的。


7. 云服务

客户所使用到的绝大部分都是云服务,每个云服务本身的高可用如何做的你真的都知道吗?而每个云服务官方所述的高可用能力是否和客户的期望能够对齐呢?显然这个问题原先是被忽略的,对于云计算如果不太了解的工程师,常犯的一个错误是认为云产品本身的高可用能力由云厂商兜底。结合到真实的业务场景,这实际上是一句正确的废话,因为本质上每个云产品的高可用能力是没有办法完全对齐的,在实际过程中,往往会出现较大偏差,只有踩了坑知道痛了才能发现问题。


8. 性能验证

关于跨可用区网络延迟,这是一个绕不开的话题,只要有物理距离,网络延迟是必然的,而客观地说,客户提的问题并非无理取闹。在同可用区、跨可用区不同并发去请求业务应用接口,在去读写redis、数据库等,性能差异和理论差异是否有较大差异,实际上是需要有数据作为方案支撑的。


四、涅槃

在理清楚整个项目中的核心问题之后,便开始将一个个问题逐个击破。首先是关于架构分层,我将原先的部署架构图转换成了一个完整链路中从流量入口层到应用服务层到数据持久化层的三层架构。并对每个云服务组件属于哪一层做了明确的表示。

有了清晰的架构分层之后,后续的讨论就变得异常简单了。回到核心问题,客户期望的是在高可用的前提下满足大促场景下的高并发能力,而现在所使用到的DRDS分布式数据库由于做了分库分表,在业务数据读写表时,在最差的情况下,流量可能会经过多次的跨可用区调用,造成性能的直线下降。而客户目前也确实没有足够的精力去对现有系统做单元化改造的预算和能力,无法做到数据库层的多活架构。在客户做了权衡之后,最终的结论是在流量接入层和应用服务层做多活,而数据持久化层做容灾。
然后是关于核心业务的性能影响,关于这个问题得从三个方面着手。
  • 流量接入层该怎样去路由流量到两边的可用区。

  • 业务服务层如何解决因跨可用区所带来的网络响应延迟。

  • 数据层DRDS分布式数据库如果是以主备模式部署在两个可用区,那其中一个可用区在访问DRDS数据库时,响应延迟将会比同可用区调用的另一个可用区有显著增加。

基于以上这三个因素,在应用多活部署,数据库主备的模式下,同时又要满足大促的性能需求,那整体的设计思路结合实际业务特点,我们决定将流量按照日常1:1流量均匀路由到两个可用区,而在大促活动时,确保80%以上流量负载到主可用区,在大促的时间段,备可用区的作用更多的仅作为基本容灾环境,牺牲一部分的可靠性换取性能提升。

关于如何解决因跨可用区所带来的网络响应延迟,这部分涉及到两种不同的跨可用区请求的方式。一种是从流量入口层进入的南北向流量请求,还有一种则是服务则是服务与服务之间的东西向流量请求。
a. 东西向流量
东西向流量请求部分的设计思路是通过中间件服务治理框架层来实现的。服务注册到Nacos(阿里云注册中心、类似Eureka)时,会带上所在可用区的标签字段,当A服务通过注册中心寻找到B服务时,会优先将服务路由到同可用区的B服务。在分布式架构中,东西向流量的请求往往是被忽视的一环,当链路较长时,耗费在跨可用区调用的请求响应延迟将极大的影响到业务系统的吞吐量。
b. 南北向流量
南北向流量请求处理相对来说则更加复杂。考虑到在大促和普通运行两种不同的场景,面临的第一个问题是在什么组件位置控制流量并基于预期情况按比例将流量负载到不同的两个可用区。
  • 方案一:一套SLB负载均衡器后接两套CSB网关,由SLB做权重比控制,CSB到EDAS的流量同东西向流量实现同可用区亲和性。

  • 方案二:两个可用区CSB前各接一套独立的SLB,通过WAF对流量按比例分配,CSB到EDAS的流量同东西向流量实现同可用区亲和性。

  • 方案三:放弃CSB到EDAS的南北向流量同可用区亲和性,WAF对访问流量不做任何流量比例规则限制。


在查阅了CSB产品的相关文档之后,发现原来CSB网关可以支持接多套SLB,但SLB后端无法接入多套CSB网关。因此也就在方案二和方案三之间进行权衡。考虑到在真实的业务场景下,南北向流量和东西向流量完全同比实际上很难做到,而CSB到EDAS的路由亲和性最多只能带来减少1-2次的跨可用区调用,效果十分有限,另一方面用户还要对WAF的后端流量比例进行定义,增加了管理上的复杂度。因此在权衡利弊之后,我们选择了方案三。

c. Kubernetes的实例部署

在整个架构蓝图基本成形之后,又有一个新的问题需要解决。无论是在日常1:1部署实例,还是在大促活动时以8:2的比例将pod部署在两个可用区。kubernetes的部署逻辑并不会像业务应用部署在指定服务器一样,而是会基于其调度器将pod实例部署在满足条件的可用区。在极端情况下,完全会出现一个可用区完全没服务pod,或主可用区有1个pod,而在备可用区有9个pod的情况。在这类场景下,性能不仅无法提升,还会造成部分服务负载过高影响业务的稳定性。尤其客户在每次大促过程中和接受,都会对其应用和底层资源进行扩缩容动作。

Kubernetes虽然支持Pod和Node级别的亲和性和反亲和性策略,但都还差点意思。在一次真正的扩缩容过程中,让用户每次都对Node节点打标,大量的人工介入在整个部署流程中,这几乎是不可接受的。

为此,又继续查阅起了文档,这就要用到接下来讲的 Kuberentes内置特性,topologyKey 了。


顾名思义,topology 就是 拓扑 的意思,这里指的是一个拓扑域,是指一个范围的概念,比如一个Node、一个机柜、一个机房或者是一个地区(如杭州、上海)等,实际上对应的还是 Node 上的标签。这里的 topologyKey 对应的是Node上的标签的 Key(没有Value),可以看出,其实 topologyKey 就是用于筛选Node 的。通过这种方式,我们就可以将各个 Pod 进行跨集群、跨机房、跨地区的调度了。

topologKey不同于nodeAffinity参数来说,提供的是一种软亲和的部署能力,pod在做跨地区、跨机房的部署过程,会尽可能的按比例将pod节点在不同机房部署。当底层ECS计算资源在两个可用区1:1,且资源充足时,K8s调度器则会将pod按照1比1的比例均匀部署在两个可用区,同样的如果底层计算资源是8:2,或者是7:3,pod节点也尽可能按照比例对底层计算池打分,并计算部署在哪个可用区的ECS实例上。


但有了topologyKey这一大神器之后,并不是说部署过程就完全高枕无忧了。在一次应用上线的版本发布日中,在一两个小时内上线几十甚至几百个服务是十分常见的事情。K8s的滚动升级机制,则是先部署一个新版本的实例,然后在注销一个。因此当底层预留计算资源不足时,即便是设置了topologyKey,依然会出现实例分配不均的情况。为此,EDAS-ASK(阿里云kubernetes托管服务)必须提供给用户能够查询到不同可用区部署情况的API接口。此外,在扩缩容或者发布时,pod没有按预期部署至多个可用区,也需要提供给用户一个能够校正pod实例分布情况的重启应用功能,以便于用户判断在业务低谷时重启实例节点。

至此,架构整体的设计基本达到客户的预期。剩下的就是云产品自身的功能迭代了。


五、总结

在将近两个月的时间和客户、其他同部门同事反复讨论整体方案,从第一次会议时被客户按在地板上摩擦,整个方案至少改了5个大版本。而在近期的最后一次会议中,终于把整个架构逻辑闭环,实属不易,此次也只是初步明确了整体方案,具体在POC验证过程中会遇到哪些新的问题尚未知晓。
实际架构中涉及到的关键要点和考虑因素实际上远不止文中所述的这些。 关于高可用架构的实现,实际上并无范式,也很难总结出一套标准打法和标准。架构设计有趣的不就是在时间、资源、目标几个条件下做出平衡么。但大道至简,在这次的项目经历里,还是能总结出一些关于高可用架构设计过程中的方法论。
  • 每个客户要解决的问题是不同的,首要做的事情必须是对客户的业务场景、技术架构上下文全面了解。不要遗漏链路的任一一环。

  • 明确了用户所使用到的服务组件及架构之后,云产品的高可用级别、性能等要素是务必要都研究透彻的。

  • 前提和用户对齐目标投入预算,其中包含了优化后的资源成本的增长、开发成本以及后期运维成本。

  • 故障恢复时间,实际上阿里云上关于故障恢复有许多方案可控选择,最简单的流量切换方式可以基于DNS(10分钟内恢复90%流量),也可以基于MSHA(秒级)实现同城多活、异地容灾等大型容灾架构。但每种方案涉及到的成本、系统复杂度也各不相同。







以上是关于一次高可用架构设计实战总结的主要内容,如果未能解决你的问题,请参考以下文章

高可用架构设计之道,实战案例直面流量洪峰

大厂架构经验之谈:支付系统高可用架构设计实战,可用性高达99.999!

百亿级流量大型分布式系统平台架构设计实战

百亿级流量大型分布式系统平台架构设计实战

百亿级流量大型分布式系统平台架构设计实战

百亿级流量大型分布式系统平台架构设计实战