当我们在讨论系统架构的时候经常听到HA(High Availability 高可用)如何如何保证, 在调研CockRoachDB时看到个MA(Multi-Active Availability 多活可用)的概念, 头一次听说, 比较新颖, 所以网上查了一上, 说到底还是CAP那一套.
High Availability
我们经常会错误的认为高可用就是一致性,其实并不然.
高可用性,是指应用程序在其中一个服务的宿主系统发生故障的时候,仍然能够不停地运行。这是通过水平拓展应用程序服务的方式来实现的(例如在多台机器和系统上部署相同的服务)。如果它们当中的其中一个服务发生故障,其他服务能够接替并提供相同的服务内容
高可用强调的是在节点发生故障时, 系统仍然可以提供服务, 并不关心数据一致性的问题.
两种使用最频繁的高可用性设计方案:Active-Passive和Active-Active系统
Active-Passive
在Active-Passive系统中,所有流量会路由到一个“Active“的主副本。这个副本上状态的变化将同步到备份的“Passive”的从副本,系统尽可能地保证“Passive”副本与“Active”副本之间的一致性。
很典型的是Oracle数据库.
然而这种设计存在以下缺点:
- 如果用户使用异步复制策略,将无法保证所有数据成功地同步到“Passive”的从副本。这就意味着用户可能丢失数据,在特定的应用场景下这可能导致非常可怕的后果。
- 如果用户使用同步复制策略,在“Passive”的从副本出现故障的时候,用户不得不牺牲整个应用系统的可用性,否则将面临不一致的风险
Active-Active
在Active-Active系统中,多个副本各自运行着独立的服务。负载被路由到所有副本上。如果一个副本出现故障,其他副本可以继续处理原本应该路由到故障副本上的负载。
对于数据库而言,Active-Active的系统对于大多数工作负载来说是难以实现的。例如:如果用户想让多个副本处理同一份数据的写操作,如何保证它们的一致性?
打个比说:
在Active-Active设计的高可用性集群当中有2个副本(A和B)。
- A确认键
xyz
的写请求,值为'123'
,随后发生故障。 - B确认键
xyz
的读请求,因为没找到匹配键值对,返回NULL
。 - B确认键
xyz
的写请求,值为'456'
。 - A重启并尝试再次与B连接,此时如何处理
xyz
值的不同?在系统里面没有一个清晰的方式去处理这种数据不一致的情况。
在这个例子当中,集群在整个生命周期内保持Active状态。根据CAP理论,这是AP系统,它能够在分区发生时保证可用性,而不能保证一致性。
Multi-Active Availability
像Active-Ative设计模式,具备多活可用性的系统当中的所有副本,都处理读和写的负载。CockroachDB在此基础上做了改进,使用“一致性副本”实现了数据之间一致性。在这种设计里,同步请求将发送到至少3个副本,且只有绝大多数副本响应了该请求,才能视作同步完成。这就意味着用户在系统不满足可用条件时仍然会遇到系统故障。
为了避免冲突,保证数据的一致性,集群如果丢失了绝大多数副本,将停止响应。这是因为在故障系统里的副本丧失了使数据达成一致的能力。待到绝大多数副本重启以后,数据库将恢复可用。
在一个多活可用的集群中有3个CockroachDB节点(A、B、C)。
- A接收到键
xyz
的写请求,值为'123'
。它与节点B和C同步写请求结果,确保它们确认了写请求结果。一旦A收到第一个确认,写请求完成。 - A随后发生故障。
- B接收到键
xyz
的读请求,返回值'123'
- C接收到键
xyz
的更新请求,修改值为'456'
。它与节点B同步写请求结果,确保B确认了写请求结果。在C接收到来自节点B的确认之后,写请求完成。 - A重启,再次加入集群。它接收到了键
xyz
的最新值,将旧值更新为'456'
。
在这个例子当中,如果在A故障以后B或C发生故障,集群将停止响应。根据CAP理论,这是一个CP系统,它能够在分区发生时保证一致性,而不是保证可用性。