网站首页 > 文章精选 正文
程序员瓶颈突破架构师?架构设计的理论与实践
每个程序员都有一个成为架构师的梦想,奈何手里无枪无法点燃心中奇梦。本系列文章分享如何让你手里有枪,只要努力,技术的梦想一定能实现,这应该是众多梦想中离地表最近的一个。
双机切换
设计关键
主备复制和主从复制方案存在两个共性的问题:
- 主机故障后,无法进行写操作
- 如果主机无法恢复,需要人工指定新的主机角色
双机切换就是为了解决这两个问题而产生的,包括主备切换和主从切换两种方案。
简单来说,这两个方案就是在原有方案的基础上增加“切换”功能,即系统自动决定主机角色,并完成角色切换。
由于主备切换和主从切换在切换的设计上没有差别,我接下来以主备切换为例,一起来看看双机切换架构是如何实现的。
要实现一个完善的切换方案,必须考虑这几个关键的设计点:
- 主备间状态判断
主要包括两方面:状态传递的渠道,以及状态检测的内容
状态传递的渠道:是相互间互相连接,还是第三方仲裁?
状态检测的内容:例如机器是否掉电、进程是否存在、响应是否缓慢等 - 切换决策
主要包括几方面:切换时机、切换策略、自动程度。
切换时机:什么情况下备机应该升级为主机?是机器掉电后备机才升级,还是主机上的进程不存在就升级,还是主机响应时间超过2秒就升级,还是3分钟内主机连续重启3次就升级等。
切换策略:原来的主机故障恢复后,要再次切换,确保原来的主机继续做主机,还是原来的主机故障恢复后自动成为新的备机?
自动程度:切换是完全自动的,还是半自动的?例如,系统判断当前需要切换,但需要人工做最终的确认操作(例如,单击一下“切换”按钮)。 - 数据冲突解决
当原有故障的主机恢复后,新旧主机之间可能存在数据冲突。
例如,用户在旧主机上新增了一条ID为100的数据,这个数据还没有复制到旧的备机,此时发生了切换,旧的备机升级为新的主机,用户又在新的主机上新增了一条ID为100的数据,当旧的故障主机恢复后,这两条ID都为100的数据,应该怎么处理?
以上设计点并没有放之四海而皆准的答案,不同的业务要求不一样,所以切换方案比复制方案不只是多了一个切换功能那么简单,而是复杂度上升了一个量级。
形象点来说,如果复制方案的代码是1000行,那么切换方案的代码可能就是10000行,多出来的那9000行就是用于实现上面我所讲的3个设计点的。
双机切换常见架构
根据状态传递渠道的不同,常见的主备切换架构有三种形式:互连式、中介式和模拟式。
互连式
故名思议,互连式就是指主备机直接建立状态传递的渠道,架构图请注意与主备复制架构对比。
你可以看到,在主备复制的架构基础上,主机和备机多了一个“状态传递”的通道,这个通道就是用来传递状态信息的。这个通道的具体实现可以有很多方式:
- 可以是网络连接(例如,各开一个端口),也可以是非网络连接(用串口线连接)
- 可以是主机发送状态给备机,也可以是备机到主机来获取状态信息
- 可以和数据复制通道共用,也可以独立一条通道
- 状态传递通道可以是一条,也可以是多条,还可以是不同类型的通道混合(例如,网络+串口)
为了充分利用切换方案能够自动决定主机这个优势,客户端这里也会有一些相应的改变,常见的方式有:
- 为了切换后不影响客户端的访问,主机和备机之间共享一个对客户端来说唯一的地址。例如虚拟IP,主机需要绑定这个虚拟的IP
- 客户端同时记录主备机的地址,哪个能访问就访问哪个;备机虽然能收到客户端的操作请求,但是会直接拒绝,拒绝的原因就是“备机不对外提供服务”
互连式主备切换主要的缺点在于:
- 如果状态传递的通道本身有故障(例如,网线被人不小心踢掉了),那么备机也会认为主机故障了从而将自己升级为主机,而此时主机并没有故障,最终就可能出现两个主机。
- 虽然可以通过增加多个通道来增强状态传递的可靠性,但这样做只是降低了通道故障概率而已,不能从根本上解决这个缺点,而且通道越多,后续的状态决策会更加复杂,因为对备机来说,可能从不同的通道收到了不同甚至矛盾的状态信息。
中介式
中介式指的是在主备两者之外引入第三方中介,主备机之间不直接连接,而都去连接中介,并且通过中介来传递状态信息,其架构图如下:
对比一下互连式切换架构,我们可以看到,主机和备机不再通过互联通道传递状态信息,而是都将状态上报给中介这一角色。
单纯从架构上看,中介式似乎比互连式更加复杂了,首先要引入中介,然后要各自上报状态。然而事实上,中介式架构在状态传递和决策上却更加简单了,这是为何呢?
连接管理更简单:
主备机无须再建立和管理多种类型的状态传递连接通道,只要连接到中介即可,实际上是降低了主备机的连接管理复杂度。
例如,互连式要求主机开一个监听端口,备机来获取状态信息;或者要求备机开一个监听端口,主机推送状态信息到备机;如果还采用了串口连接,则需要增加串口连接管理和数据读取。
采用中介式后,主备机都只需要把状态信息发送给中介,或者从中介获取对方的状态信息。无论是发送还是获取,主备机都是作为中介的客户端去操作,复杂度会降低。
状态决策更简单:
主备机的状态决策简单了,无须考虑多种类型的连接通道获取的状态信息如何决策的问题,只需要按照下面简单的算法即可完成状态决策:
- 无论是主机还是备机,初始状态都是备机,并且只要与中介断开连接,就将自己降级为备机,因此可能出现双备机的情况
- 主机与中介断连后,中介能够立刻告知备机,备机将自己升级为主机
- 如果是网络中断导致主机与中介断连,主机自己会降级为备机,网络恢复后,旧的主机以新的备机身份向中介上报自己的状态
- 如果是掉电重启或者进程重启,旧的主机初始状态为备机,与中介恢复连接后,发现已经有主机了,保持自己备机状态不变
- 主备机与中介连接都正常的情况下,按照实际的状态决定是否进行切换。例如,主机响应时间超过3秒就进行切换,主机降级为备机,备机升级为主机即可
虽然中介式架构在状态传递和状态决策上更加简单,但并不意味着这种优点是没有代价的,其关键代价就在于如何实现中介本身的高可用。
如果中介自己宕机了,整个系统就进入了双备的状态,写操作相关的业务就不可用了。
这就陷入了一个递归的陷阱:为了实现高可用,我们引入中介,但中介本身又要求高可用,于是又要设计中介的高可用方案……如此递归下去就无穷无尽了。
MongoDB的Replica Set采取的就是这种方式,其基本架构如下:
MongoDB(M)表示主节点,MongoDB(S)表示备节点,MongoDB(A)表示仲裁节点。主备节点存储数据,仲裁节点不存储数据。客户端同时连接主节点与备节点,不连接仲裁节点。
幸运的是,开源方案已经有比较成熟的中介式解决方案,例如ZooKeeper和Keepalived。
ZooKeeper本身已经实现了高可用集群架构,因此已经帮我们解决了中介本身的可靠性问题,在工程实践中推荐基于ZooKeeper搭建中介式切换架构。
模拟式
模拟式指主备机之间并不传递任何状态数据,而是备机模拟成一个客户端,向主机发起模拟的读写操作,根据读写操作的响应情况来判断主机的状态。其基本架构如下:
对比一下互连式切换架构,我们可以看到,主备机之间只有数据复制通道,而没有状态传递通道,备机通过模拟的读写操作来探测主机的状态,然后根据读写操作的响应情况来进行状态决策。
模拟式切换与互连式切换相比,优点是实现更加简单,因为省去了状态传递通道的建立和管理工作。
简单既是优点,同时也是缺点。
因为模拟式读写操作获取的状态信息只有响应信息(例如,HTTP 404,超时、响应时间超过3秒等),没有互连式那样多样(除了响应信息,还可以包含CPU负载、I/O负载、吞吐量、响应时间等),基于有限的状态来做状态决策,可能出现偏差。
主主复制
主主复制指的是两台机器都是主机,互相将数据复制给对方,客户端可以任意挑选其中一台机器进行读写操作,下面是基本架构图。
相比主备切换架构,主主复制架构具有如下特点:
- 两台都是主机,不存在切换的概念
- 客户端无须区分不同角色的主机,随便将读写操作发送给哪台主机都可以
从上面的描述来看,主主复制架构从总体上来看要简单很多,无须状态信息传递,也无须状态决策和状态切换。
然而事实上主主复制架构也并不简单,而是有其独特的复杂性,具体表现在:如果采取主主复制架构,必须保证数据能够双向复制,而很多数据是不能双向复制的。
例如:
用户注册后生成的用户ID,如果按照数字增长,那就不能双向复制,否则就会出现X用户在主机A注册,分配的用户ID是100,同时Y用户在主机B注册,分配的用户ID也是100,这就出现了冲突。
库存不能双向复制。例如,一件商品库存100件,主机A上减了1件变成99,主机B上减了2件变成98,然后主机A将库存99复制到主机B,主机B原有的库存98被覆盖,变成了99,而实际上此时真正的库存是97。
类似的还有余额数据。
因此,主主复制架构对数据的设计有严格的要求,一般适合于那些临时性、可丢失、可覆盖的数据场景。
例如,用户登录产生的session数据(可以重新登录生成)、用户行为的日志数据(可以丢失)、论坛的草稿数据(可以丢失)等。
猜你喜欢
- 2024-12-27 西门子 200PLC数据存储区及其含义
- 2024-12-27 空压机|这个部位保养好,不但节能还可能延长5年整机寿命
- 2024-12-27 转载--减负荷过程中为什么主汽压力升高会导致主汽温度下降?
- 2024-12-27 MAN B&W 主机EGR系统使用说明及日常管理
- 2024-12-27 Linux网络协议栈-TCP/IP协议报文格式解析(内含代码演示)
- 2024-12-27 性价比爆棚!全新N100小主机跌至444元,比二手更便宜
- 2024-12-27 夏天电脑性能低?真相在你的CPU表面
- 2024-12-27 杀疯了!宁美i7-12700F+RTX3060游戏主机直降600元
- 2024-12-27 IP地址和子网掩码的基础知识 ip地址和子网掩码是什么
- 2024-12-27 干货!人造雾主机适用的保养维护方案以及冬季特殊护理—锦胜雾森
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)