一个成功的技术,可行性的优先级必须高于PR,你可以糊弄别人,但糊弄不了自然规律。
——罗杰斯委员会报告(1986)
在本书的第一部分中,我们讨论了数据存储在一台机器上数据系统的方方面面。现在到了第二部分中,我们提一个更高级的问题:如果多台机器参与数据的存储和检索会发生什么? 将数据库分布到多台机器上可能会有很多原因:
可扩展性
如果您的数据量读取负载/写入负载比单台计算机可以处理的还要大,则可以将负载分散到多台计算机上。
容错/高可用性
如果即使一台机器(或多台机器,网络或整个数据中心)出现故障,您的应用程序仍然需要继续工作,您可以使用多台机器来提供冗余。当一台故障时,另一台可以接管。
延迟
如果在世界各地都有用户,也许你会考虑在全球多处部署服务器,既而每个用户从地理上相近的数据中心获取服务,以免用户需要等待网络数据包穿越半个世界。
如果只是需要扩展到支持更高的负载,最简单的方法就是购买更强大的机器(有时称为垂直扩展 vertical scaling或scaling up)。许多CPU、RAM芯片和磁盘可以在一个操作系统内相互连接,快速互连允许任何CPU访问存储器或磁盘的任何部分。在这种共享内存架构中,所有的组件都可以看作是一台单独的机器(在大型机中,尽管任何CPU都可以访问内存的任何部分,但是总有一些内存区域与一些CPU更接近1。 为了有效地利用这种架构特性,需要对处理进行细分,以便每个CPU主要访问临近的内存,这意味着底层仍然进行了分区,即使表面上看起来只有一台机器在运行)
共享内存方法的问题在于,开销的增长速度快于线性增长:一台机器的CPU数量翻倍,内存大小也翻倍,磁盘大小翻倍,但成本通常多的可不止一倍。而且由于瓶颈存在,一台双倍规格机器不一定能处理双倍的负载。
共享内存体系结构可以提供有限的容错能力,相比之下,使用高端机器虽然具有热插拔组件(可以不关机更换磁盘,内存模块,甚至CPU),但是它必然局限于单个地理位置。
另一种方法是共享磁盘架构,它使用多台具有独立CPU和RAM的机器,但将数据存储在机器之间共享的磁盘阵列上,这些磁盘通过快速网络连接(Network Attached Storage, Storage Area Network)。此架构用于某些数据仓储,但竞争和锁定的开销限制了共享磁盘方法的可扩展性[2]。
相比之下,无共享架构(shared-nothing 有时称为水平扩展 horizontal scaling 或 scaling out)已经相当普及。在这种架构中,运行数据库软件的每台机器/虚拟机都称为节点(node)。每个节点只使用各自的CPU,内存和磁盘。节点之间的任何协调都是在软件层面使用传统网络实现的。
无共享系统不需要特殊的硬件,所以你可以用任何性价比最好的机器。也许可以跨多个地理区域分发数据从而减少用户延迟,也许可以在整个数据中心丢失的情况下幸免于难。随着云端虚拟机部署的出现,即使是小公司,现在无需Google级别的运维,也可以实现多地分布式架构。
在这一部分里,我们将重点放在无共享架构上,并不是因为它们一定是每个用例的最佳选择,而是因为它们要求应用程序开发人员最为谨慎。如果你的数据分布在多个节点上,你需要意识到这样一个分布式系统中约束和权衡 ——数据库并不能神奇地把这些东西藏起来。
虽然分布式无共享架构具有许多优点,但它通常也会给应用程序带来额外的复杂性,有时也会限制您可以使用的数据模型表现力。在某些情况下,一个简单的单线程程序可以比一个拥有100多个CPU核心的集群表现得更好[4]。另一方面,无共享系统可以非常强大。接下来的几章将详细讨论分布式数据的问题。
数据分布在多个节点上有两种常见的方式:
-
复制(Replication)
在几个不同的节点上保存相同数据的副本,可能位于不同的位置。 复制提供了冗余:如果某些节点不可用,则仍然可以从其余节点提供数据。 复制也可以帮助提高性能。
第五章将讨论复制。
-
分区 (Partitioning)
将大型数据库拆分成称为分区的较小子集,以便不同的分区可以指派:给不同的节点(也称为分片 sharding)。
第六章将讨论分区。
复制和分区是不同的机制,但它们经常同时使用。如图II-1所示。
图II-1 复制与分区
理解了这些概念,就可以开始讨论在分布式系统中需要做出的困难抉择。
第七章将讨论事务(Transaction),这对了解数据系统中可能出现的所有问题以及可以做些什么很有帮助。
在本书的第三部分中,将讨论如何将多个(可能分布的)数据存储集成到一个更大的系统中,以满足复杂应用程序的需求。 但首先我们来谈谈分布式的数据。
Footnotes
-
称为非均匀内存访问 nonuniform memory access,或者NUMA ↩