云上高可用系统-韧性设计模式
一、走近韧性设计模式
(一)基本概念
韧性设计模式是一系列在软件工程中用于提高系统韧性的设计原则、策略、实践和模式。韧性(Resilience)在这里指的是系统对于各种故障、异常和压力的抵抗能力,以及在遭受这些挑战后能够快速自我恢复的能力。韧性设计模式旨在确保系统在面对不可避免的故障时,能够保持高可用性、可靠性和性能。

这些设计模式不仅关注系统的开发阶段,还包括系统的部署、运维和监控阶段,形成了一个全面的韧性设计理念。通过采用这些模式,可以降低系统遭受故障时的影响,并在出现问题时快速、自动地进行恢复。
一些常见的韧性设计模式整合如下:
| 模式 | 描述 | 应用场景 |
|---|---|---|
| 重试模式 (Retry Pattern) | 在面对临时性故障时,系统自动尝试重新执行失败的操作。 | 网络问题、服务瞬时不可用等。 |
| 断路器模式 (Circuit Breaker Pattern) | 在系统检测到连续的失败请求时,断开对失败服务的请求,避免连锁故障。 | 避免对故障服务的过度请求,提高整体系统稳定性。 |
| 超时模式 (Timeout Pattern) | 为每个操作设置最大执行时间,避免长时间等待导致资源浪费。 | 防止系统在某个操作上无限期阻塞。 |
| 限流模式 (Rate Limiting Pattern) | 控制系统在一定时间内的请求速率,防止系统过载。 | 防止大量请求导致系统资源耗尽。 |
| 负载均衡模式 (Load Balancer Pattern) | 将请求分发到多个相同的服务实例,提高系统的扩展性和稳定性。 | 均衡系统负载,避免单一节点故障影响整体服务。 |
| 舱壁模式 (Bulkhead Pattern) | 将系统的不同模块隔离开来,避免一个模块的故障影响其他模块。 | 确保故障在一个区域内隔离,不会波及整个系统。 |
| 异步消息模式 (Asynchronous Messaging Pattern) | 通过消息队列将系统的不同组件解耦,提高系统的弹性和可恢复性。 | 降低组件之间的依赖,减少同步调用风险。 |
| 灾备模式 (Disaster Recovery Pattern) | 设计系统的备份和恢复策略,以应对灾难性故障。 | 数据中心故障、自然灾害等情况下确保系统可用性。 |
| 自愈模式 (Self-Healing Pattern) | 系统能够自动检测并恢复从故障中恢复的能力。 | 监控系统状态,自动修复故障。 |
| 版本控制模式 (Feature Toggling / Feature Flags Pattern) | 通过动态切换系统的特性,使得可以在运行时开启或关闭功能。 | 灰度发布、紧急关闭某个功能等。 |
这些模式的综合应用能够帮助构建更具韧性的系统,提高系统的可用性和稳定性。在云上部署和运行的环境中,韧性设计尤为重要,因为这些环境更容易受到各种因素的影响。
(二)“拥抱故障”理念
对故障和事故的定义如下:
| 定义 | 例子 |
|---|---|
| 故障(Failure):系统不能执行预期功能的状态。 | 宕机、请求超时、内存溢出等。 |
| 事故(Accident):故障是系统最终用户可感知的,或者造成了业务损失的情况。 | 下单服务不可用,导致订单损失约10万单。 |
在故障与事故的定义中,系统不能执行预期功能的状态被定义为故障,而当故障对系统最终用户可感知,或者造成了业务损失时被定义为事故。
在大规模系统中,故障是常态。尤其在管理数千个实例的大规模系统中,宕机、系统出现Bug、请求失败、网络中断等都是经常发生的情况,而不是例外。因此,一个具备韧性的系统需要在部分故障的情况下仍能够正常运行,即使面对较大规模的故障,系统也能够提供大部分的服务。
“拥抱故障”的理念强调了开发者需要在系统的全生命周期中考虑系统如何应对故障,确保系统在故障发生时的状态是符合预期的。这并不意味着构建一个能够抵御任何故障的完美系统,而是要知道并接受系统能够在哪些情况下抵御故障,在哪些情况下会降级,以及在哪些情况下无法抵御。
韧性和成本在大多数情况下是矛盾的。在不那么关键的系统中,为了保证在罕见的自然灾害下的可用性而花费数倍的成本可能得不偿失。因此,理性的做法是在“保证高可靠所花费的成本”和“因停服而造成的潜在损失”之间找到一个合理的平衡点。
(三)避免重大事故关键方向
理解故障和事故的不可避免性后,确实需要通过一系列工作来尽量减小事故的发生概率和降低事故造成的损失。

主要的关键方向如下:
-
降低事故发生的概率: 通过健康检查、冗余、负载均衡等手段,预防已知故障的发生,提高系统的可用性。这是一种常见的做法,可以有效降低系统出现常见故障的概率。
-
减少故障时长: 在故障发生时,关键是尽快恢复系统的正常状态。快速检测故障、自动切换到备用系统、采用断路器模式等手段都有助于减少故障时长,从而降低损失。
-
减小故障影响范围: 在大规模系统中,故障可能只影响系统的一部分。通过设计系统的舱壁模式、服务隔离等,可以限制故障的影响范围,避免故障在整个系统中扩散。
以上三个方向共同作用,有助于降低事故的发生概率,缩短故障时长,减小故障造成的损失。另外,在大规模系统中,事故定级是一个常见的做法,通过事故定级,可以更有针对性地采取措施,提高系统的韧性。
二、保持简单的架构
KISS原则(Keep It Simple and Stupid,或者Keep It Simple, Stupid)是一项设计原则,强调在设计和开发中应保持简单性。这个原则的核心思想是,大多数系统如果保持简单而不是变得复杂,则效果最佳。KISS原则起源于美国海军,在20世纪60年代提出,并后来在计算机科学和软件工程领域广泛应用。
无论采用哪种表述,“保持简单”是KISS原则的核心含义。原则强调设计和实现应该简明直观,避免引入不必要的复杂性。这并不是要求完全排斥复杂性,而是要在确保必要功能的同时,尽量避免使系统变得难以理解、维护和扩展的复杂性。
(一)同质化部署
同质化部署是一种部署策略,它指的是在部署时将系统的所有组件集成在一起,然后部署到系统的每个实例上。这意味着系统的每个实例上运行的应用是完全一样的,所有组件被打包成一个整体。这种部署方式的集成方式一般包括一起编译打包成二进制程序或JAR包,也可以封装成包含所有组件的镜像。

同质化部署的好处在于简化了部署和运行时系统的复杂度。在部署时,不需要为每个组件准备不同的构建和部署脚本,也不必关注不同组件在启动过程中的依赖关系。在运行时,由于所有实例都是相同的,处理问题实例的替代变得更加容易。如果某个实例宕机或者出现容量问题,可以使用其他的实例来替代,而且这个热切换过程不需要拉起新的实例,速度很快,也更容易做到无感知切换。
(二)最少关键依赖原则
最少关键依赖原则是软件设计中的一项原则,强调在设计和实现系统时,应该尽量减少系统对外部组件、服务或库的依赖。核心思想是降低系统受到外部变化的影响,提高系统的稳定性和可维护性。
假设我们正在设计一个健身软件,用户可以通过该软件制定训练计划、记录健身数据等。健身软件中的用户数据直接依赖外部身体数据传感器和第三方社交媒体平台。软件在用户训练时,直接获取身体数据传感器的数据,并将健身记录分享到第三方社交媒体平台。
问题分析:
- 系统直接依赖外部身体数据传感器和第三方社交媒体平台,增加了软件对这两个外部组件的耦合性。
- 如果身体数据传感器或社交媒体平台发生变化,需要修改健身软件,可能导致软件其他部分的不稳定性。
应用最少关键依赖原则:
- 重新设计健身软件,引入中间层或者服务代理。
- 软件不再直接依赖外部身体数据传感器和第三方社交媒体平台,而是通过中间层或服务代理来与这两个服务通信。
- 中间层或服务代理负责与外部服务进行交互,并将结果传递给健身软件。
具体实现方案:
-
引入数据同步服务:通过引入数据同步服务,将身体数据传感器的数据同步到软件的数据存储中。健身软件直接从数据存储中获取用户的身体数据,降低了对传感器的直接依赖。
-
使用社交媒体 API:通过引入社交媒体 API,软件通过 API 与社交媒体平台通信,将用户的健身记录分享到平台。这样,软件不再直接依赖特定的社交媒体平台实现。
(三)简化部署
在很多系统中,启动新实例时的初始化配置脚本、安装动态链接库以及从外部服务获取初始化配置等操作会导致启动速度变慢,且容易出错。这种做法在容器化部署的环境下可以通过简化部署来优化。
具体实践中,可以将这些初始化操作从首次启动阶段迁移到更早期的构建阶段,使用 Dockerfiles 或 Docker Compose 在构建镜像的过程中完成初始化工作。这种方式可以显著提高启动速度,尤其是在扩容和故障恢复的场景下。
三、冗余、无状态和幂等
冗余、无状态和幂等这三个基础的韧性模式是在设计可靠系统时的重要原则,通常被视为基础或必要条件。
(一)冗余:普适基础
冗余是提升系统可用性的一种最简单且有效的方法。在高可用架构的设计中,采用冗余设计意味着引入多个相同或相似的系统组件实例,以降低单点故障的影响,提升系统的整体可用性。冗余的方式可以涵盖硬件层面、软件层面、数据层面等。
(二)无状态服务
无状态服务是指服务在处理请求时不依赖于本地存储数据,而是通过外部存储或其他服务获取所需的信息。这种设计模式对单次请求的处理不依赖于其他请求,每个请求都包含处理所需的全部信息,或者可以从外部获取。
-
不依赖本地存储: 无状态服务不在本地存储数据,而是从外部获取所需的信息。这使得服务可以更容易水平扩展,因为每个服务实例都是相同的,而不需要考虑本地数据的同步和共享问题。
-
独立请求处理: 单次请求的处理不依赖于其他请求的状态,每个请求都是独立的。这样的设计适用于绝大部分在线业务服务,特别是那些数据保存在远程数据库中且请求之间没有明显关联的场景。
-
存储计算分离: 无状态服务的状态数据被下沉到外部存储系统,实现了存储和计算的分离。这使得集群管理和调度更加简单,支持更灵活的负载均衡和水平扩展。
考虑一个健身软件的案例,该软件需要记录用户的运动数据。在传统有状态的设计中,每个服务实例可能会维护用户的运动数据状态,而在无状态设计中,用户的运动数据被存储在外部的分布式数据库中,服务实例通过API从数据库获取用户的运动数据。这样设计可以实现水平扩展,任意服务实例都可以处理任意用户的请求,而不依赖于本地存储数据。同时,用户的运动数据可以被多个服务实例同时访问,需要注意并发控制的问题。
(三)幂等性
在计算机科学中,幂等性是指一个操作的多次执行和一次执行具有相同的效果。换句话说,无论操作执行多少次,系统的状态都与执行一次时的状态相同。这个概念对于分布式系统和网络通信中的操作非常重要,因为在这些场景下,由于各种原因可能会导致请求的重复执行。
为什么需要幂等性:
在负载均衡和分布式系统中,由于网络不稳定性、超时、重试等原因,同一个请求可能被发送到不同的服务实例上。如果某个操作不是幂等的,那么在请求失败后的重试可能会导致系统状态的变化,进而引起不一致的问题。幂等性的设计可以确保即使请求被重复执行,对系统状态的影响也是相同的,从而防止因为重试而引发的副作用。
幂等性的实现方法:
-
业务逻辑设计: 最好的方式是从业务逻辑上入手,设计具备天然幂等性的操作。这意味着无论执行多少次,结果都是相同的。例如,创建订单服务可以设计成只有在订单号不存在时才创建订单,如果订单号已存在,则返回已存在的订单,这样无论多次执行都只会有一个订单记录。
-
唯一标识和检查: 使用唯一标识来防止重复操作。每个请求可以携带一个唯一标识,服务在处理请求时先检查该标识是否已经处理过,如果处理过则直接返回结果,避免重复执行。
-
幂等键: 引入幂等键(Idempotence Key),客户端在每次请求时都携带一个唯一的键,服务端通过这个键来判断请求是否已经处理过。这样,即使同一个请求被发送多次,服务端通过幂等键就能够判断出重复请求并进行幂等性处理。
通过保证操作的幂等性,系统可以更好地适应分布式环境和不稳定的网络条件,确保在各种情况下都能够维持一致的状态。
四、松耦合设计
在软件设计中,耦合度是指两个模块之间相互依赖的程度。松耦合(Low Coupling)是一种设计原则,旨在降低系统内部组件之间的依赖关系,从而提高系统的灵活性和可维护性。低耦合的系统中,一个模块的变化不太可能影响到其他模块,模块之间的关联性较弱。
五、Event Sourcing:全异步架构模式
六、最终一致
相关文章:
云上高可用系统-韧性设计模式
一、走近韧性设计模式 (一)基本概念 韧性设计模式是一系列在软件工程中用于提高系统韧性的设计原则、策略、实践和模式。韧性(Resilience)在这里指的是系统对于各种故障、异常和压力的抵抗能力,以及在遭受这些挑战后…...
【保姆级教程】Windows11下go-zero的etcd安装与初步使用
【Go-Zero】Windows11下etcd的安装与初步使用 大家好 我是寸铁👊 总结了一篇Windows11下etcd的安装与初步使用的文章✨ 喜欢的小伙伴可以点点关注 💝 前言: 在使用etcd 前,我们需要了解一下etcd 是什么,为什么使用etcd…...
golang通过go-git下载gitlab源码
1 申请令牌 方法1:具体项目下申请: 方法2:全局申请 2 获取token 3 下载代码 package mainimport ("fmt""os""github.com/go-git/go-git/v5" )func main() {_, err : git.PlainClone("/tmp/foo",…...
探索Pyecharts之美-绘制多彩旭日图的艺术与技巧【第37篇—python:旭日图】
文章目录 引言准备工作绘制基本旭日图调整颜色和样式添加交互功能定制标签和标签格式嵌套层级数据高级样式与自定义进阶主题:动态旭日图数据源扩展:外部JSON文件总结 引言 数据可视化在现代编程中扮演着重要的角色,而Pyecharts是Python中一个…...
c++ QT 信号的个人理解 信号就是独立文件调用的一种“协议”
一. 简介 就我个人来理解,信号槽机制与Windows下消息机制类似,消息机制是基于回调函数,Qt中用信号与槽来代替函数指针,使程序更安全简洁。 信号和槽机制是 Qt 的核心机制,可以让编程人员将互不相关的对象绑定在一起&a…...
C#语法(关键字)
C#关键字 关键字是C#编译器预定义的保留字。这些关键字不能作为标识符,但是,如果您想要用它们做标识符,在这个前面加个字符做前缀。 保留关键字abstractasbaseboolbreakbytecasecatchcharcheckedclassconstcontinuedecimaldefaultdelegated…...
让B端管理软件既美观又实用的解决方案来了
hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 让B端管理软件既美观又实用的解决方案来了 在当今数字化时代,B端管理软件已…...
npm run dev,vite 配置 ip 访问
启动项目通过本地 ip 的方式访问 方式一.通过修改 package.json "scripts": {"dev": "vite --host 0.0.0.0",}, 方式二.通过修改 vite.config.ts export default defineConfig({plugins: [vue(), vueJsx()],server: { // 配置 host 与 port 方…...
实验3:数据显示输出
1、实验目的: 掌握将内存单元存储的数据显示输出到显示器的方法。 2、实验内容: 将内存单元存储的字节数据(例如 56H)的16进制数的低位输出到显示器并显示。 3、实验要求: (1)运行程序后&a…...
查看 Avro 格式的 Kafka 消息(启用了 Confluent Schema Registry )
使用 Avro 格式传递 Kafka 消息要比 Json 更加高效,因为它是二进制格式,在启用了 Confluent Schema Registry 的情况下,会进一步地提升传输效率,因为 Avro 中的 Schema 信息将不再出现在消息中,消息体积会进一步压缩,同时,还可以利用到 Schema Registry 的其他好处,例如…...
QT+VS实现Kmeans聚类算法
1、Kmeans的定义 聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使…...
openssl3.2 - 测试程序的学习 - test\acvp_test.c
文章目录 openssl3.2 - 测试程序的学习 - test\acvp_test.c概述笔记要单步学习的测试函数备注END openssl3.2 - 测试程序的学习 - test\acvp_test.c 概述 openssl3.2 - 测试程序的学习 将test*.c 收集起来后, 就不准备看makefile和make test的日志参考了. 按照收集的.c, 按照…...
Qt Quick 项目(第二集Qt Quick Application创建)
上集回顾 Qt Quick 项目(第一集Qt Quick UI 项目项目创建) 如果将程序的用户界面称为前端,将程序中的数据存储和业务逻辑称为后端,那么传统Qt应用程序的前端和后端都是使用C++来完成的。对于现代软件开发而言,这里有一个存在已久的冲突:前端的演化速度要远快于后端。当用…...
深度强化学习(王树森)笔记03
深度强化学习(DRL) 本文是学习笔记,如有侵权,请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接:https://github.com/wangshusen/DRL 源代码链接:https://github.c…...
Cesium材质特效
文章目录 0.引言1.视频材质2.分辨率尺度3.云4.雾5.动态水面6.雷达扫描7.流动线8.电子围栏9.粒子烟花10.粒子火焰11.粒子天气 0.引言 现有的gis开发方向较流行的是webgis开发,其中Cesium是一款开源的WebGIS库,主要用于实时地球和空间数据的可视化和分析。…...
华为产业链之车载激光雷达
一、智能汽车 NOA 加快普及,L3 上路利好智能感知硬件 1、感知层是 ADAS 最重要的一环 先进驾驶辅助系统 (ADAS, Advanced driver-assistance system)分“感知层、决策层、执行层”三个层级,其中感知层是最重要的一环…...
java的Object类的hasCode()和ToString()
(1)hasCode解释 hashCode()是Object类中定义的方法,用于返回对象的哈希码值。哈希码值是一个整数,用于在哈希表等数据结构中快速定位对象。 在Java中,哈希码值的计算是基于对象的内存地址的。默认情况下,ha…...
php数组算法(1)判断一维数组和多元数组中的元素是否相等并输出键值key
在php中,如何判断[1,0,1]和[ [0, 0, 0],//体质正常 [1, 0, 0],//气虚体质 [0, 1, 0],//血瘀体质 [0, 0, 1],//阴虚体质 [1, 1, 0],//气虚兼血瘀体质 [1, 0, 1],//气虚兼阴虚体质 [0, 1, 1],//血瘀兼阴虚体质 [1, 1, 1],//气虚兼血瘀兼阴虚体质 ];中的第n项相等&…...
已解决Error:AttributeError: module ‘numpy‘ has no attribute ‘float‘.
成功解决Error:AttributeError: module ‘numpy‘ has no attribute ‘float‘. 🌵文章目录🌵 🌳引言🌳🌳报错分析🌳🌳解决方案1:降低NumPy版本🌳ἳ…...
WordPress块编辑器(Gutenberg古腾堡)中如何添加脚注?
WordPress默认自带的块编辑器(Gutenberg古腾堡编辑器)本身就自带添加脚注功能,不过经典编辑器不行。如果想要在WordPress中添加更加专业的脚注,建议使用Modern Footnotes插件,具体介绍及使用请参考『WordPress站点如…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
