C. 高可用架构

C. 高可用架构
	FMEA
		具体分析方法
			给出初始的架构设计图。
			假设架构中某个部件发生故障。
			分析此故障对系统功能造成的影响。
			根据分析结果,判断架构是否需要进行优化。
		FMEA 分析表
			功能点
			故障模式
			故障影响
			严重程度
			故障原因
			故障概率
			风险程度
			已有措施
			规避措施
			解决措施
			后续规划
	概述
		本质:存储高可用方案的本质都是通过将数据复制到多个存储设备,通过数据冗余的方式来实现高可用,其复杂性主要体现在如何应对复制延迟和中断导致的数据不一致问题。
		思路
			各个节点的职责是什么?
			数据如何复制?
			如何应对复制延迟?
			如何应对复制中断?
	双机架构
		模式
			主备:其整体架构比较简单,主备架构中的“备机”主要还是起到一个备份作用,并不承担实际的业务读写操作,如果要把备机改为主机,需要人工操作。
				优点
					对于客户端来说,不需要感知备机的存在,即使灾难恢复后,原来的备机被人工修改为主机后,对于客户端来说,只是认为主机的地址换了而已,无须知道是原来的备机升级为主机。
					对于主机和备机来说,双方只需要进行数据复制即可,无须进行状态判断和主备切换这类复杂的操作。
				缺点
					备机仅仅只为备份,并没有提供读写操作,硬件成本上有浪费。
					故障后需要人工干预,无法自动恢复。人工处理的效率是很低的,可能打电话找到能够操作的人就耗费了 10 分钟,甚至如果是深更半夜,出了故障都没人知道。人工在执行恢复操作的过程中也容易出错,因为这类操作并不常见,可能 1 年就 2、3 次,实际操作的时候很可能遇到各种意想不到的问题。
			主从:与主备复制架构比较类似,主要的差别点在于从机正常情况下也是要提供读的操作。
				优点
					主从复制在主机故障时,读操作相关的业务可以继续运行。
					主从复制架构的从机提供读操作,发挥了硬件的性能。
				缺点
					主从复制架构中,客户端需要感知主从关系,并将不同的操作发给不同的机器进行处理,复杂度比主备复制要高。
					主从复制架构中,从机提供读业务,如果主从复制延迟比较大,业务会因为数据不一致出现问题。
					故障时需要人工干预。
			主备/主从(双机)切换
				关键技术点
					主备间状态判断:主要包括两方面:状态传递的渠道,以及状态检测的内容。
						状态传递的渠道:是相互间互相连接,还是第三方仲裁?
						状态检测的内容:例如机器是否掉电、进程是否存在、响应是否缓慢等。
					切换决策:主要包括几方面:切换时机、切换策略、自动程度。
						切换时机:什么情况下备机应该升级为主机?是机器掉电后备机才升级,还是主机上的进程不存在就升级,还是主机响应时间超过 2 秒就升级,还是 3 分钟内主机连续重启 3 次就升级等。
						切换策略:原来的主机故障恢复后,要再次切换,确保原来的主机继续做主机,还是原来的主机故障恢复后自动成为新的备机?
						自动程度:切换是完全自动的,还是半自动的?例如,系统判断当前需要切换,但需要人工做最终的确认操作(例如,单击一下“切换”按钮)。
					数据冲突解决
				常见架构
					互联式:故名思议,互连式就是指主备机直接建立状态传递的渠道,架构图请注意与主备复制架构对比。
						连接方式
							可以是网络连接(例如,各开一个端口),也可以是非网络连接(用串口线连接)。
							可以是主机发送状态给备机,也可以是备机到主机来获取状态信息。
							可以和数据复制通道共用,也可以独立一条通道。
							状态传递通道可以是一条,也可以是多条,还可以是不同类型的通道混合(例如,网络 + 串口)。
						客户端
							为了切换后不影响客户端的访问,主机和备机之间共享一个对客户端来说唯一的地址。例如虚拟 IP,主机需要绑定这个虚拟的 IP。
							客户端同时记录主备机的地址,哪个能访问就访问哪个;备机虽然能收到客户端的操作请求,但是会直接拒绝,拒绝的原因就是“备机不对外提供服务”。
						问题
							如果状态传递的通道本身有故障(例如,网线被人不小心踢掉了),那么备机也会认为主机故障了从而将自己升级为主机,而此时主机并没有故障,最终就可能出现两个主机。
							虽然可以通过增加多个通道来增强状态传递的可靠性,但这样做只是降低了通道故障概率而已,不能从根本上解决这个缺点,而且通道越多,后续的状态决策会更加复杂,因为对备机来说,可能从不同的通道收到了不同甚至矛盾的状态信息。
					中介式
						连接方式
							连接管理::主备机无须再建立和管理多种类型的状态传递连接通道,只要连接到中介即可,实际上是降低了主备机的连接管理复杂度。
							状态决策管理::主备机的状态决策简单了,无须考虑多种类型的连接通道获取的状态信息如何决策的问题,只需要按照下面简单的算法即可完成状态决策。
								无论是主机还是备机,初始状态都是备机,并且只要与中介断开连接,就将自己降级为备机,因此可能出现双备机的情况。
								主机与中介断连后,中介能够立刻告知备机,备机将自己升级为主机。
								如果是网络中断导致主机与中介断连,主机自己会降级为备机,网络恢复后,旧的主机以新的备机身份向中介上报自己的状态。
								如果是掉电重启或者进程重启,旧的主机初始状态为备机,与中介恢复连接后,发现已经有主机了,保持自己备机状态不变。
								主备机与中介连接都正常的情况下,按照实际的状态决定是否进行切换。例如,主机响应时间超过 3 秒就进行切换,主机降级为备机,备机升级为主机即可。
						缺点
							虽然中介式架构在状态传递和状态决策上更加简单,但并不意味着这种优点是没有代价的,其关键代价就在于如何实现中介本身的高可用。如果中介自己宕机了,整个系统就进入了双备的状态,写操作相关的业务就不可用了。这就陷入了一个递归的陷阱:为了实现高可用,我们引入中介,但中介本身又要求高可用,于是又要设计中介的高可用方案……如此递归下去就无穷无尽了。
					模拟式:模拟式指主备机之间并不传递任何状态数据,而是备机模拟成一个客户端,向主机发起模拟的读写操作,根据读写操作的响应情况来判断主机的状态。
						优点
							简单
						缺点
							因为模拟式读写操作获取的状态信息只有响应信息(例如,HTTP 404,超时、响应时间超过 3 秒等),没有互连式那样多样(除了响应信息,还可以包含 CPU 负载、I/O 负载、吞吐量、响应时间等),基于有限的状态来做状态决策,可能出现偏差。
			主主:主主复制指的是两台机器都是主机,互相将数据复制给对方,客户端可以任意挑选其中一台机器进行读写操作
				特点
					两台都是主机,不存在切换的概念。
					客户端无须区分不同角色的主机,随便将读写操作发送给哪台主机都可以。
				问题
					因此,主主复制架构对数据的设计有严格的要求,一般适合于那些临时性、可丢失、可覆盖的数据场景。例如,用户登录产生的 session 数据(可以重新登录生成)、用户行为的日志数据(可以丢失)、论坛的草稿数据(可以丢失)等。
	集群和分区
		概述:主备、主从、主主架构本质上都有一个隐含的假设:主机能够存储所有数据,但主机本身的存储和处理能力肯定是有极限的。
		集群
			1. 数据集中集群:数据集中集群与主备、主从这类架构相似,我们也可以称数据集中集群为 1 主多备或者 1 主多从。无论是 1 主 1 从、1 主 1 备,还是 1 主多备、1 主多从,数据都只能往主机中写,而读操作可以参考主备、主从架构进行灵活多变。
				主机如何将数据复制给备机
				备机如何检测主机状态
				主机故障后,如何决定新的主机
			2. 数据分散集群:数据分散集群指多个服务器组成一个集群,每台服务器都会负责存储一部分数据;同时,为了提升硬件利用率,每台服务器又会备份一部分数据。
				关键点
					均衡性:算法需要保证服务器上的数据分区基本是均衡的,不能存在某台服务器上的分区数量是另外一台服务器的几倍的情况。
					容错性:当出现部分服务器故障时,算法需要将原来分配给故障服务器的数据分区分配给其他服务器。
					可伸缩性:当集群容量不够,扩充新的服务器后,算法能够自动将部分数据分区迁移到新服务器,并保证扩容后所有服务器的均衡性。
		数据分区:数据分区指将数据按照一定的规则进行分区,不同分区分布在不同的地理位置上,每个分区存储一部分数据,通过这种方式来规避地理级别的故障所造成的巨大影响。采用了数据分区的架构后,即使某个地区发生严重的自然灾害或者事故,受影响的也只是一部分数据,而不是全部数据都不可用;当故障恢复后,其他地区备份的数据也可以帮助故障地区快速恢复业务。
			核心思想:近距离机房提供异地多活,远距离机房提供冷备
			关键技术点
				1. 数据量:数据量的大小直接决定了分区的规则复杂度。例如,使用 MySQL 来存储数据,假设一台 MySQL 存储能力是 500GB,那么 2TB 的数据就至少需要 4 台 MySQL 服务器;而如果数据是 200TB,并不是增加到 800 台的 MySQL 服务器那么简单。如果按照 4 台服务器那样去平行管理 800 台服务器,复杂度会发生本质的变化,具体表现为:
					800 台服务器里面可能每周都有一两台服务器故障,从 800 台里面定位出 2 台服务器故障,很多情况下并不是一件容易的事情,运维复杂度高。
					增加新的服务器,分区相关的配置甚至规则需要修改,而每次修改理论上都有可能影响已有的 800 台服务器的运行,不小心改错配置的情况在实践中太常见了。
					如此大量的数据,如果在地理位置上全部集中于某个城市,风险很大,遇到了水灾、大停电这种灾难性的故障时,数据可能全部丢失,因此分区规则需要考虑地理容灾。
				2. 分区规则:地理位置有近有远,因此可以得到不同的分区规则,包括洲际分区、国家分区、城市分区。具体采取哪种或者哪几种规则,需要综合考虑业务范围、成本等因素。
					通常情况下,洲际分区主要用于面向不同大洲提供服务,由于跨洲通讯的网络延迟已经大到不适合提供在线服务了,因此洲际间的数据中心可以不互通或者仅仅作为备份;
					国家分区主要用于面向不同国家的用户提供服务,不同国家有不同语言、法律、业务等,国家间的分区一般也仅作为备份;
					城市分区由于都在同一个国家或者地区内,网络延迟较低,业务相似,分区同时对外提供服务,可以满足业务异地多活之类的需求。
				3. 复制规则:数据分区指将数据分散在多个地区,在某些异常或者灾难情况下,虽然部分数据受影响,但整体数据并没有全部被影响,本身就相当于一个高可用方案了。但仅仅做到这点还不够,因为每个分区本身的数据量虽然只是整体数据的一部分,但还是很大,这部分数据如果损坏或者丢失,损失同样难以接受。因此即使是分区架构,同样需要考虑复制方案。
					集中式:集中式备份指存在一个总的备份中心,所有的分区都将数据备份到备份中心
						优缺点
							设计简单,各分区之间并无直接联系,可以做到互不影响。
							扩展容易,如果要增加第四个分区(例如,武汉分区),只需要将武汉分区的数据复制到西安备份中心即可,其他分区不受影响。
							成本较高,需要建设一个独立的备份中心。
					互备式:互备式备份指每个分区备份另外一个分区的数据
						优缺点
							设计比较复杂,各个分区除了要承担业务数据存储,还需要承担备份功能,相互之间互相关联和影响。
							扩展麻烦,如果增加一个武汉分区,则需要修改广州分区的复制指向武汉分区,然后将武汉分区的复制指向北京分区。而原有北京分区已经备份了的广州分区的数据怎么处理也是个难题,不管是做数据迁移,还是广州分区历史数据保留在北京分区,新数据备份到武汉分区,无论哪种方式都很麻烦。
							成本低,直接利用已有的设备。
					独立式:独立式备份指每个分区自己有独立的备份中心
						优缺点
							设计简单,各分区互不影响。
							扩展容易,新增加的分区只需要搭建自己的备份中心即可。
							成本高,每个分区需要独立的备份中心,备份中心的场地成本是主要成本,因此独立式比集中式成本要高很多。
	异地多活架构
		顾名思义,异地多活架构的关键点就是异地、多活,其中异地就是指地理位置上不同的地方,类似于“不要把鸡蛋都放在同一篮子里”;多活就是指不同地理位置上的系统都能够提供业务服务,这里的“活”是活动、活跃的意思。判断一个系统是否符合异地多活,需要满足两个标准:
			正常情况下,用户无论访问哪一个地点的业务系统,都能够得到正确的业务服务。
			某个地方业务异常的时候,用户访问其他地方正常的业务系统,能够得到正确的业务服务。
		架构模式
			1. 同城异区:同城异区指的是将业务部署在同一个城市不同区的多个机房。例如,在北京部署两个机房,一个机房在海淀区,一个在通州区,然后将两个机房用专用的高速网络连接在一起。
			2. 跨城异地:跨城异地指的是业务部署在不同城市的多个机房,而且距离最好要远一些。例如,将业务部署在北京和广州两个机房,而不是将业务部署在广州和深圳的两个机房。
			3. 跨国异地:跨国异地指的是业务部署在不同国家的多个机房。相比跨城异地,跨国异地的距离就更远了,因此数据同步的延时会更长,正常情况下可能就有几秒钟了。这种程度的延迟已经无法满足异地多活标准的第一条:“正常情况下,用户无论访问哪一个地点的业务系统,都能够得到正确的业务服务”。
				应用场景
					为不同地区用户提供服务
					只读类业务做多活
		思路
			技巧 1:保证核心业务的异地多活
			技巧 2:保证核心数据最终一致性
				问题:异地多活架构面临一个无法彻底解决的矛盾:业务上要求数据快速同步,物理上正好做不到数据快速同步,因此所有数据都实时同步,实际上是一个无法达到的目标。
				解决思路:尽可能减少影响
					尽量减少异地多活机房的距离,搭建高速网络
					尽量减少数据同步,只同步核心业务相关的数据
					保证最终一致性,不保证实时一致性
			技巧 3:采用多种手段同步数据
				存储系统同步机制
				消息队列
				二次读取方式:某些情况下可能出现消息队列同步也延迟了,用户在 A 中心注册,然后访问 B 中心的业务,此时 B 中心本地拿不到用户的账号数据。为了解决这个问题,B 中心在读取本地数据失败时,可以根据路由规则,再去 A 中心访问一次(这就是所谓的二次读取,第一次读取本地,本地失败后第二次读取对端),这样就能够解决异常情况下同步延迟的问题。
				回源读取方式:对于登录的 session 数据,由于数据量很大,我们可以不同步数据;但当用户在 A 中心登录后,然后又在 B 中心登录,B 中心拿到用户上传的 session id 后,根据路由判断 session 属于 A 中心,直接去 A 中心请求 session 数据即可;反之亦然,A 中心也可以到 B 中心去获取 session 数据。
				重新生成数据方式:对于“回源读取”场景,如果异常情况下,A 中心宕机了,B 中心请求 session 数据失败,此时就只能登录失败,让用户重新在 B 中心登录,生成新的 session 数据。
			技巧 4:只保证绝大部分用户的异地多活
		设计步骤
			业务分级
				访问量大的业务
				核心业务
				产生大量收入的业务
			数据分类
				数据量:这里的数据量包括总的数据量和新增、修改、删除的量。对异地多活架构来说,新增、修改、删除的数据就是可能要同步的数据,数据量越大,同步延迟的几率越高,同步方案需要考虑相应的解决方案。
				唯一性:数据的唯一性影响业务的多活设计,如果数据不需要唯一,那就说明两个地方都产生同类数据是可能的;如果数据要求必须唯一,要么只能一个中心点产生数据,要么需要设计一个数据唯一生成的算法。
				实时性:实时性指如果在 A 机房修改了数据,要求多长时间必须同步到 B 机房,实时性要求越高,对同步的要求越高,方案越复杂。
				可丢失性:可丢失性指数据是否可以丢失。
				可恢复性
			数据同步
				存储系统同步
				消息队列同步
				重复生成
			异常处理
				目标
					问题发生时,避免少量数据异常导致整体业务不可用。
					问题恢复后,将异常的数据进行修正。
					对用户进行安抚,弥补用户损失。
				措施
					多通道同步
						关键点
							一般情况下,采取两通道即可,采取更多通道理论上能够降低风险,但付出的成本也会增加很多。
							数据库同步通道和消息队列同步通道不能采用相同的网络连接,否则一旦网络故障,两个通道都同时故障;可以一个走公网连接,一个走内网连接。
							需要数据是可以重复覆盖的,即无论哪个通道先到哪个通道后到,最终结果是一样的。例如,新建账号数据就符合这个标准,而密码数据则不符合这个标准。
					同步和访问结合
						关键点
							接口访问通道和数据库同步通道不能采用相同的网络连接,不能让数据库同步和接口访问都走同一条网络通道,可以采用接口访问走公网连接,数据库同步走内网连接这种方式。
							数据有路由规则,可以根据数据来推断应该访问哪个机房的接口来读取数据。例如,有 3 个机房 A、B、C,B 机房拿到一个不属于 B 机房的数据后,需要根据路由规则判断是访问 A 机房接口,还是访问 C 机房接口。
							由于有同步通道,优先读取本地数据,本地数据无法读取到再通过接口去访问,这样可以大大降低跨机房的异地接口访问数量,适合于实时性要求非常高的数据。
					日志记录
						为了应对不同级别的故障,日志保存的要求也不一样,常见的日志保存方式有:
							服务器上保存日志,数据库中保存数据,这种方式可以应对单台数据库服务器故障或者宕机的情况。
							本地独立系统保存日志,这种方式可以应对某业务服务器和数据库同时宕机的情况。例如,服务器和数据库部署在同一个机架,或者同一个电源线路上,就会出现服务器和数据库同时宕机的情况。
							日志异地保存,这种方式可以应对机房宕机的情况。
					用户补偿:常见的补偿措施有送用户代金券、礼包、礼品、红包等,有时为了赢得用户口碑,付出的成本可能还会比较大,但综合最终的收益来看还是很值得的。
	计算高可用
		核心思想:计算高可用的主要设计目标是当出现部分硬件损坏时,计算任务能够继续正常运行。
		关键技术
			任务管理
				哪些服务器可以执行任务
					第一种方式和计算高性能中的集群类似,每个服务器都可以执行任务。例如,常见的访问网站的某个页面。
					第二种方式和存储高可用中的集群类似,只有特定服务器(通常叫“主机”)可以执行任务。当执行任务的服务器故障后,系统需要挑选新的服务器来执行任务。例如,ZooKeeper 的 Leader 才能处理写操作请求。
				任务如何重新执行
					第一种策略是对于已经分配的任务即使执行失败也不做任何处理,系统只需要保证新的任务能够分配到其他非故障服务器上执行即可。
					第二种策略是设计一个任务管理器来管理需要执行的计算任务,服务器执行完任务后,需要向任务管理器反馈任务执行结果,任务管理器根据任务执行结果来决定是否需要将任务重新分配到另外的服务器上执行。
				应用
					Nginx 将页面请求发送给 Web 服务器,而 CSS/JS 等静态文件直接读取本地缓存。这里的 Nginx 角色是反向代理系统,但是承担了任务分配器的职责,而不需要 Nginx 做反向代理,后面再来一个任务分配器。
					对于一些后台批量运算的任务,可以设计一个独立的任务分配系统来管理这些批处理任务的执行和分配。
					ZooKeeper 中的 Follower 节点,当接收到写请求时会将请求转发给 Leader 节点处理,当接收到读请求时就自己处理,这里的 Follower 就相当于一个逻辑上的任务分配器。
		解决方案
			主备:主备架构是计算高可用最简单的架构,和存储高可用的主备复制架构类似,但是要更简单一些,因为计算高可用的主备架构无须数据复制
				设计方案
					主机执行所有计算任务。例如,读写数据、执行操作等。
					当主机故障(例如,主机宕机)时,任务分配器不会自动将计算任务发送给备机,此时系统处于不可用状态。
					如果主机能够恢复(不管是人工恢复还是自动恢复),任务分配器继续将任务发送给主机。
					如果主机不能够恢复(例如,机器硬盘损坏,短时间内无法恢复),则需要人工操作,将备机升为主机,然后让任务分配器将任务发送给新的主机(即原来的备机);同时,为了继续保持主备架构,需要人工增加新的机器作为备机。
				类型
					冷备:备机上的程序包和配置文件都准备好,但备机上的业务系统没有启动(注意:备机的服务器是启动的),主机故障后,需要人工手工将备机的业务系统启动,并将任务分配器的任务请求切换发送给备机。
					温备:备机上的业务系统已经启动,只是不对外提供服务,主机故障后,人工只需要将任务分配器的任务请求切换发送到备机即可。冷备可以节省一定的能源,但温备能够大大减少手工操作时间,因此一般情况下推荐用温备的方式。
				优缺点
					优点
						主备架构的优点就是简单,主备机之间不需要进行交互,状态判断和切换操作由人工执行,系统实现很简单。
					缺点
						而缺点正好也体现在“人工操作”这点上,因为人工操作的时间不可控,可能系统已经发生问题了,但维护人员还没发现,等了 1 个小时才发现。发现后人工切换的操作效率也比较低,可能需要半个小时才完成切换操作,而且手工操作过程中容易出错。例如,修改配置文件改错了、启动了错误的程序等。
			主从:和存储高可用中的主从复制架构类似,计算高可用的主从架构中的从机也是要执行任务的。任务分配器需要将任务进行分类,确定哪些任务可以发送给主机执行,哪些任务可以发送给备机执行,
				设计方案
					正常情况下,主机执行部分计算任务(如图中的“计算任务 A”),备机执行部分计算任务(如图中的“计算任务 B”)。
					当主机故障(例如,主机宕机)时,任务分配器不会自动将原本发送给主机的任务发送给从机,而是继续发送给主机,不管这些任务执行是否成功。
					如果主机能够恢复(不管是人工恢复还是自动恢复),任务分配器继续按照原有的设计策略分配任务,即计算任务 A 发送给主机,计算任务 B 发送给从机。
					如果主机不能够恢复(例如,机器硬盘损坏,短时间内无法恢复),则需要人工操作,将原来的从机升级为主机(一般只是修改配置即可),增加新的机器作为从机,新的从机准备就绪后,任务分配器继续按照原有的设计策略分配任务。
				优缺点
					优点:主从架构的从机也执行任务,发挥了从机的硬件性能。
					缺点:主从架构需要将任务分类,任务分配器会复杂一些。
			集群
				对称集群
					设计方案
						正常情况下,任务分配器采取某种策略(随机、轮询等)将计算任务分配给集群中的不同服务器。
						当集群中的某台服务器故障后,任务分配器不再将任务分配给它,而是将任务分配给其他服务器执行。
						当故障的服务器恢复后,任务分配器重新将任务分配给它执行。
					关键点
						任务分配器需要选取分配策略。
						任务分配器需要检测服务器状态。
				非对称集群:非对称集群中不同服务器的角色是不同的,不同角色的服务器承担不同的职责。以 Master-Slave 为例,部分任务是 Master 服务器才能执行,部分任务是 Slave 服务器才能执行。
					详细设计
						集群会通过某种方式来区分不同服务器的角色。例如,通过 ZAB 算法选举,或者简单地取当前存活服务器中节点 ID 最小的服务器作为 Master 服务器。
						任务分配器将不同任务发送给不同服务器。例如,图中的计算任务 A 发送给 Master 服务器,计算任务 B 发送给 Slave 服务器。
						当指定类型的服务器故障时,需要重新分配角色。例如,Master 服务器故障后,需要将剩余的 Slave 服务器中的一个重新指定为 Master 服务器;如果是 Slave 服务器故障,则并不需要重新分配角色,只需要将故障服务器从集群剔除即可。
					关键点
						任务分配策略更加复杂:需要将任务划分为不同类型并分配给不同角色的集群节点。
						角色分配策略实现比较复杂:例如,可能需要使用 ZAB、Raft 这类复杂的算法来实现 Leader 的选举。
	限流降级 --- 应对接口级故障

猜你喜欢

转载自blog.csdn.net/micklongen/article/details/89762922