在互联网出现之前,7*24小时的可用性基本是不可能实现的,而现在凌晨处理用户请求已经成为了常态。当然,如果仅仅是依靠一台电脑来实现这些请求是不太现实的,为了保证正常运行,最好是在满足我们需求的多台计算机之间分配负载。
分布式除了具备众所周知的优点,也有很多明显的缺点,例如其具有尖锐的边缘,特别是在同步和容忍系统内部分故障的方面。数据库中的分布式,与其它计算机科学领域的技术相比,发展比较缓慢,往往是软件在跟踪本地数据库中的分布式计算结果,但数据库本身的状态保存在一台机器上。为什么?因为跨机器复制状态很难。
所以,本文就来探讨一下分布式数据库如何处理系统内的部分故障,并在其它层次上解释一下高可用性。
Christina Chung
Active-Passive
以前,数据库只在单台机器上运行,只有一个节点,处理所有读写和写入,自然也就是不存在“部分失败”这样的事情。
对于互联网来说,单个数据库的完全失败是一个双重问题,首先,计算机是全天候访问的,因此停机时间直接会影响用户;其次,一次请求失败可能会导致系统不断的请求,加重后果。而想要解决这个问题也很简单,那就是拥有多台可以处理请求的计算机,这就是分布式数据库真正开始的故事。
在单节点世界中,最明显的解决方案是继续让单个节点提供读写操作,并简单地将其状态同步到辅助被动机器上,这样Active-Passive复制就诞生了。
Active-Passive通过在主节点发生故障的情况下进行最新备份来提高可用性,用户可以将流量定向到Passive节点,并将其状态转换为active。无论何时,只要有服务器出现问题,都可以用新的机器替换掉。
首先,从active节点到 passive节点的复制是一个同步过程,即在passive节点确认之前,不会提交转换。但是,如果passive节点也发生故障,那么就可能会让人有些手足无措,如果要是备份系统不可用,那么整个系统一旦崩溃就完蛋了。
为了进一步提高可用性,可以异步复制数据。虽然体系结构看起来相同,但异步复制能够处理active或passive节点,而不会影响数据库的可用性。
异步Active-Passive已经是向前发展了一大步,但是其仍存在重大缺陷:
- 当active节点死亡时,尚未复制到passive节点的数据都可能丢失,而这时客户端可能会认为数据已经完全提交了。
- 依靠一台机器来处理流量,你仍然绑定到一台机器的最大可用资源。
五个9:扩展到许多机器
互联网的发展使得企业在规模和复杂性等方面的需求都有所增长,这对数据库来说,则意味着它们需要能够处理比任何单个节点处理的更多流量,并且要能够提供“始终在线”的高可用性。鉴于现在很多工程师都有从事分布式技术的经验,很显然,超越单节点active-passive设置甚至在多台计算机之间分配数据库是完全有可能实现的。
Sharding
首先,也是最容易执行的地方是调整现有内容,工程师通过sharding将Active-Passive复制转换为更具可扩展性的内容。在此方案中,您将集群中的数据按某个值(例如主键中的行数或唯一值)进行拆分,并将这些段分布在多个站点中,每个站点都有一个active - passive。然后可以在集群前添加某种路由技术,以将客户端定向到正确的站点获取其请求。
通过sharding可以在多台计算机之间分配工作负载,提高吞吐量,并通过容忍更多的部分故障来创建更大的弹性。
系统分片优势很多,但其复杂性也给团队带来了巨大的运营负担,计算分片可能会变得非常繁重,以至于路由最终会逐渐渗透到应用程序的业务逻辑中。如果您需要修改系统分片的方式(例如架构更改),通常会带来巨大的工程量。
Single-node Active-Passive系统也提供了事务支持(即使不是很强的一致性),但跨分片协调事务实在是太困难了,因为很多分片系统都彻底放弃了。
Active-Active
鉴于分片数据库难以管理且功能不全,工程师们开始开发至少可以解决其中一个问题的系统。虽然出现的系统仍然不支持交易,但却更容易管理。随着对应用程序正常运行时间的需求增加,帮助团队满足其SLA是一个明智的决定。
这些系统背后的思想是每个站点可以包含集群的一些(或所有)数据并为其提供读写。每当一个节点接收到一个写时,它就会将更改传播到需要它的副本的所有其他节点。为了处理两个节点接收到对同一**的写操作的情况,在提交之前,其他节点的转换被输入冲突解决算法。考虑到每个站点都是“active”,它被称为Active-Active。
因为每个服务器都可以处理其所有数据的读写,所以分片在算法上更容易完成,且部署更容易管理。
在可用性方面,Active-Active非常出色,如果节点失败,客户端只需要重定向到包含数据的另一个节点。只要数据的一个副本是活的,就可以为它服务读写操作。
虽然这种方案非常适合可用性,但其设计基本上与一致性不一致。因为每个站点都可以处理**的写入(并且在故障转移方案中),所以在处理数据时保持数据完全同步非常困难。相反,该方法通常是通过冲突解决算法来调解站点之间的冲突,该算法对如何“平滑”不一致性做出粗粒度的决策。
因为该解决方案是在事后完成的,这时客户端已经收到有关过程的答案,且理论上已经基于响应执行了其他业务逻辑,因此,active-active复制很容易在数据中生成异常。但是,考虑到对正常运行时间的溢价,认为潜在异常的成本大于停机时间的成本,Active-Active成为主要的复制类型。
Scale一致性:Consensus & Multi-Active Availability
Active-Active似乎已经解决了基础设施面临的主要问题-可用性,但它只是通过放弃事务来实现的,这使得需要强一致性的系统没有选择空间。
例如,Google的广告业务使用了一个庞大而复杂的分片MySQL系统,它严重依赖于SQL来任意查询数据库。由于这些查询通常依赖于辅助索引来提高性能,因此它们必须与从它们派生的数据保持完全一致。
当系统变得足够大是,分片MySQL就会出现问题,因此工程师就会开始设想如何解决拥有大规模可伸缩系统也能提供所需的强一致性。Active Active缺乏交易支持意味着它将不会是我们的选择。
使用一致性复制,向节点提出写入,然后将其复制到一定数量的其他节点。一旦大多数节点已经确认写入,就可以提交。
Consensus & High Availability
这里的关键思想是,一致复制是在同步和异步复制之间取平衡,我们需要有任意节点来同步工作,这样我们就可以忍受少数节点能够有性能下降,且不会影响系统可用性。
一致性的代价是需要节点与其他人通信来执行写入,我们可以通过一些措施来减少节点之间的延迟,例如将它们放在相同的可用性区域中,如果所有的节点都在同一个数据中心,通信就会很快,但无法在整个数据中心脱机时继续存在。将节点扩展到多个数据中心可能会增加写入所需的延迟,但可以通过让整个数据中心脱机而不关闭应用程序来提高可用性。
Multi-Active Availability
CockroachDB实现了Google Spanner论文中的大部分知识,包括超出一致性复制的功能,使可用性更加简单。为了描述其工作原理并将其与Active-Active区分开来,我们创造了术语“Multi-Active Availability”。
Active-Active vs. Multi-Active
Active-Active通过让集群中的任何节点为其**进行读写来获得可用性,但仅在提交写之后才将其接受的任何更改传播到其他节点。
另一方面,Multi-Active Availability允许任何节点提供读和写,但是确保大多数副本在写(docs)时保持同步,并且只从最新版本(docs)的复制件进行读取。
在可用性方面,Active-Active只需要一个副本即可用于两个写读取,而Multi-Active需要大多数副本联机以实现一致性(这仍然允许系统内的部分故障)。
这些数据库可用性的下游是一致性的差异。Active-Active数据库在大多数情况下都会接受写操作,但不保证客户端读取数据的能力;而Multi-Active数据库只在保证数据能够以一致的方式读取时才接受写操作。
总结:
目前,业界开发了两种主要的数据库范例:Active-Active主要用于关注快速写入的应用程序,而Active-Active用于需要一致性的应用程序。