04 _ 系统设计目标(二):系统怎样做到高可用?

news2024/11/30 1:32:10

这里将探讨高并发系统设计的第二个目标——高可用性。

高可用性(High Availability,HA)是你在系统设计时经常会听到的一个名词,它指的是系统具备较高的无故障运行的能力。

我们在很多开源组件的文档中看到的HA方案就是提升组件可用性,让系统免于宕机无法服务的方案。比如,你知道Hadoop 1.0中的NameNode是单点的,一旦发生故障则整个集群就会不可用;而在Hadoop2中提出的NameNode HA方案就是同时启动两个NameNode,一个处于Active状态,另一个处于Standby状态,两者共享存储,一旦Active NameNode发生故障,则可以将Standby NameNode切换成Active状态继续提供服务,这样就增强了Hadoop的持续无故障运行的能力,也就是提升了它的可用性。

通常来讲,一个高并发大流量的系统,系统出现故障比系统性能低更损伤用户的使用体验。想象一下,一个日活用户过百万的系统,一分钟的故障可能会影响到上千的用户。而且随着系统日活的增加,一分钟的故障时间影响到的用户数也随之增加,系统对于可用性的要求也会更高。所以今天,我就带你了解一下在高并发下,我们如何来保证系统的高可用性,以便给你的系统设计提供一些思路。

可用性的度量

可用性是一个抽象的概念,你需要知道要如何来度量它,与之相关的概念是:MTBF和MTTR。

MTBF(Mean Time Between Failure)是平均故障间隔的意思,代表两次故障的间隔时间,也就是系统正常运转的平均时间。这个时间越长,系统稳定性越高。

MTTR(Mean Time To Repair)表示故障的平均恢复时间,也可以理解为平均故障时间。这个值越小,故障对于用户的影响越小。

可用性与MTBF和MTTR的值息息相关,我们可以用下面的公式表示它们之间的关系:

Availability = MTBF / (MTBF + MTTR)

这个公式计算出的结果是一个比例,而这个比例代表着系统的可用性。一般来说,我们会使用几个九来描述系统的可用性。

其实通过这张图你可以发现,一个九和两个九的可用性是很容易达到的,只要没有蓝翔技校的铲车搞破坏,基本上可以通过人肉运维的方式实现。

三个九之后,系统的年故障时间从3天锐减到8小时。到了四个九之后,年故障时间缩减到1小时之内。在这个级别的可用性下,你可能需要建立完善的运维值班体系、故障处理流程和业务变更流程。你可能还需要在系统设计上有更多的考虑。比如,在开发中你要考虑,如果发生故障,是否不用人工介入就能自动恢复。当然了,在工具建设方面,你也需要多加完善,以便快速排查故障原因,让系统快速恢复。

到达五个九之后,故障就不能靠人力恢复了。想象一下,从故障发生到你接收报警,再到你打开电脑登录服务器处理问题,时间可能早就过了十分钟了。所以这个级别的可用性考察的是系统的容灾和自动恢复的能力,让机器来处理故障,才会让可用性指标提升一个档次。

一般来说,我们的核心业务系统的可用性,需要达到四个九,非核心系统的可用性最多容忍到三个九。在实际工作中,你可能听到过类似的说法,只是不同级别,不同业务场景的系统对于可用性要求是不一样的。

目前,你已经对可用性的评估指标有了一定程度的了解了,接下来,我们来看一看高可用的系统设计需要考虑哪些因素。

高可用系统设计的思路

一个成熟系统的可用性需要从系统设计和系统运维两方面来做保障,两者共同作用,缺一不可。那么如何从这两方面入手,解决系统高可用的问题呢?

1.系统设计

“Design for failure”是我们做高可用系统设计时秉持的第一原则。在承担百万QPS的高并发系统中,集群中机器的数量成百上千台,单机的故障是常态,几乎每一天都有发生故障的可能。

未雨绸缪才能决胜千里。我们在做系统设计的时候,要把发生故障作为一个重要的考虑点,预先考虑如何自动化地发现故障,发生故障之后要如何解决。当然了,除了要有未雨绸缪的思维之外,我们还需要掌握一些具体的优化方法,比如failover(故障转移)、超时控制以及降级和限流。

一般来说,发生failover的节点可能有两种情况:

1.是在完全对等的节点之间做failover。
2.是在不对等的节点之间,即系统中存在主节点也存在备节点。

在对等节点之间做failover相对来说简单些。在这类系统中所有节点都承担读写流量,并且节点中不保存状态,每个节点都可以作为另一个节点的镜像。在这种情况下,如果访问某一个节点失败,那么简单地随机访问另一个节点就好了。

举个例子,Nginx可以配置当某一个Tomcat出现大于500的请求的时候,重试请求另一个Tomcat节点,就像下面这样:

针对不对等节点的failover机制会复杂很多。比方说我们有一个主节点,有多台备用节点,这些备用节点可以是热备(同样在线提供服务的备用节点),也可以是冷备(只作为备份使用),那么我们就需要在代码中控制如何检测主备机器是否故障,以及如何做主备切换。

使用最广泛的故障检测机制是“心跳”。你可以在客户端上定期地向主节点发送心跳包,也可以从备份节点上定期发送心跳包。当一段时间内未收到心跳包,就可以认为主节点已经发生故障,可以触发选主的操作。

选主的结果需要在多个备份节点上达成一致,所以会使用某一种分布式一致性算法,比方说Paxos,Raft。

除了故障转移以外,对于系统间调用超时的控制也是高可用系统设计的一个重要考虑方面。

复杂的高并发系统通常会有很多的系统模块组成,同时也会依赖很多的组件和服务,比如说缓存组件,队列服务等等。它们之间的调用最怕的就是延迟而非失败,因为失败通常是瞬时的,可以通过重试的方式解决。而一旦调用某一个模块或者服务发生比较大的延迟,调用方就会阻塞在这次调用上,它已经占用的资源得不到释放。当存在大量这种阻塞请求时,调用方就会因为用尽资源而挂掉。

在系统开发的初期,超时控制通常不被重视,或者是没有方式来确定正确的超时时间。

我之前经历过一个项目,模块之间通过RPC框架来调用,超时时间是默认的30秒。平时系统运行得非常稳定,可是一旦遇到比较大的流量,RPC服务端出现一定数量慢请求的时候,RPC客户端线程就会大量阻塞在这些慢请求上长达30秒,造成RPC客户端用尽调用线程而挂掉。后面我们在故障复盘的时候发现这个问题后,调整了RPC,数据库,缓存以及调用第三方服务的超时时间,这样在出现慢请求的时候可以触发超时,就不会造成整体系统雪崩。

既然要做超时控制,那么我们怎么来确定超时时间呢?这是一个比较困难的问题。

超时时间短了,会造成大量的超时错误,对用户体验产生影响;超时时间长了,又起不到作用。我建议你通过收集系统之间的调用日志,统计比如说99%的响应时间是怎样的,然后依据这个时间来指定超时时间。如果没有调用的日志,那么你只能按照经验值来指定超时时间。不过,无论你使用哪种方式,超时时间都不是一成不变的,需要在后面的系统维护过程中不断地修改。

超时控制实际上就是不让请求一直保持,而是在经过一定时间之后让请求失败,释放资源给接下来的请求使用。这对于用户来说是有损的,但是却是必要的,因为它牺牲了少量的请求却保证了整体系统的可用性。而我们还有另外两种有损的方案能保证系统的高可用,它们就是降级和限流。

降级是为了保证核心服务的稳定而牺牲非核心服务的做法。比方说我们发一条微博会先经过反垃圾服务检测,检测内容是否是广告,通过后才会完成诸如写数据库等逻辑。

反垃圾的检测是一个相对比较重的操作,因为涉及到非常多的策略匹配,在日常流量下虽然会比较耗时却还能正常响应。但是当并发较高的情况下,它就有可能成为瓶颈,而且它也不是发布微博的主体流程,所以我们可以暂时关闭反垃圾服务检测,这样就可以保证主体的流程更加稳定。

限流完全是另外一种思路,它通过对并发的请求进行限速来保护系统。

比如对于Web应用,我限制单机只能处理每秒1000次的请求,超过的部分直接返回错误给客户端。虽然这种做法损害了用户的使用体验,但是它是在极端并发下的无奈之举,是短暂的行为,因此是可以接受的。

实际上,无论是降级还是限流,在细节上还有很多可供探讨的地方,我会在后面的课程中,随着系统的不断演进深入地剖析,在基础篇里就不多说了。

2.系统运维

在系统设计阶段为了保证系统的可用性可以采取上面的几种方法,那在系统运维的层面又能做哪些事情呢?其实,我们可以从灰度发布、故障演练两个方面来考虑如何提升系统的可用性。

你应该知道,在业务平稳运行过程中,系统是很少发生故障的,90%的故障是发生在上线变更阶段的。比方说,你上了一个新的功能,由于设计方案的问题,数据库的慢请求数翻了一倍,导致系统请求被拖慢而产生故障。

如果没有变更,数据库怎么会无缘无故地产生那么多的慢请求呢?因此,为了提升系统的可用性,重视变更管理尤为重要。而除了提供必要回滚方案,以便在出现问题时快速回滚恢复之外,另一个主要的手段就是灰度发布。

灰度发布指的是系统的变更不是一次性地推到线上的,而是按照一定比例逐步推进的。一般情况下,灰度发布是以机器维度进行的。比方说,我们先在10%的机器上进行变更,同时观察Dashboard上的系统性能指标以及错误日志。如果运行了一段时间之后系统指标比较平稳并且没有出现大量的错误日志,那么再推动全量变更。

灰度发布给了开发和运维同学绝佳的机会,让他们能在线上流量上观察变更带来的影响,是保证系统高可用的重要关卡。

灰度发布是在系统正常运行条件下,保证系统高可用的运维手段,那么我们如何知道发生故障时系统的表现呢?这里就要依靠另外一个手段:故障演练。

故障演练指的是对系统进行一些破坏性的手段,观察在出现局部故障时,整体的系统表现是怎样的,从而发现系统中存在的,潜在的可用性问题。

一个复杂的高并发系统依赖了太多的组件,比方说磁盘,数据库,网卡等,这些组件随时随地都可能会发生故障,而一旦它们发生故障,会不会如蝴蝶效应一般造成整体服务不可用呢?我们并不知道,因此,故障演练尤为重要。

在我来看,故障演练和时下比较流行的“混沌工程”的思路如出一辙,作为混沌工程的鼻祖,Netfix在2010年推出的“Chaos Monkey”工具就是故障演练绝佳的工具。它通过在线上系统上随机地关闭线上节点来模拟故障,让工程师可以了解,在出现此类故障时会有什么样的影响。

当然,这一切是以你的系统可以抵御一些异常情况为前提的。如果你的系统还没有做到这一点,那么我建议你另外搭建一套和线上部署结构一模一样的线下系统,然后在这套系统上做故障演练,从而避免对生产系统造成影响。

小结

说了这么多,你可以看到从开发和运维角度上来看,提升可用性的方法是不同的:

  • 开发注重的是如何处理故障,关键词是冗余和取舍。冗余指的是有备用节点,集群来顶替出故障的服务,比如文中提到的故障转移,还有多活架构等等;取舍指的是丢卒保车,保障主体服务的安全。

  • 运维角度来看则更偏保守,注重的是如何避免故障的发生,比如更关注变更管理以及如何做故障的演练。

两者结合起来才能组成一套完善的高可用体系。

还需要注意的是,提高系统的可用性有时候是以牺牲用户体验或者是牺牲系统性能为前提的,也需要大量人力来建设相应的系统,完善机制。所以我们要把握一个度,不该做过度的优化。就像我在文中提到的,核心系统四个九的可用性已经可以满足需求,就没有必要一味地追求五个九甚至六个九的可用性。

另外,一般的系统或者组件都是追求极致的性能的,那么有没有不追求性能,只追求极致的可用性的呢?答案是有的。比如配置下发的系统,它只需要在其它系统启动时提供一份配置即可,所以秒级返回也可,十秒钟也OK,无非就是增加了其它系统的启动时间而已。但是,它对可用性的要求是极高的,甚至会到六个九,原因是配置可以获取的慢,但是不能获取不到。我给你举这个例子是想让你了解,可用性和性能有时候是需要做取舍的,但如何取舍就要视不同的系统而定,不能一概而论了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1253675.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯第2119题 特殊时间 C++ 思维暴力

题目 思路和解题方法 1110 代表 1110年11月10号11点10分1110 4*4*4 有0111 1011 1101 1110 可以符合年 月日 时分秒的都有4种例如 1113有1113 1131 1311 3111 年份符合月日只有11 13 时分秒 只有11 13 11 31 13 11 无31 11 c 代码 #include <bits/stdc.h> using…

使用Python的turtle库绘制随机生成的雪花

1.1引言 在这篇文章中&#xff0c;我们将使用Python的turtle库来绘制一个具有分支结构的雪花。该程序使用循环和随机颜色选择来绘制20个不同大小和颜色的雪花。turtle库是一个流行的绘图库&#xff0c;常用于创建图形用户界面和简单的动画。这个代码实现了一个有趣的应用&…

如何理解2023vivo开发者大会,使用Rust语言编写蓝河操作系统(BlueOS)?

在2023年vivo开发者大会上&#xff0c;vivo宣布使用Rust语言编写其蓝河操作系统&#xff08;BlueOS&#xff09;。 什么是Rust语言&#xff1f; Rust 是一种开放源代码系统编程语言&#xff0c;可用于开发高效、安全的软件。 使用 Rust 可管理内存并控制其低级详细信息。 但你…

Windows服务设置多个服务依赖项避免服务启动失败找不到数据库

添加多个服务依赖项建议通过命令行的方式添加&#xff1a; winr键打开命令行 cmd 命令行添加命令如下&#xff1a; sc config "thinvent-auth" depend "MySQL57"/"RabbitMQ"/"Redis" sc config "服务A" depend "服务…

【C++干货铺】优先队列 | 仿函数

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 优先队列&#xff08;priority_queue &#xff09;的介绍和使用 priority_queue的介绍 priority_queue的使用 大堆 小堆 priority_queue的模拟实现 仿…

算法-技巧-中等-颜色分类

记录一下算法题的学习12 颜色分类 题目&#xff1a;给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums &#xff0c;原地对它们进行排序&#xff0c;使得相同颜色的元素相邻&#xff0c;并按照红色、白色、蓝色顺序排列。 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝…

Linux进程管理,用户管理,文件压缩命令

gcc与g区别(补充了解): 比如有两个文件:main.c,mainc.cpp(分别用C语言和C语言写的)如果要用gcc编译呢? gcc -o mainc main.c gcc -o mainc mainc.cpp -lstdc 指明用c的标准库; 区别一: gcc默认只链接C库,并不会链接C的库;g会默认链接c标准库. 区别二: gcc编译.c文件,则按照C语…

小程序中的大道理之四--单元测试

在讨论领域模型之前, 先继续说下关于测试方面的内容, 前面为了集中讨论相应主题而对此作了推迟, 下面先补上关于测试方面的. 测试覆盖(Coverage) 先回到之前的一些步骤上, 假设我们现在写好了 getPattern 方法, 而 getLineContent 还处于 TODO 状态, 如下: public String ge…

Kubernetes 秘密暴露使大型区块链公司面临风险

领先的网络安全专家对公开的 Kubernetes 配置表示担忧&#xff0c;这可能会威胁许多组织供应链的安全。 受影响的公司包括两家主要的区块链公司&#xff08;出于安全原因&#xff0c;其名称已被隐去&#xff09;以及其他多家财富 500 强公司。 Aqua Security 研究人员报告称&…

【C++干货铺】非类型模板 | 模板特化 | 模板分离编译

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 非类型模板参数 模板的特化 什么是模板特化&#xff1f; 函数模板特化 类模板的特化 全特化 偏特化 模板的分离编译 什么是分离编译&#xff1f; 模板的…

shiro的前后端分离模式

shiro的前后端分离模式 前言&#xff1a;在上一篇《shiro的简单认证和授权》中介绍了shiro的搭建&#xff0c;默认情况下&#xff0c;shiro是通过设置cookie&#xff0c;使前端请求带有“JSESSION”cookie&#xff0c;后端通过获取该cookie判断用户是否登录以及授权。但是在前…

30系列显卡在ubuntu下不能满血运行的问题

之前发现在ubuntu下&#xff0c;我的3080只能跑115w最高&#xff0c;而这在win下是可以跑165w的。于是乎google了所有结果&#xff0c;无解… 现已经过去一年&#xff0c;显卡价格飞涨&#xff0c;无奈只能使用笔记本跑自己的代码了。结果发现nvidia推了Linux下的动态加速&…

用友NC word.docx接口存在任意文件读取漏洞 附POC

@[toc] 用友NC word.docx接口存在任意文件读取漏洞 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使…

有了倾斜摄影,如何搭建一座智慧城市?

随着无人机航测、倾斜摄影等全新一代测绘信息技术方法的发展&#xff0c;可以迅速搜集制作精细化的城市三维模型&#xff0c;搭建城市地理信息基础服务架构。 近期都在重点关注的“智慧城市”究竟是什么&#xff0c;有什么重大作用&#xff0c;同时又面临着什么难关&#xff0c…

Deepin使用记录-deepin系统下安装RabbitMq

目录 0、引言 1、由于RabbitMq是erlang语言开发的&#xff0c;所有需要先安装erlang 2、更新源并安装RabbitMq 3、安装完成之后&#xff0c;服务是启动的&#xff0c;可以通过以下语句查看状态 4、这样安装完成之后&#xff0c;是看不到web页面的&#xff0c;需要再安装一…

调试器gdb

目录 一、调试 1、前言 2、 debug和release 二、基本操作 1、退出 quit 2、开始调试 r 3、打断点 b 4、查看断点 info b 5、查看代码 l 6、删除断点 d 7、逐过程 n 8、打印变量内容 p 9、逐语句&#xff08;进入函数&#xff09; s 10、查看函数调用堆栈 bt 11、…

扫描条形码到电脑:Barcode to pc 4.6.3 Crack

像专业人士一样使用条形码将条形码发送到 PC 排名第一的智能手机扫描应用程序 将条形码即时发送到计算机程序并自动执行任务的最简单方法 受到全球 500,000 多名用户的信赖 条形码到 PC&#xff1a;Wi-Fi 扫描仪应用程序&#xff0c;条码到 PC&#xff1a;适用于 Android 和 i…

visual stdio动态库的使用

导出类和使用方式 #ifndef PCH_H #define PCH_H// 添加要在此处预编译的标头 #include "framework.h"#ifdef _WIN32 #ifdef MYCLASS_EXPORTS #define MYCLASS_API __declspec(dllexport) #else #define MYCLASS_API __declspec(dllimport) #endif #else #define MYC…

Nginx反向代理实现负载均衡webshell

目录 本实验所用的环境&#xff1a; 问题一&#xff1a;由于nginx采用的反向代理是轮询的方式&#xff0c;所以上传文件必须在两台后端服务器的相同位置上传相同的文件 问题二&#xff1a;我们在执行命令时&#xff0c;无法知道下次的请求交给哪台机器去执行我们在执行hostn…

C#,数值计算——有理函数插值和外推(Rational_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 有理函数插值和外推 /// Rational Function Interpolation and Extrapolation /// Given a value x, and using pointers to data xx and yy, this routine returns …