当前位置: 首页 > 科技观察

浅谈系统稳定性和高可用保障的几种思路

时间:2023-03-18 23:17:38 科技观察

1.前言高并发、高可用、高性能并称为互联网的三大高架构。这三者是工程师和架构师在系统架构设计中必备的。要考虑的因素之一。今天我们就来说说三H中的高可用,也就是我们常说的系统稳定性。本文只谈思路,没有太多深入的细节。阅读全文大约需要5-10分钟。2、高可用性的定义业界常用N9来量化一个系统的可用性,可以直接映射为网站正常运行时间的百分比。可用性计算公式:大部分公司要求四个九,即每年宕机时间不能超过53分钟。要实现这个目标还是非常困难的,需要各个子模块相互配合。要提高一个系统的可用性,首先要知道影响系统稳定性的因素有哪些。3.影响稳定性的因素首先,我们梳理一下影响系统稳定性的一些常见问题场景,大致可以分为三类:人为因素、不合理变更、外部攻击等。软件因素如代码错误、设计漏洞、以及GC问题、线程池异常、上下游异常硬件因素、网络故障、机器故障等,以下是对症下药。一是故障前的预防,二是故障后快速恢复的能力。下面说说几种常见的解决方法。4.提高稳定性的几种思路4.1系统拆分拆分不是为了减少不可用时间,而是为了减少故障的影响。由于一个大系统被拆分成几个独立的小模块,一个模块出现问题不会影响到其他模块,从而减少了故障的影响。系统拆分包括接入层拆分、业务拆分和数据库拆分。接入层&服务层一般按照业务模块、重要性、变更频率等维度进行拆分。数据层一般先按业务拆分,必要时也可以纵向拆分,即数据分片、读写分离、冷热数据分离。4.2解耦系统拆分后,会分成多个模块。模块之间存在强依赖和弱依赖。如果是强依赖,那么如果依赖方出现问题,也会牵连到问题中。这时候就可以梳理出整个流程的调用关系,做成弱依赖调用。弱依赖调用可以通过MQ的方式解耦。即使下游出现问题,也不会影响到当前模块。4.3技术选型可从适用性、优劣势、产品口碑、社区活跃度、实战案例、可扩展性等方面进行全面评估,选择适合当前业务场景的中间件&数据库。前期调研一定要充分,先比较、试验、研究,再做决定,磨刀不误砍柴工。4.4冗余部署&自动故障转移服务层的冗余部署很容易理解。冗余不足以让一个服务部署多个节点。每次出现故障,都需要人工干预来恢复系统,这势必会增加系统的不可服务时间。因此,系统的高可用性往往是通过“自动故障转移”来实现的。即节点宕机后,需要能够自动去除上游流量。这些能力基本上都可以通过负载均衡检测机制来实现。到数据层就比较复杂了,不过一般都有成熟的方案可以参考。一般分为一主一从、一主多从、多主多从。但是总的原则是数据同步实现多slave,数据分片实现多master。故障转移时,通过选举算法选出新的主节点,然后对外提供服务(这里,如果写时没有强一致性同步,故障转移时会丢失部分数据)。具体可以参考RedisCluster、ZK、Kafka等集群架构。4.5容量评估系统上线前,需要对整个服务使用的机器、DB、缓存的容量进行评估。机器容量的大小可以通过以下方式进行评估:指定预期的流量指标——QPS;指定可接受的时延和安全水位指标(如CPU%≤40%,核心链路RT≤50ms);通过压测评估单机在安全水位以下所能支持的最高QPS(建议通过混合场景验证,比如根据预估流量比同时压测多个核心接口);最后可以估算出具体的机器数量。除了QPS,DB和cache的评估也需要评估数据量。方法大致相同。系统上线后,可根据监控指标进行扩容和缩容。4.6快速服务扩展能力&防洪能力现阶段,无论是容器还是ECS,简单的节点复制和扩展都非常容易。扩展需要评估的关键点是服务本身是否是无状态的。比如最大下游DB连接数支持当前服务扩展多少个单位?扩容后缓存是否需要预热?重型策略等因素需要提前准备和完整的SOP文件。当然,最好的方法是进行演练并实际手动进行准备。泄洪能力一般是指在冗余部署的情况下,选择若干个节点作为备份节点,通常承担一小部分流量。当流量高峰来临时,通过调整流量路由策略,将热点节点的部分流量转移到备份节点。与扩容计划相比,成本相对较高,但优势是反应快、风险小。4.7TrafficShaping&FuseDegradationTrafficshaping也称为限流,主要是防止意外流量把服务搞垮,而fusion是针对自组件或者依赖下游故障,可以快速失效防止长期阻塞引起雪崩。关于限流熔断器的能力,开源组件Sentinel基本都有,使用起来也很简单方便,但是有一些需要注意的地方。限流阈值一般是配置为服务的某种资源所能支持的最高水位,需要通过压力测试来评估。随着系统迭代,这个值可能需要不断调整。配置过高,系统死机时不会触发保护,配置过低,会造成误伤。熔断降级——接口或资源熔断后,需要根据业务场景和熔断资源的重要性评估是抛出异常还是返回自下而上的结果。比如下单场景下的扣库存接口断了,由于扣库存是下单接口的必要条件,所以只有熔断断了才能抛出异常,导致整个链路失效,roll后退。如果获取商品评论相关的接口被炸了,那么可以选择返回一个空值,不影响整个链接。4.8资源隔离如果一个服务的多个下游同时被阻塞,单个下游接口没有达到熔断标准(比如异常和慢请求的比例没有达到阈值),就会导致整个服务的吞吐量下降,更多的线程被占用,极端情况下甚至会导致线程池被耗尽。引入资源隔离后,可以限制单个下游接口可以使用的最大线程资源,保证整个服务的吞吐量在被炸掉之前尽可能少的受到影响。说到隔离机制,我可以在这里展开。由于每个接口的流量与RT不同,很难设置一个合理的最大可用线程数,而且随着业务迭代,这个阈值也很难维护。这里可以使用共享加独享来解决这个问题。每个接口都有自己独占的线程资源。当独占资源满了,就使用共享资源。共享池达到一定水位后,强制使用独占资源,排队等待。这种机制的明显优点是可以在保证隔离的同时最大限度地利用资源。这里的线程数只是一种资源,资源还可以是连接数、内存等。4.9系统保护系统保护是一种不分青红皂白的限流。简言之,就是在系统即将崩溃前,对所有进水口实施无差别限流,当系统恢复到健康水位时停止限流。具体点就是结合应用负载、整体平均RT、入口QPS、线程数等几个维度的监控指标,实现系统入口流量和系统负载的平衡,让系统最大程度地运行在确保整体系统稳定性的同时尽可能多地提高吞吐量。4.10可观察性和告警当系统出现故障时,我们首先需要找到故障原因,然后解决问题,最后恢复系统。故障排除的速度在很大程度上决定了整个故障恢复的时间,而可观察性的最大价值在于快速排除故障。其次,基于Metrics、Traces、Logs三大支柱配置告警规则,提前发现系统可能存在的风险和问题,避免故障发生。4.11变更过程三招变更是可用性最大的敌人,99%的失败都来自变更,可能是配置变更、代码变更、机器变更等。那么如何减少变更带来的失败呢?灰度可以使用一小部分流量来验证更改的内容,减少对用户群的影响。回滚出现问题后,可以有一个有效的回滚机制。如果涉及数据修改,发布后会写入脏数据,需要可靠的回滚过程来保证脏数据的清除。可观察通过观察变化前后指标的变化,可以在很大程度上提前发现问题。除了以上三招外,其他的开发过程也要规范,比如代码控制、集成编译、自动化测试、静态代码扫描等。五、总结对于一个动态演化的系统,我们没有办法降低概率故障率为0。我们能做的就是尽可能地预防和缩短发生故障时的恢复时间。当然,我们不需要一味追求可用性。毕竟在提高稳定性的同时,维护成本和机器成本也会增加。所以需要结合系统的业务SLO需求,适合的才是最好的。如何保证稳定性和高可用是一个非常大的命题。这篇文章并没有太多深入的细节,只是讲了一些整体的思路,主要是为了大家有一套系统的框架可以参考。最后,感谢耐心阅读的同学们。