-
什么是高可用
-
如何实现故障探测
-
如何解决脑裂问题
-
如何解决数据复制问题
-
如何做到数据一致
-
同步复制
-
异步复制
-
处理节点宕机
-
Slave故障:
-
Master故障
-
如何做到对客户端透明化
-
总结
-
参考
什么是高可用
高可用HA(High Availability):通过设计减少系统不能提供服务的时间。假设系统一直能够提供服务,我们说系统的可用性是100%。如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。
简而言之就是我们如何减少故障发生后的恢复时间,因为机器故障是无法避免的,我们只能去减少故障发生后的恢复时间。要想快速恢复故障,最好的办法就是避免服务单节点,让每个服务有多个副本,当单台机器宕机后可以快速切换到其他副本继续提供服务,也就是自动实现故障转义(Failover)。要实现一套完整的Failover方案必须要考虑如下几个问题
如何实现故障探测
实现故障探测最简单也是最常用的方式基本就是通过心跳来周期性探测,但是周期性探测会遇到如下几个问题。我们以Master和Slave为例
-
Master进程宕机 -
Master所在机器宕机 -
Master暂时僵死(实际过几分钟或几十秒继续能提供服务) -
Master进程正常,只是因为网络抖动问题导致心跳检测失败
前两种场景很好解决,因为Master是真的宕机了,后两者则是发生了误判。就可能导致脑裂
如何解决脑裂问题
在发生误判的情况下,旧Master还存活,而这时候切换到了新Master,新旧Master同时存活,而有的客户端还连接旧Master,有的客户端连接到了新的Master,这时候两个Master同时写入数据就会导致数据错乱
那么如何解决这种问题呢?主要方式有如下三种
-
隔离:对旧Master进行隔离,杀死旧的Master进程或者旧Master不提供服务 -
纪元(epoch):每次新Master切换都会产生新的epoch.旧Master发现自己的epoch是旧的,主动退位(切换成Slave) -
租约机制:由Master(房东)和协调者(租客)签约,租期到了,要么续约,要么过期(则意味着旧Master退位),新Master上位可以保证旧Master的租约一定是失效的(即一间房不能同时租给两个人)
如何解决数据复制问题
当有了多个副本,必须要解决的一个问题是:如何确保所有数据都落在了所有的副本上
最常见的方式就是:基于领导者的复制(leader-based replication)
工作原理大致如下:
-
当客户端要向数据库写入时,它必须将请求发送给Master,Master会将新数据写入其本地存储 -
每当Master将新数据写入本地存储时,它也会将数据变更发送给所有的Slave,称之为复制日志(replication log) 记录或变更流(change stream)。每个Slave从Master拉取日志,并相应更新其本地数据库副本,方法是按照Master处理的相同顺序应用所有写入 -
当Slave想要读取数据时,它可以向Master或Slave查询。但只有Master才能接受写操作(从客户端的角度来看从库都是只读的)
如何做到数据一致
因为有Master和Slave,所以Master和Slave之间肯定需要数据同步,Master和Slave之间的数据同步有如下两种方式:同步复制和异步复制
同步复制
同步复制就是主库写完数据后,必须要从库(不是所有从库,只需要有一个同步从库)也确定写成功才算成功
从上面图中可以看出同步复制实际也只有Follower1是与Master同步复制的,其他的节点比如Follower2也是异步复制。这种同步方式也称为半同步(semi-synchronous)
同步复制的优点很明显:从库保证有与主库一致的最新数据副本。如果主库突然失效,我们可以确信这些数据仍然能在从库上找到。缺点是,如果同步从库没有响应(比如它已经崩溃,或者出现网络故障,或其它任何原因),主库就无法处理写入操作。主库必须阻止所有写入,并等待同步副本再次可用.
将所有从库都设置为同步的是不切实际的:任何一个节点的中断都会导致整个系统停滞不前。实际上,如果在数据库上启用同步复制,通常意味着其中一个跟随者是同步的,而其他的则是异步的。如果同步从库变得不可用或缓慢,则使一个异步从库同步。这保证你至少在两个节点上拥有最新的数据副本:主库和同步从库(半同步)
异步复制
如果是异步复制,Slave的数据相比Master肯定是有一定的延时的,那么Master宕机后,Slave立即切换为Master肯定是会有数据丢失的,如何解决?
数据一致性方案有很多,数据一致性要求越高,实现技术难度也就越高。目前主要有以下几种数据一致性
其中最难的就是强一致性
处理节点宕机
任何节点都有可能出现宕机,我们如何处理节点的宕机呢?
节点分为Master和Slave,所以故障处理也分为Master故障和Slave故障
Slave故障:
Slave故障主要是分如下两种:
-
从库崩溃并重新启动 -
主库和从库之间的网络暂时中断
两种故障的解决方式都是如下:从库可以从日志中知道,在发生故障之前处理的最后一个事务。因此,从库可以连接到主库,并请求在从库断开期间发生的所有数据变更。当应用完所有这些变化后,它就赶上了主库,并可以像以前一样继续接收数据变更流
Master故障
主库失效处理起来相当棘手:其中一个从库需要被提升为新的主库,需要重新配置客户端,以将它们的写操作发送给新的主库,其他从库需要开始拉取来自新主库的数据变更。这个过程被称为 故障切换(failover)。而故障切换问题又回到了数据一致问题的处理。不同中间件有不同的实现方式。自动故障的实现方式比较复杂,即使一些软件支持自动切换,但是很多运维团队还是愿意手动切换,因为自动故障切换要解决的上面的很多问题,并不是那么容易
如何做到对客户端透明化
这里又分如下几种情况
-
如果客户端连接的是Master的IP,主从切换后,客户端如何感知变化,自动切换到新的Master(连接新的Master IP)。
目前解决方案有如下
1. VIP(virtual IP address,虚IP漂移,不支持跨网段、跨机房切换)
2. DNS
3. 客户端维护所有的IP列表,自己做心跳探测,客户端自己切换
4. 增加服务代理,客户端连接服务代理,服务代理维护所有的IP列表,做心跳检测,客户端切换
-
客户端与旧Master之间的连接为长连接,并且客户端采用了长连接池(类似于数据库连接池),当Master发送主从切换,所有的长连接都要失效,客户端要和新的Master建立长连接池。这个连接工作,是业务系统自己实现,还是统一封装成SDK -
Master切换需要的时间是多久?秒级别还是分钟级别?在切换过程中服务是否处于不可用状态?客户端处理的策略是什么?
总结
可以看出分布式系统要满足高可用还是很复杂的,需要解决的问题很多,细节更是很多,主要是有如下一些问题:
-
如何做故障检测 -
如何解决多副本之间的数据同步 -
数据不一致需要如何处理 -
脑裂如何处理 -
如何做到对客户端透明化
实际所有的分布式系统都面临上面的问题,大多都需要解决1-4这四个问题,至于第五个问题有一些是自身处理了,也有一些依赖于其他三方客户端作代理处理。要解决1-4这几个问题并不是那么容易处理。有些问题还是非常棘手的。后续我们会继续详细介绍如何处理并结合实际案例
参考
-
大型系统架构设计方法论与实践 -
设计数据密集型应用
原文始发于微信公众号(小奏技术):你所不了解的分布性系统之高可用篇
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/30075.html