系统高可用是一个宏大的命题,从设计思想、架构原则到工程能力、服务管理等等方方面面,每个视角单拆出来都不是一篇文章可以解决的。本文将从大局上全面系统地梳理高可用系统架构,起到一个提纲挈领的作用。
关注腾讯云开发者,一手技术干货提前解锁
1 月 7 日晚 7:30,腾讯云开发者视频号「鹅厂程序员面对面」直播间,为你揭晓过去一年狂飙、烧钱的大模型背后,是如何为企业降本增效,应用落地的,预约观看准时抢鹅厂周边好礼!
海恩法则
· 事故的发生是量的积累的结果。 · 再好的技术、再完美的规章 , 在实际操作层面也无法取代人自身的素质和责任心 。
薛定谔的猫
“薛定谔的猫”告诉我们,事物发展不是确定的,而是量子态的叠加。
墨菲定律
· 任何事情都没有表面看起来那么简单 。 · 所有事情的发展都会比你预计的时间长 。 · 会出错的事总会出错。 · 如果你担心某种情况发生,那么它更有可能发生 。
蝴蝶效应
世界会因一些微小因素的变动,而发生很大的变化。
熵增原理
“热力学第二定律”(熵增原理)告诉我们,世界总是在变得更加混乱无序。
警示我们,在互联网公司里,对生产环境发生的任何怪异现象和问题都不要轻易忽视,对于其背后的原因一定要彻查。同样,海恩法则也强调任何严重事故的背后都是多次小问题的积累,积累到一定的量级后会导致质变,严重的问题就会浮出水面。那么,我们需要对线上服务产生的任何征兆,哪怕是一个小问题,也要刨根问底:这就需要我们有技术攻关的能力,对任何现象都要秉着以下原则:为什么发生?发生了怎么应对?怎么恢复?怎么避免?对问题要彻查,不能因为问题的现象不明显而忽略 。
个人学习实践和总结笔记:
架构设计的愿景就是高可用、高性能、高扩展、高效率。为了实现架构设计四高愿景,需要实现自动化系统目标:
要实现这些,在中小型公司,架构师可以 hold 住,而在大企业/大厂里面,虾兵蟹将是无法搞定的,至少是 vp 级别来推动。
整个自动化体系需要多平台、系统、工具来解决各类场景的自动化执行,各个平台之间要相互联动形成体系化,而不是相互脱离,各自发展。目前还没看到一站式平台可以串接需求、设计、开发、测试、发布、运维等,而高可用系统架构设计要从产品、开发、运维、硬件等全方位去统筹综合考虑形成一体化。
本文着眼整体,全局规划、分层设计,提供一个稳定性建设总体规划的参考。如果缺什么补什么,没有总体规划的建设,后面做出的系统往往是相互割裂,定位不清、无法持续集成,最后就是沦为一堆零散工具而无法形成体系(个人拙见,仅供参考)。紫色部分是我们最近半年主要关注和建设的部分:
1.1 业务可用性指标
所谓业务可用性(availability)也即系统正常运行时间的百分比,架构组/SRE 最主要的 KPI (Key Performance Indicators 关键业绩指标)。对于我们提供的服务(web/api)来说,现在业界更倾向用 N 个 9 来量化可用性,最常说的就是类似“4个9(也就是99.99%)”的可用性。
故障时间=故障修复时间点-故障发现(报告)时间点
服务年度可用时间%=(1-故障时间/年度时间)× 100%。
1.2 故障的度量与考核
对管理者/部门而言:可用性是产品的整体考核指标。对于研发工程师而言:使用故障分来考核:
类别 | 描述 | 权重 |
---|---|---|
高危S级事故故障 | 一旦出现故障,可能会导致服务整体不可用 | 100 |
严重A级故障 | 客户明显感知服务异常:错误的回答 | 20 |
中级B级故障 | 客户能够感知服务异常:响应比较慢 | 5 |
一般C级故障 | 服务出现短时间内抖动 | 1 |
考核指标可以使用故障分度量:故障分=故障时间分钟* 故障级别权重。
1.3 服务分级
如果是一个分布式架构设计,系统由很多微服务组成,所有的服务可用性不可能都是统一的标准。
为了提高我们服务可用性,我们需要对服务进行分类管理并明确每个服务级别的可用性要求。
类别 | 服务 | 可用性要求 | 描述 |
---|---|---|---|
一级核心服务 | 核心产品或者服务 | 99.99%(全年53分钟不可用) | 系统引擎部分:一旦出现故障,整个系统瘫痪 |
二级重要服务 | 重要的产品功能 | 99.95%(全年260分钟不可用) | 类比汽车轮子:该服务出现问题,该重要功能不可用。 |
三级一般服务 | 一般功能 | 99.9%(全年8.8小时不可用) | 类比汽车倒车影像:该部分出现问题,稍微影响用户体验 |
四级工具服务 | 工具类是服务 | 0.99 | 非业务功能:比如爬虫、管理后台、运维工具 |
高可用系统的架构设计,要从产品需求、代码开发、运维部署、故障管理等系统全生命周期进行全方位去考量和设计,核心思想就是:
高可用系统的架构设计思想包括但不限于:
2.1 系统设计
2.2 故障预防
2.3 故障发现
2.4 故障恢复
2.5 故障总结
系统都是研发人员设计和编码写出来的,因此首先要对研发层面有一个代码架构规范,例如编码规范、如果代码架构设计不足,就会造成影响全局的架构设计。例如我们之前一个系统,很多功能耦合在一个大单体应用里面,某个功能接口出现问题,就导致整个系统崩溃。
通过规范研发流程可以让我们更好地去研发和维护一个高可用的系统:
3.1 制定研发规范和原则
3.2 设计阶段
原则上新功能或者模块要有设计文档,规范好相关方案设计文档的模板和提纲,让团队内部保持统一,例如
设计文档能够指导整个开发流程,包括编码、接口文档和测试用例,所有出现的问题都可以追溯到设计文档中。
设计文档是否需要评审:新项目、重构项目、大的系统优化或者升级一定要评审。
3.3 编码阶段
遵循代码规范进行编码。
1、API 安全建议: 2、API 数据传输采用随机、不可预测、复杂的 Token 机制; 3、对 API 调用的数据、功能等实施严格访问控制,并严格设置白名单清单; 4、严格定义 API 输入数据类型,并校验、过滤所有传入数据; 5、对 API 的请求采用公开密码算法进行数字签名和校验; 6、加密 API 请求流量,可采用非对称加密算法逐个加密敏感信息字段,加密结果需做 Base64 编码等; 7、设置 API 请求频率限制策略。
3.4 线上发布阶段
系统灰度发布:确保故障不会造成大面积影响。
接口监控完善,确保及时发现发布过程可能存在的问题。
总结一下代码层面可能引发的故障/问题:
4.1 容量评估
明确系统的业务场景,如果是管理工具平台相关,可能不太关注 QPS 相关指标。如果是应对业务系统,一般都要考虑 QPS 均值和峰值。
如果是新系统,可以先搜集产品和运营同学对业务的大体预估,可以大体估算出 QPS 相关指标。如果是老系统,那么就可以根据历史数据来评估。评估的时候,要从一个整体角度来看全局的量级,然后再细化到每个子业务模块要承载的量级。
4.2 容量规划
是指系统在设计的时候,就要能够初步规划好系统大致能够维持的量级,比如是十万级还是百万级别的请求量,或者更多。不同量级对应的系统架构设计完全不一样。尤其到了千万、亿级别的量级的时候,架构设计会有更多的考量。
这里值得注意的是,不需要在一开始就设计出远超当前业务真实流量的系统,要根据业务实际情况来设计。同时,容量规划还涉及到:系统上下游的各个模块、依赖的存储、依赖的三方服务分别需要多少资源,需要有一个相对可量化的数据。容量规划阶段更多是要依靠自身和团队的经验,比如要了解系统的 log 的性能、redis 的性能、rpc 接口的性能、服务化框架的性能等等,然后根据各种组件的性能来综合评估已经设计的系统的整体性能情况。
4.3 性能压测
容量评估和容量规划之后,还需要做就是性能压测。最好是能够做到全链路压测。
性能压测的目的:
我们中心的 SRE 压测任务:建立常态化压测机制,使核心链路在目标 QPS 下保持稳定。
搭建压测平台,定期根据实际现网请求生成源模块到目标流量的放大系数,测出不同业务资源占用率峰值,辅助容量评估。
5.1 架构分层
为了降低应用服务管理的复杂性,我们把整个系统划分成若干个层次,每一层专注解决某个领域的问题,并向上提供服务。
典型架构分层设计如下:按照功能处理顺序划分应用,这是面向业务深度的划分。同时禁止逆向调用。
每个公司的架构分层可能不一样,但是目的都是为了统一架构术语,方便团队内部沟通。
我们先列出目前我们系统有哪些环节,每个环节是否薄弱. 客户端访问服务器端,经过很多环节,任何环节出问题,都不能访问:
接入层:
应用层/服务层:
数据层:
整体架构层:
5.2 接入高层可用设计
在接入层,这里主要是架构运维的高可用要求的事项:
接入层架构参考:
当系统对外的接口繁多,同时不同的项目不同的接口,没有一个统一管理的系统,也不方便监控和跟踪 api 的健康状况。需要 api 网关,方便 api 日常管理,包括控版本管理,升级,回滚。 更重要的是 api 网关起到限流防刷(CC 攻击)作用,保护后端服务。
5.3 应用层高可用设计
5.3.1 应用层设计主要原则
5.3.2 应用服务可能存在异常的情况
5.3.3 提高服务可用性机制
解决的思路:服务分级治理、服务隔离、自我保护、失效转移或恢复、服务降级。
依据依赖服务的重要性或依赖程度(强、弱),实行相应服务降级手段:
5.3.4 具体容错机制说明
1、failover:失效转移:失败自动切换”,是一种备份操作模式。
Fail-Over 失效转移是一种备份操作模式,当主要组件异常时,其功能转移到备份组件。其要点在于有主有备,主故障时系统能够自动地切换到备用服务上, 保证服务继续运行。比如内部调用 nginx 代理,不能是单点提供服务,需要有主备模式,通过 keep-alive 机制自动切换到备用服务上。核心和重要服务都需要按 N+1 原则部署。通常用于读操作;
2、failfast:快速失败:快速识别,就是只发起一次调用,失败后立即报错。
fail-fast 是“快速失败”,尽可能的发现系统中的错误,使系统能够按照事先设定好的错误的流程执行,对应的方式是“fault-tolerant(错误容忍)”。以 JAVA 集合(Collection)的快速失败为例,当多个线程对同一个集合的内容进行操作时,就可能会产生 fail-fast 事件。例如:当某一个线程 A 通过 iterator 去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程 A 访问集合时,就会抛出 ConcurrentModificationException 异常(发现错误执行设定好的错误的流程),产生 fail-fast 事件。通常用于非幂等性的写操作;
3、failback:故障自动恢复:故障转移(Fail-Over)之后,服务能够自动恢复。
Fail-over 之后的自动恢复,在簇网络系统(有两台或多台服务器互联的网络)中,由于要某台服务器进行维修,需要网络资源和服务暂时重定向到备用系统。在此之后将网络资源和服务器恢复为由原始主机提供的过程,称为自动恢复。
4、failsafe:失效安全:出现异常时,直接忽略。即使发生了故障,也不会对系统/服务造成伤害,或尽量减少伤害。
Fail-Safe 的含义为“失效安全”,即使在故障的情况下也不会造成伤害或者尽量减少伤害。维基百科上一个形象的例子是红绿灯的“冲突监测模块”当监测到错误或者冲突的信号时会将十字路口的红绿灯变为闪烁错误模式,而不是全部显示为绿灯。通常用于写入审计日志等操作;
5、接口幂等设计
应用调用服务失败后,会将请求重新转发到其他服务上,这个时候要进行幂等性的判断,有可能服务调用失败是网络问题导致的,实际上业务处理成功了。
5.4 服务分级治理
服务层设计最主要原则:服务分级管理。
线上有很多服务,每个服务的可用性要求不一样,我们需要先这些服务做分级。
定义:
可用性:99.99%,极高可用性,全年53分钟不可用。
条件:
服务设计满足以下原则:
服务设计满足以下原则:
定义:
可用性99.9%(全年8.8小时不可用)。
条件:
服务设计满足以下原则:
服务设计满足以下原则:
数据是最宝贵的资产。
数据存储高可用主要手段是冗余备份和失效转移机制。数据备份是保证数据有多副本,任意副本的失效都不会导致数据的永久丢失。从而实现数据完全的持久化。而失效转移机制是保证当一个数据副本不可访问时,可以快速切换访问数据的其他副本。保证数据可用。
6.1 数据架构设计原则
6.2 数据一致性设计
分布式的 CAP 理论
在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),最多只能同时三个特性中的两个,三者不可兼得。
在非金融的互联网分布式应用里面,主机多,数据大,部署分散。所以节点故障,网络故障是常态。一般是为了保证服务可用性而舍弃一致性 C。即保证 AP。
分布式的 BASE 理论
BASE 理论,它是在 CAP 理论的基础之上的延伸。包括基本可用(Basically Available)、柔性状态(Soft State)、最终一致性(Eventual Consistency)。
柔性事务(遵循 BASE 理论)放弃了隔离性,减小了事务中锁的粒度,使得应用能够更好的利用数据库的并发性能,实现吞吐量的线性扩展。异步执行方式可以更好的适应分布式环境,在网络抖动、节点故障的情况下能够尽量保障服务的可用性 (Availability)。因此在高可用、高性能的应用场景,柔性事务是最佳的选择。
柔性事务对 ACID 的支持:
在业内,关于柔性事务,最主要的有以下四种类型:
6.3 完善的数据备份和恢复机制
完善的数据备份和恢复机制能力,在发生数据丢失的时候,可以使用备份快速恢复。
运营层面主要故障总结:
具体措施:
7.1 故障预防
1、灰度发布
服务发布上线的时候,要有一个灰度的过程。先灰度 1-2 个服务实例,然后逐步放量观察。
A/B 测试就是一种灰度发布方式,指为产品已发布 A 版本,在发布 B 版本时,在同一时间维度,让一部分用户继续用 A 版本,一部分用户开始用 B 版本,如果用户对 B 版本没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到 B 版本上面来。灰度发布可以保证整体系统的稳定,在初始灰度发布时就可以发现及调整问题,以保证其影响度。
通过灰度发布降低发布影响面和提升用户体验,就算出问题,也只会影响部分用户,从而可以提前发现新版本中的 bug,然后在下一次发布前提前修复,避免影响更多用户;
灰度发布的主要分类:
2、容灾备份部署
3、故障演练
故障演练是应用高可用能力测评的核心, 通过例行化故障演练、找出系统风险点、优化业务系统、产出可行有效的故障处理预案。
7.2 完善的服务故障发现
1、监控告警机制
在高可用服务设计章节提到,核心服务可以监控:服务流量预警、端口存活、进程占用的资源、服务接口功能逻辑是否正常,应用 FGC 等情况,需要一个完善监控告警机制,并在告警后,通过一定的策略进行处理,以致服务可以快速恢复。例如,监控 FGC,如果在一分钟内存出现10次 FGC,自动重启服务。
2、全链路观测平台
构建服务全链路观测能力,并有效降低 MTTR 各项指标。
掌握数据分析方法,构建数据服务指标,有效评估业务整体服务质量,沉淀一般通用指标方案,能成功复用到其他项目。
形成闭环管理:有迹可循,来源可溯、去向可查等完整的生命周期管理。
海恩法则提到:再好的技术、再完美的规章 , 在实际操作层面也无法取代人自身的素质和责任心 。
因此要做到高可用的架构设计,职责也要清晰明确,要不然出现问题,相互推诿,问题解决进度很慢,会直接影响业务服务可用性。
9.1 职责清晰明确
1、架构师职责:
2、运维/SRE 职责:
3、研发职责:
9.2 作为架构师/SRE 具备能力
人的能力素质是解决问题的根本
作为架构师,需要能力:
"具备对操作系统、容器技术、网络,大型分布式微服务架构深入理解和实践经验。能理解业务的可靠性需求,转化为技术指标,运用云原生、混沌工程、全链路压测等技术手段,建立业务的可观测,提升业务的 MTBF(平均故障间隔时间 Mean Time Between Failure)、降低 MTTR(平均修复时间 Mean time to repair),通过系统与数据能力不断帮助业务取得成功"。
自动化体系建设能力:
能对日常发布、变更工作、容量规划进行主动的自动化体系建设,并能沉淀指导方法,有效指导多业务建设。
掌握故障预防和发现技巧:
掌握通过构建和实施全链路压测和混沌工程等故障预防手段提升 MTBF。
掌握通过构建和实施系统异常检测和监控告警机制等故障发现手段降低 MTTI。
构建观测平台能力:
具备构建服务全链路观测能力,并有效降低 MTTR 各项指标。
精通数据分析方法,构建数据服务指标,有效评估业务整体服务质量,沉淀一般通用指标方案,能成功复用到其他项目。
技术深度能力:性能分析,基础扎实,深入底层:
能多维度的分析业务的性能瓶颈,通过架构调整,内核、软件参数等手段调优,沉淀一般通用性调优方案。
技术广度能力:
理解云原生相关技术与生态,能指导业务架构、技术架构调整落地为云原生应用。
-End-
原创作者|黄规速