译者:崔英峰
电脑可以没日没夜的运行,但是以前的网站是不能24*7小时运行的。现在看来,我们都不可思议。但是,在互联网出现之前,24*7高可用是不存在的。
那时候我们期待可用性,但是我们觉得这不是我们有权利要求的。我们只在需要的时候使用电脑;更多的时候,我们没有机会使用它。自然,我们很少让电脑一直开着,这样它就可以随时回应我们。随着互联网的发展,以前在当地时间凌晨3点不常见的请求越来越多,这个时间段也变成了全世界的黄金营业时间。因此,确保计算机能够满足这些要求是非常重要的。
然而,许多系统只依赖一台计算机来处理这些请求——单点故障——我们都知道这是一个不好的事实。为了保持正常运行,我们需要将负载分布在多台能够满足我们需求的计算机上。然而,分布式计算有明显的优势:特别是,它可以同步和容忍系统中的一些故障。每一代工程师都在迭代这些解决方案,以满足这个时代的需求。
很多人不知道数据库是如何引入分布式领域的前因后果,因为这是一个比其他领域发展慢得多的难题。当然,软件会在本地数据库中记录一些分布式计算结果,但数据库本身的状态只能保存在单台机器上。为什么?因为跨机器状态复制非常困难。
在本文中,我们来看看分布式数据库在历史上是如何处理容错的,以及高可用性是什么样子的。此外,我们将介绍几种不同类型的高可用性系统。
高可用性数据库有哪些类型?
一般来说,高可用性数据库可以分为两类。目前,第三类出现了,而且越来越普遍:
主从式数据库:数据库有一个主节点处理请求,另一个是热备节点,一旦主节点出现故障就会投入使用;
Master-master数据库:数据库有多个主节点,分别对数据进行切片和写入数据库;
多主数据库:数据库至少有三个主节点,可以读写集群中的任意数据,不会发生冲突。
什么是主从可用性?
主从可用性是指数据库有一个主节点处理请求,另一个主节点是热备用节点,一旦主节点出现故障,就会投入使用。主从可用性模型基于两个节点的概念,即一个节点接收所有请求,然后将数据复制到其追随者。
过去,数据库运行在一台机器上。它只有一个节点,处理所有读写操作。没有所谓的“部分失败”;数据库成功启动或未能停止服务。
对于互联网来说,单节点数据库完全不可用是双重问题;第一,电脑无时无刻不在被访问,所以宕机更容易直接影响用户;其次,通过将计算机置于持续的访问请求下,它们更有可能失败。显然,解决这个问题的方法是使用多台计算机共同处理请求,这也是分布式数据库的出发点。
生活在单节点的世界里,最自然的解决方案就是继续让单个节点提供读写服务,简单地将其状态同步到一个辅助备份机上——于是,主从复制就诞生了。
主从模式是通过即时备份实现高可用性的早期步骤。在主节点出现故障的情况下,您可以简单地将流量定向到从节点,从而将其提升到主节点。只要有可能,您将使用新的备份机器替换关闭的服务器。
首先,从主节点到从节点的复制是一个同步的过程,也就是在从节点确认后才会提交数据转换。但是,如果从节点出现故障,该怎么办还不清楚。如果备份系统不可用,整个系统宕机当然没有意义——但是只要使用同步复制,这种情况就会发生。
为了进一步提高可用性,您可以改为异步复制数据。虽然它的体系结构看起来相同,但它可以处理主节点或从节点的停机时间,而不会影响数据库的可用性。
尽管异步主从模式又向前迈进了一步,但仍有明显的缺点:
当主节点关闭时,任何没有复制到从节点的数据都可能会丢失——即使客户端已经确认了数据的完整提交。
依靠单台机器来处理流量仍然受到单台机器的最大可用资源的限制。
追求“五个9”的高可用性
扩展到多台机器
随着互联网的普及,业务需求的规模和复杂程度越来越高。对于数据库来说,这意味着它们需要能够处理比任何单个节点更多的流量,并且提供“始终在线”的高可用性成为一项任务。
现在大量的工程师都有了其他分布式技术的经验,显然数据库可以超越单节点主从模式,将数据库分布在多台机器上。
分成几部分
类似地,我们可以从调整现有系统开始,我们的工程师通过开发碎片将活动复制调整为更具可扩展性的架构。
在这个场景中,您按照某个值分割集群数据,并将这些数据段分布在多个实例中,每个实例都有一组主节点和从节点。然后,在由这些实例组成的集群前面添加一些路由技术,将客户机请求引导到正确的实例进行处理。
切片允许您将工作负载分布到多台机器上,从而通过容忍更多的部分故障和消除单点故障来提高吞吐量和创造更大的灵活性。
尽管有这些优势,但是对系统进行碎片化是很复杂的,给团队带来了巨大的运维负担。对片段的刻意统计可能会变得非常乏味,以至于路由最终会渗透到应用程序的业务逻辑中。更糟糕的是,如果需要修改系统碎片化的方式,通常需要明显的工程量才能实现。
单节点主从系统也提供事务支持。然而,跨碎片协调事务的困难是如此琐碎和复杂,以至于许多碎片系统决定完全放弃它们。
什么是主可用性?
主可用性意味着数据库至少有两个主节点,它们对数据进行切片并写入数据库。主设备的可用性代表了从主设备到从设备的演变。通过让集群中的节点提供读写服务,数据库可以扩展到单台机器之外。
考虑到碎片化的数据库难以管理且功能不全,工程师们开始开发一种至少可以解决其中一个问题的系统。这个时候,有一个系统仍然不支持事务,但是非常容易管理。随着对应用程序正常运行时间需求的增加,帮助团队满足其SLA是明智的。
这些系统背后的动机是每个实例节点可以包含集群的一些数据,并为其提供读写服务。每当一个节点接收到写请求时,它会将更改传播到需要其副本的所有其他节点。为了处理两个节点写入相同键值的情况,任何一个节点的转换在提交之前都将被发送到冲突解决算法中。由于每个站点都是“活动的”,因此被称为所有者。
因为每台服务器都可以读取和写入其所有数据,所以分段在算法上更容易实现,并且使部署更容易管理。
从可用性来说,车主是优秀的。如果一个节点出现故障,客户端只需重定向到另一个包含数据的节点。只要数据的单个拷贝处于活动状态,就可以为其提供读写服务。
尽管该方案在高可用性方面非常出色,但其设计在一致性和数据正确性方面存在根本性问题。因为每个实例节点都可以处理键值的写入,所以它在处理数据时很难保持数据完全同步。在这种方案中,实例之间的冲突通常由冲突解决算法来调解,如何“消除”不一致的决策是粗粒度的。
因为解决方案是事后完成的,在客户端收到程序的响应之后——理论上已经根据响应执行了其他业务逻辑——主-主复制很容易在数据中产生异常。
然而,考虑到正常运行时间的溢价,停机成本被认为大于潜在的非正常成本,因此所有者成为复制的主要类型。
大规模正确性
共识和活力可用性
Lord似乎解决了基础设施面临的主要问题——提供高可用性。但它只是通过放弃事务来做到这一点,这使得系统在满足强一致性的要求方面不太可靠。
比如Google在广告业务中使用了庞大复杂的MySQL碎片化系统,非常依赖SQL的表达能力任意查询数据库。因为这些查询通常依赖辅助索引来提高性能,所以它们必须与它们派生的数据完全一致。
最终,系统变得足够大,导致碎片化的MySQL出现问题,工程师们开始想象如何解决这样的问题:大规模的可扩展系统和业务所需的强一致性。Master缺乏事务支持意味着它不应该是一个选项,所以他们必须设计一些新的东西。最终,他们用这样一个系统解决了问题,这个系统基于共识复制,可以保证一致性,提供高可用性。
使用一致复制,写入被提议到一个节点,然后被复制到一些其他节点。一旦大多数节点确认写入,它们就可以提交。
共识和高可用性
这里的关键概念是一致复制是同步和异步复制之间的一种机制:您可以指定任意数量的节点进行同步,但这些节点是哪些并不重要。这意味着集群可以容忍少数节点停机,而不会影响系统的可用性。
然而,共识的代价是,它需要节点与其他节点通信来执行写入。虽然可以采取一些措施来减少节点之间的延迟,比如把它们放在同一个可用区域,但是这需要和高可用性进行权衡。
举个例子,如果所有节点都在同一个数据中心,那么它们之间的通信速度是非常快的,但是如果整个数据中心都离线,你的服务就不是一个人住了。将节点分散到多个数据中心可能会增加写入所需的延迟,但可以提高可用性。即使整个数据中心离线,您的应用程序仍将在线。
什么是多主可用性?
多可用性要求数据库至少有三个活动节点,并且每个活动节点可以无冲突地读写集群中的任何数据。
CockroachDB实现了Google Spanner论文的大部分内容,包括那些超越共识复制的特性,这些特性使得易用性更容易。为了描述它的工作原理并将其与主-主相区别,我们创造了术语多主可用性。
主对多主
主节点通过允许集群中的任何节点为其键值提供读写服务来实现可用性,但只有在提交写入后,其接受的更改才会传播到其他节点。
另一方面,多主可用性允许任何节点提供读写服务,但保证大多数副本在写入时是同步的,只提供从最新版本副本的读取服务。
在高可用性方面,拥有者只需要一个副本同时读写,而多拥有者需要大部分副本在线才能达成共识。
显然,这些数据库在可用性方面的不同表现是由于系统对一致性处理的不同。主数据库在大多数情况下会努力写数据,但是不能保证客户端现在或将来可以读取数据。但是,多主数据库仅在能够保证数据在未来以一致的方式被读取时才接受写入。
回顾与展望
在过去的30年里,数据库复制和可用性有了很大的进步,现在已经支持全球部署。感觉他们永远不会不受欢迎。这方面的第一次尝试通过主从复制奠定了重要的基础,但最终还需要更好的可用性和更大的规模。
在这一领域,业界开发了两种主要类型的数据库:主从式用于满足那些主要关注快速写入的应用,多主式则服务于那些需要一致性的应用。
我们都期待有一天可以利用量子纠缠,转向下一代数据库类型:可管理的分布式数据库。