查看原文
其他

道路千万条,安全第一条:微服务稳定性保障的“痛”!

刘俊海 K8S中文社区 2019-11-18

微服务改造中,挑战最大的就是拆分之后的稳定性保障,拆分之后链路复杂、故障点众多,需要一套体系化的稳定性保障机制。


1. 稳定性保障的目标

微服务稳定性保障需要从事前、事中和事后全方位进行考虑。微服务架构下,应用程序、依赖服务、网络、硬件等都有可能出现故障,稳定性设计和保障的具体目标如下。

故障预防,尽可能减少故障的产生,绝大多数稳定性问题和稳定性故障发生都有一定的诱因,并且一般是在多种拦截手段均失灵的情况下故障才会发生,如果我们在故障发生前制定完备的稳定性保障措施,可以最大限度地减少稳定性故障的发生。


故障快速定位,完全不出故障的业务是不存在的,关键是出故障时能够快速发现故障,只有及时发现,才能在最短时间内采取相应的解决措施。


故障快速止损,发生故障后第一时间要进行业务止损,恢复业务的正常运行,故障深层次的具体原因可以事后再分析和复盘解决。


2. 稳定性保障的6个维度

系统故障点很多,稳定性保障就是对故障点进行管理的过程。可以从故障点管理的角度将整个稳定性设计和保障分为如下隔离、冗余、容灾容错、变更管理、时间相关故障管理与运维友好6个维度。


(1)隔离

影响系统稳定性的不稳定性因素和故障点很多,从稳定性保障的角度看,很自然的想法就是,如何尽量减少如此多的故障点给系统稳定性带来的隐患,比如某电商业务有200个微服务组成,如果这100个微服务中的任何一个出问题,导致业务不可用,那么系统的可用性就会很低。业务层面如果能够梳理和抽象出保障业务核心运行的最小系统(比如上面提到的电商业务最小系统包含的服务可能会小于50个,其他都是增值和支撑性的服务),同时将最小系统之外的不稳定性因素从最小系统中隔离出来,就可以大大增强系统的稳定性和健壮性。因此,稳定性设计的第一个原则就是“隔离”,通过各种隔离机制,将核心服务之前的故障点隔离出去,保证核心服务的可用性。


(2)冗余

通过隔离,可以减少绝大多数不稳定性因素对系统稳定性的影响,但如果核心服务或核心服务所在的环境出问题,就无法从隔离中受益。我们需要有相应的机制保证核心业务的部分单元出问题时,业务整体运行不受大的影响,这种机制就是冗余。通过服务级别、机器级别、集群级别、机房级别等多种维度的冗余,我们可以保证:即便核心服务出问题,也可以通过相应的流量切换策略,将流量切到冗余节点上,保证业务不受影响。


(3)容灾容错

通过冗余可以保证核心服务及其部署环境变化时的系统稳定性,但如果系统外部输入有变化,比如遇到突然大流量、异常流量或者突发的安全攻击,而系统事先没有相应的应对机制,则业务很可能瞬间被击垮。因此,稳定性设计的第三个原则是“容灾容错”,通过构建多维度的容灾容错体系,保证系统面对异常输入时,仍然能够提高稳定的输出能力。


隔离、冗余及容灾是解决外部环境与输入导致的各种故障点和风险。


① 隔离强调的是将微服务架构体系中非核心服务导致的故障隔离出去,减少非核心因素对业务核心的稳定性影响,隔离工作做好之后只需要考虑核心服务的稳定性。


② 冗余解决的是核心服务面对各种环境变化时的稳定性应对,比如服务故障、交换机故障、网络故障、机房故障等,通过各种层次的冗余和流量调度机制,保证业务面对各种硬件和环境变化时仍然可以通过冗余切换提供稳定的服务。


③ 容灾解决的是面对各种输入变化时的稳定性应对,比如突发大流量、异常请求、安全攻击等,容灾容错保证系统面对各种输入突变问题时,稳定性不受大的影响。通过隔离、冗余和容灾,解决了非核心故障点风险、环境和输入风险,保障了业务最小子系统面对各自外部变化时均能够提供稳定输出。


(4)变更管理

通过隔离、冗余与容灾可以排除和应对业务最小子系统的各种外部稳定性风险,变更管理、时间相关故障管理是为了解决核心系统自身的稳定性问题。绝大部分稳定性故障都是由变更引起,系统如果长时间没有任何变更,很少会有稳定性问题,因此服务稳定性保障的关键一环是严把变更这一关,保证变更质量。


(5)时间相关故障管理

服务没有变更时,有一类故障很少发生并且很难发现,就是随时间变化而产生的ID越界和溢出,这类故障平常测试时很难发现,并且发生时会对整个系统产生很大的影响,需要从设计层面开始把控,比如随时间变化的ID字段尽量使用int64。


(6)运维友好

隔离、冗余和容灾减少了核心服务的外部稳定性风险,变更管理和时间相关故障管理保证了核心服务自身的稳定性。上述5种措施构成了业务稳定性预防的整个闭环,但即使设计得再好,也不能完全杜绝稳定性故障,稳定性风险只能最大限度地减少,因此服务的研发生命周期中,还需要加上运维友好的考虑。设计时需要针对稳定性问题的快速发现进行特别考虑,如日志怎么输出,统计信息如何收集等。通过运维友好设计,比如log、metric和trace等方式的良好设计与运用,建立全方位多维度的故障发现机制,保证出现问题时可以快速发现和快速止损,最大程度上减少稳定性风险的影响。


3. 稳定性保障的设计建议

总之,隔离、冗余和容灾、变更管理、时间相关故障管理和运维友好构成了整个的稳定性保障体系,下面会对这几个维度详细展开讨论。


(1)隔离机制

隔离机制的指导原则是将变和不变、重要和非重要区分开来,变更是稳定性故障的最主要的来源,将容易发生变化的部分从核心服务和核心流程中剥离开来,减少核心部分的变更,可以保障核心系统的稳定性。


隔离机制的一大手段就是解耦,通过解耦可以把核心服务和非核心服务隔离开来,同时核心服务访问非核心服务时,通过熔断、超时和重试等机制,最大限度地保障非核心服务故障不会影响整体的稳定性。


异步化是流程隔离的主要方式,为了减少非核心服务故障对核心服务的影响,可以将一些非核心流程异步化处理。


为了减少对核心服务的影响,核心服务建议单独部署,如果特殊情况下需要和其他服务混部,一定要保证有精细的资源隔离机制,保证不会因为其他服务资源使用不当,影响核心服务的稳定性;同时核心服务用到的一些关键基础服务、关键数据服务也建议隔离开来,分开部署,避免其他服务出问题对核心流程的影响。


(2)冗余

为了保证故障时冗余机制的可用性,事先需要进行完善的冗余容量规划,各级故障发生后,剩余容量足够承载峰值流量,一个大体的原则是:机房内尽量满足N + 2冗余,2用来冗余(应急变更故障和其他故障),机房间N + 1冗余,1个机房挂掉后,剩余机房能承载所有流量。


为了尽量避免冗余同时失效的情况,冗余副本之间需要相互独立,完全对等,不能相互依赖,机房内副本跨交换机部署(此时一般也能保证跨机柜),如果有多机房冗余的情况,各机房独立,不能有完全相同的依赖。


系统为了构建完善的冗余机制,服务设计时尽量无状态,无状态的服务随时可部署启动,方便水平扩展。


为了用好冗余,常态下,需要支持灵活的流量调度策略,具体包含服务发现、流量路由、负载均衡等;节点故障时,通过健康检查、故障节点剔除、动态路由切换等机制,可以平滑地将流量从故障节点切到冗余节点,保证节点故障不会影响系统整体稳定性。


(3)容灾容错

为了减少异常流量对系统的影响,服务开发和设计时需要采取防御性编程,提前想到可能面临的种种异常情况,并针对性地进行防御和解决。


服务可以通过降级和限流,减少突发大流量对系统的冲击,保证系统稳定输出,为了保证降级和限流操作的即时性,系统需要支持配置的动态修改和生效。


(4)变更管理

为了提高变更的质量,减少变更带来的稳定性风险,需要从测试、上线和规范等多角度进行保障。


测试上,通过建设线上/线下多级测试环境,比如线下的联调环境、集成环境、仿真环境,线上的预发布环境,通过不同用途的环境,提高各种场景的模拟能力,提高故障拦截率。


针对变更,需要制定完善的变更规范,变更时严格按照规范进行,再小的变更都可能会产生稳定性隐患,因此变更时一定要加强稳定性意识,变更的每一步操作都要进行各项监控项检查,如果出现问题立即进行回滚。


对所有变更操作,不管是服务变更、配置变更和数据变更,均要采用灰度机制,灰度观察没有问题后再放量,关键特性需要设置相应的特性开关,方便根据需要灵活地对特性进行开启和关闭。


最后,针对变更过程中比较容易遇到的问题,可以梳理出一套变更反模式出来,供其他人作为反面例子参考,下面是梳理的之前线上服务遇到的典型变更反模式。


1)代码搭车上线。

比如由于缺乏有效的代码修改管理机制,某产品线由于代码搭车上线,出现过多次线上故障,并且由于变更时涉及的修改比较多,导致问题定位和追查时非常困难。


2)服务回滚时遗漏回滚代码。

某业务隐私页面改动,首页浮层上线有问题,导致呼叫量下降,上线回滚后恢复;回滚后没有第一时间把代码回滚掉,其他人上线时将未回滚的问题代码再次带上线,导致连续两天出现系统故障。


因此,服务回滚的时候,必须第一时间回滚代码,保证主线代码任何时候都是干净没有问题的。


3)服务启动或者回滚时间过长。

某产品计价服务上线异常,回滚时单个服务回滚时间太长,导致未能短时间内快速止损。经排查,回滚过程中部署系统和服务都存在耗时过长的现象,由于服务回滚速度比较慢,产生了较大的线上服务故障。定期检查和优化服务的启动和回滚时间,保证出现故障时可以第一时间完成回滚操作。


4)配置文件缺少有效的校验机制。

配置文件由模型产出,数据配送系统实时配送到线上服务,模型产生的配置文件有问题,引发线上故障。因此,针对配置文件,尤其是策略模型产出的配置文件,需要建立严格的检查和校验机制。


5)小流量后的修改没有经过严格的测试和灰度验证。

某服务经过小流量灰度后,代码又有少量修改,再次上线时未灰度,导致线上故障。再小的变更,都要进行测试、灰度和双重检查(double check)。修改一行代码,也可能导致线上的稳定性故障。


(5)运维友好

为了实现运维友好的系统设计,系统需要将故障分析和定位时涉及的所有相关信息监控起来,构建完善的监控闭环,对系统层、服务层、接口层、业务层等维度进行监控收集和告警。


为了减少系统的稳定性隐患,微服务架构设计中尽量遵循简单的设计原则,从业务的真实需求出发,避免纯粹从技术角度出发的高大上技术方案,如果不是业务的核心功能,必要时可以进行一定的折中和裁剪,尽量保证系统的简单和简洁性。


另外,尽量使用一些验证过的技术,对于没有充分验证过的新技术的引入需要特别谨慎,如果一定要引入,需要控制好节奏,循序渐进。

 

以上内容摘自《Service Mesh微服务架构设计》一书,经出版方授权发布


作者简介

刘俊海,好未来高级架构师,曾在滴滴、百度等知名互联网公司任职,超过8年C/C++开发和架构设计经验;精通服务框架和业务高可用技术,多年亿级流量环境下高并发和高可用实战经验,精通微服务架构和微服务基础设施,近期关注Service Mesh。




免费赠书

福利时间:本次联合【机械工业出版社华章公司】为大家带来8本正版新书


如何参加:
识别下方二维码关注“架构艺术”公众号
 在后台回复 “11月17日” ,获取自动抽奖小程序。
 活动截止时间:11月20日:12:00
没中奖小伙伴也可以直接购买哦!



END

Kubernetes  CKA线下班

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存