ScyllaDB实战——介绍

742 阅读34分钟

本章内容:

  • ScyllaDB及其定义
  • ScyllaDB与其他数据库的比较
  • ScyllaDB如何利用分布式系统的优势

ScyllaDB是一款分布式NoSQL数据库,旨在作为Apache Cassandra的高性能重写版本。尽管它的名字和“哥斯拉”发音相似,并且拥有一个可爱的吉祥物,但它的设计目标是让操作变得不那么“庞大”和复杂。

与关系型数据库相比,ScyllaDB在“大数据库大战”中带来了两大武器:可扩展性容错性。作为一个分布式数据库,ScyllaDB通过运行多个节点来存储和服务数据。这种分布式架构简化了可扩展性;要增加额外的容量,操作员只需要添加更多的节点。通过提供用户调节有多少节点响应查询的能力,ScyllaDB也提供了容错性,因为该系统可以在丧失可配置数量的节点后继续处理请求,如图1.1所示。

image.png

这种分布式设计影响了周围的一切:应用程序的设计、数据查询、数据库监控以及系统在故障期间的恢复方式。我们将探讨这些领域,展示ScyllaDB如何成为任何应用程序的实际分布式数据库。让我们深入了解吧!

1.1 ScyllaDB,一个与众不同的数据库

ScyllaDB是一种数据库——它的名字就表明了这一点!用户向它提供数据,当被请求时,数据库会将数据返回。这种非常基础且过于简化的接口,与流行的关系型数据库(如PostgreSQL和MySQL)并没有太大区别。然而,ScyllaDB并不是一个关系型数据库;它摒弃了连接(joins)和关系数据建模,提供了一组不同的优势。为了说明这些优势,我们来看一个虚拟的例子。

1.1.1 假设数据库

假设你刚刚搬到一个新城市,每次去餐厅时,你都想记住自己吃了什么,以便下次可以再次点它或者避免点它。你可以把自己的订单写在日记本上,或者保存在手机的Notes应用中,但你听说了一种新的商业模式,那就是有些人会记住你发送给他们的信息。你的朋友Robert刚刚开始了类似的生意:Robert’s Rememberings。

ROBERT’S REMEMBERINGS

Robert的生意(如图1.2所示)非常简单:你可以发短信到Robert的电话号码,他会记住你发送给他的任何信息。他还会为你检索信息,这样你就不需要记住在新城市吃过的所有东西。这就是Robert的工作。

image.png

一开始,这个计划运作得非常顺利,但问题开始出现。有一次,你发短信给Robert,他没有回复。后来他道歉说他去看医生了。这个理由不算过分——毕竟你希望你的朋友保持健康。又一次,你发短信告诉他你尝试了新的餐点,结果他花了好几分钟才回复,而不是像平时那样立刻回应。他说生意太火爆了,收到了太多请求——所以回应的时间变慢了。他安慰你说不用担心,他已经有了一个计划(如图1.3所示)。

image.png

Robert雇佣了一个朋友来帮助他,他给你发送了他的系统的新更新规则。如果你只是想问个问题,可以发短信给他的朋友Rosa。所有更新仍然会发送给Robert,他会把你保存的所有内容发给Rosa,这样她就能拥有最新的副本。起初,你不小心继续向Robert提问,但这个系统似乎运行得不错。Robert不再被读请求压得喘不过气来,而Rosa的回复也很及时。

有一天,你意识到,当你向Rosa提问时,她发回的是你之前覆盖过的旧评价。你立刻给Robert发消息,担心你对Main Street Tacos餐厅的评价会永远丢失。Robert告诉你系统出现了问题,导致Rosa没有收到Robert的消息,但她仍然能够接到客户的请求。你的请求并没有丢失,他们正在进行数据对账,尽快同步。

你原本只是想回答一个问题:这家餐厅的食物好不好?现在你却担心是否需要联系不同的人,取决于你是查看评论还是写评论,数据是否同步,以及你朋友的系统是否能扩展以满足所有用户的请求。如果Robert甚至无法处理所有的保存请求会怎样呢?当你开始考虑给自己灌注能量饮料时,你意识到是时候考虑其他选择了。

ABC 数据:另一种方法

你的研究将你引导到另一个公司:ABC Data。公司告诉你他们的系统有些不同:他们有三个人——Alice、Bob和Charlotte——任何人都可以保存信息或回答问题。他们之间会相互沟通,确保每个人都有最新的数据,如图1.4所示。你很好奇,如果其中一个人无法使用,会发生什么情况,公司告诉你,他们提供了一个很酷的功能:因为有多个人,他们之间会进行协调,为你的数据提供冗余和更高的可用性。如果Charlotte不可用,Alice和Bob将会接收请求并进行回答。如果Charlotte之后回来了,Alice和Bob会让她快速了解最新的变动。

image.png

这个设置令人印象深刻,但由于每个请求可能会导致额外的请求,你担心系统可能比Robert的系统更容易被压垮。ABC Data告诉你,这种分布式设计正是它系统的优点。它创建了数据集的多个副本,然后将这些冗余数据分配给员工。如果公司需要扩展,只需要增加额外的员工,他们就可以接管一些现有的数据切片。当假设中的第四个人Diego加入时,某个客户的数据可能会由Alice、Charlotte和Diego共同拥有,而Bob、Charlotte和Diego则可能拥有其他数据。

因为它允许你选择需要多少人来响应内部请求以确保请求成功,ABC Data让你能够控制数据的可用性和准确性(如图1.5所示)。如果你希望始终拥有最新的数据,可以要求所有三个持有者协调一致给你答案。如果你更优先考虑尽快得到答案,即使它不是最新的,你可以要求仅由一个持有者响应,跳过任何内部协调,立即返回答案。你还可以通过要求两个持有者响应来平衡这些属性——这样,你可以容忍一个持有者的丢失,但可以确保大多数持有者都已经看到最新的数据,因此你应该能得到最准确的信息。

image.png

你在这里了解了两个虚拟数据库:一个看似简单,但随着请求的增加引入了复杂性;另一个则实现了更复杂的设计,试图处理第一个系统的缺点。在考虑告诉朋友你要离开他的业务,转投竞争对手之前,让我们回到现实,将这些假设的数据库转化为现实世界中的数据库。

1.1.2 现实世界的数据库

Robert的数据库是一个隐喻,代表像PostgreSQL或MySQL这样的关系型数据库。这些数据库运行起来相对简单,适用于多种用例,性能也不错,其关系型数据模型在实际中已经使用了超过50年。通常,关系型数据库是一个安全且强大的选择。因此,开发人员往往会默认使用这些系统。但正如所示,它们也有缺点。可用性往往是“全有或全无”的。即使你运行了只读副本(在Robert的数据库中是他的朋友Rosa),你也可能仅能在丢失主实例时进行读取。可扩展性也可能很棘手:一个服务器的计算资源和内存是有限的。一旦达到这个限制,你就没有更多空间来扩展。ScyllaDB通过解决这些缺点与众不同。

ABC Data系统就是ScyllaDB。像ABC Data一样,ScyllaDB是一个分布式数据库,它在各个节点之间复制数据,提供可扩展性和容错性。扩展非常简单;通过良好的数据模型,你只需要添加更多节点。这种节点数量的弹性也扩展到查询上。ScyllaDB允许你决定需要多少个副本响应才能成功执行查询,这给你的应用程序提供了处理服务器丢失的余地。

1.1.3 拆解定义

ScyllaDB(非正式地称为Scylla)通常被描述为一个分布式宽列NoSQL数据库,它是流行的Cassandra数据库的重写版本,正如你可能想象的那样,它们共享许多相似的属性。这个定义展示了Scylla如何与其他数据库区分开来。它的目标是比关系型数据库更具可扩展性,并且比Cassandra具有更好的性能。这种定位通常通过将ScyllaDB描述为一个NoSQL数据库来体现。正如其名称所示,PostgreSQL和MySQL被归类为SQL数据库。它们使用SQL(结构化查询语言)来查询关系型数据库模式。而NoSQL已经成为一个笼统的术语,用于描述不符合这种模型的数据库。广泛的数据库种类都可以归类为NoSQL,从ScyllaDB到像MongoDB这样的文档存储,再到像CockroachDB这样的“非单一SQL”数据库。

什么是宽列数据库

ScyllaDB和Cassandra常被称为宽列数据库。在这种类型的数据库中,数据可以被看作是一个多维地图或键值对存储,其中表有列,但不要求每一列都有值。这些表,或者最初在Cassandra中称为列族(Column Families),是一起存储在磁盘上的。这种方法与列式数据库形成对比,后者是将一个给定列的所有值存储在一起。

在列式数据库中,将一个给定列的所有值存储在一起,允许你轻松地对该列中的所有值进行聚合。数据库可以轻松地计算存储数字的列的平均值,因为所有值都被存储在一起并且是共址的,因此它不需要定位并读取数据库中的每一行来聚合这些数据。以下图展示了列式方法如何与宽列数据库不同。

image.png

虽然它们的名称相似,但列式数据库和宽列数据库在存储范式上有显著的不同。ScyllaDB 是一个宽列数据库。

我记得它们的区别是,在 ScyllaDB 和 Cassandra 中,表格——它们现在不再被称为列族——可以是任意宽的。因此,ScyllaDB 是一个宽列存储。表中的行可以分布在整个数据库中——这也是“宽”的另一个例子。我认为“宽列”这个术语是多余的,因此我建议你关注定义的其他部分:ScyllaDB 是一个分布式 NoSQL 数据库,相比其他数据库,它更强调容错性和可扩展性。

NoSQL 数据库通常更强调可扩展性和容错性,而不是数据库中数据的完全正确性和准确性,这个特性被称为一致性。这个权衡在一开始可能听起来很荒谬,但你将在本书中仔细研究这一点。实际上,Scylla 力求最终一致性,随着时间的推移逐渐趋向正确性。为了实现其预期的可扩展性和容错性,ScyllaDB 在集群中运行多个实例。

image.png

没有一个至高无上的领导者,每个节点都和其他节点一样重要。系统中不仅有多个节点,数据还分布在所有这些节点上。ScyllaDB 之所以是一个分布式数据库,并不是因为分布式系统很酷,而是因为它的设计目标是为了构建一个更可靠和可扩展的数据库。如果你将数据分布在集群中的所有节点上,如果丢失一个节点会发生什么呢?ScyllaDB 会存储数据的多个副本,并通过让你选择需要响应查询的副本数,选择少于最大副本数的数量,可以使数据库容忍节点故障。这种分布式架构也有助于可扩展性。如果某个节点承受了大量流量,集群中的其他节点不会受到影响。那些没有命中繁忙节点的请求,不会受到其他节点负载过重的影响。这种容错能力对 ScyllaDB 的设计至关重要。与其把所有的鸡蛋放在一个篮子里,不如把鸡蛋放在多个篮子里。如果丢了一个篮子,你仍然有很多鸡蛋!

1.2 ScyllaDB:一个分布式数据库

ScyllaDB 运行多个节点,使其成为一个分布式系统。通过将数据分布在其部署中,ScyllaDB 实现了其所需的可用性和一致性,而这两者的结合使得该数据库与其他系统区分开来。

1.2.1 数据分布

所有分布式系统都有一个标准:它们必须提供足够的价值,以克服引入的复杂性。ScyllaDB 作为一个分布式系统,通过这种设计实现了其可扩展性和容错性。

当用户将数据写入 ScyllaDB 时,他们首先联系任何一个节点。许多系统采用领导者-跟随者拓扑,其中一个节点被指定为领导者,负责系统中的特定任务。如果领导者死亡,系统会选举一个新的领导者,系统继续运行。

然而,ScyllaDB 并不遵循这种模型;每个节点和其他节点一样重要。没有一个集中式的协调者来决定谁存储什么数据,因此每个节点必须知道任何给定数据应存储的位置。在内部,Scylla 可以通过哈希环来映射给定的行到它所拥有的节点,转发请求到适当的节点,这一点将在第 3 章中讲解。

为了提供容错能力,ScyllaDB 不仅分布数据,还将其复制到多个节点上。数据库将行存储在多个位置——复制的数量取决于配置的复制因子。在理想的情况下,每个节点应该在每次请求时立即响应,但如果它们没有这么做呢?为了应对这种意外的情况,数据库提供了可调一致性。

查询数据的方式取决于你希望获得的 consistency(一致性)级别。ScyllaDB 是一个最终一致性的数据库,在系统趋向一致的过程中,你可能会看到不一致的数据。开发者在使用数据库时,必须时刻记住这一点。为了适应不同的一致性需求,ScyllaDB 提供了多种一致性级别,包括表 1.1 中列出的选项。

表 1.1 一致性级别选项示例(假设集群有三个副本)

一致性级别描述成功所需的副本数量可容忍的失败数量
ALL要求所有副本成功30
QUORUM要求大多数副本成功21
ONE要求至少一个副本成功12

在使用 ALL 一致性级别时,您可以要求所有副本确认一个查询,但这种设置会影响可用性。此时,您将无法容忍节点的丢失。使用 ONE 一致性级别时,您只需要一个副本确认查询,但这会大大增加结果不一致的可能性。

幸运的是,ScyllaDB 提供了更灵活的选项。ScyllaDB 通过 Quorum(法定人数)的概念来调整一致性。法定人数是一个组中大多数成员的集合。例如,美国参议院在成员人数低于法定人数时无法进行操作。将这一概念应用到 ScyllaDB 时,您可以实现一致性级别的中间状态。

QUORUM 一致性级别下,数据库要求大多数副本确认查询。如果您有三个副本,则其中两个副本必须接受每个读写请求。如果丢失一个节点,仍然可以依赖其他两个副本继续提供服务。此外,您还可以确保大多数节点获取到每次更新,这样就可以避免读取不一致的数据。

一旦选择了您的一致性级别,您就知道需要多少个副本来执行成功的查询。客户端发送请求到一个节点,这个节点作为该查询的协调者。协调节点将请求转发给指定键的副本,包括它自己(如果它是副本的话)。这些副本将结果返回给协调节点,协调节点根据一致性要求对结果进行评估。如果结果满足一致性要求,它会将结果返回给调用者。

CAP 定理(<www.scylladb.com/glossary/ca… 1.7 所示)。对于 CAP 定理,我们将一致性定义为每个请求读取到最新的写入数据;它是数据库中正确性的度量。可用性指系统是否能够处理请求,网络分区容忍性指的是系统能够处理一个节点离线的情况。

image.png

根据 CAP 定理,分布式系统必须具备网络分区容忍性,因此它最终需要在一致性和可用性之间做出选择。如果一个系统是一致的,那么它就必须保证不会读取到不一致的数据。为了实现一致性,必须确保所有节点都接收到所有必要的数据副本。这一要求意味着系统无法容忍节点的丢失,从而失去可用性。

:实际上,系统并不像 CAP 定理所暗示的那样严格分类。对于这些属性的更细致讨论,可以参考 PACELC 定理(www.scylladb.com/glossary/pa…),它阐述了系统如何在延迟和一致性之间做部分权衡。

ScyllaDB 通常被分类为 AP 系统。当遇到网络分区时,它选择牺牲一致性以维持可用性。你可以从其设计中看到这一点:ScyllaDB 通过使用法定人数(quorum)和最终一致性来不断做出选择,以保持系统的运行,同时可能会牺牲一致性。在它强调可用性的同时,你可以看到 ScyllaDB 与最受欢迎的竞争对手——关系型数据库——之间的差异。

1.2.2 ScyllaDB 与关系型数据库的比较

我在介绍 ScyllaDB 时,已通过与关系型数据库的对比描述了它的特性,接下来我们将更详细地探讨这些差异。关系型数据库,如 PostgreSQL 和 MySQL,是软件应用程序中数据存储的标准,它们几乎总是新开发者在构建应用时的默认选择。关系型数据库在许多使用场景中是一个非常强大的选项,但这并不意味着它们适合所有的使用场景。

ScyllaDB 是一个分布式 NoSQL 数据库。通过将数据分布到集群中,ScyllaDB 比单节点的关系型数据库在节点发生故障时提供更好的可用性。尽管 PostgreSQL 和 MySQL 可以通过扩展或更新的存储引擎来运行分布式模式,但它们并非数据库的主要本地模式。而 ScyllaDB 的分布式特性是它设计的基石。

通过作为分布式系统运行,ScyllaDB 实现了水平扩展。许多关系型数据库只有垂直扩展能力——你只能通过将数据库运行在更大的服务器上来增加资源。而水平扩展使得你可以通过向系统添加节点来增加其容量。ScyllaDB 支持这种扩展;管理员可以添加更多的节点,集群会自动重新平衡数据,转移到新的集群成员。在关系型数据库中,水平扩展虽然也是可能的,但通常需要手动操作。操作员需要手动将数据分片到多个节点上,以实现这种行为。

ScyllaDB 不提供关系型数据库的 ACID(原子性、一致性、隔离性和持久性)保证,而是采用了一种更灵活的模型,称为 BASE(基本可用性、软状态和最终一致性),其中数据库具有基本的可用性,并且最终会实现一致性。这一决策使得写入速度比关系型数据库更快,因为后者每次写入后都需要验证数据库的一致性;而 ScyllaDB 只需要保存写入数据,因为它并不承诺达到那种程度的正确性。这个权衡是,开发者需要考虑 ScyllaDB 的较弱一致性。

ACID 与 BASE

ACID 为事务提供了一组保证。一个事务是对数据库应用的一个或多个语句。当开发者提到数据库中的事务时,他们几乎总是指 ACID 事务。ACID 提供了以下保证:

  • 原子性:事务中的所有语句要么一起成功,要么一起失败。
  • 一致性:每次事务后,数据库都处于有效状态。
  • 隔离性:一个事务不能干扰并发执行的事务。
  • 持久性:事务中的任何更改都会持久化。

我倾向于将 ACID 理解为你期望数据库运行的方式。你希望数据库保持一致,并且希望写入操作是持久的。如果你向数据库写入数据,它没有持久化,那将让人失望。

ScyllaDB 提供了一组较为宽松的保证,称为 BASE。宽松并不代表不好;这些保证使得 ScyllaDB 更容易提供可扩展性和容错性。BASE 提供了以下保证:

  • 基本可用性:数据库基本上是可用的。部分数据库可能处于不可用状态,但总体系统仍然可用。
  • 软状态:数据库中的每个节点不必始终保持一致。
  • 最终一致性:数据库在一段时间后会趋向一致性。

虽然我依然认为 BASE 的设计者使用“软状态”这一术语是为了让缩写更合适,但它确实准确地描述了 ScyllaDB 的优点。它能够容忍节点的丢失并保持可用性,但为此必须放宽一致性。然而,它应该努力并逐渐趋向一致性。在接下来的章节中,我们将讨论这些属性,它们如何影响 ScyllaDB 及其使用方式,以及系统架构如何提供这些属性。

最终,ScyllaDB 与关系型数据库的选择是一个基础性和哲学性的问题。它们的运作方式截然不同,并且为客户端提供了各自不同的保证,因此选择其中一个将对应用程序产生重大影响。如果你在数据库中寻求可用性和可扩展性,ScyllaDB 是一个强有力的选择。

1.2.3 ScyllaDB 与 Cassandra 的比较

ScyllaDB 是 Apache Cassandra 的重写版本。它常常被描述为“性能更好的 Cassandra”或“Cassandra,但使用 C++ 实现”。ScyllaDB 设计上与 Cassandra 兼容:它使用兼容的 API、查询语言、磁盘存储格式以及哈希环架构。“像 Cassandra,但更好”是 ScyllaDB 的目标;为了实现这一目标,它做了一些改进。

重写时选择的语言立即提升了性能。Cassandra 是用 Java 编写的,Java 使用垃圾回收器来进行内存管理。由于对象被加载到内存中,某个时刻它们需要被移除。Java 的垃圾回收算法负责这一移除过程,但这会消耗计算资源。垃圾回收所花费的时间是 Cassandra 无法用来执行查询的时间。如果垃圾回收达到了某个阈值,Java 虚拟机会暂停所有执行,进行内存清理,这一过程被称为“停止世界”暂停。即便只是暂停几毫秒,这种暂停对客户端而言也是痛苦的。尽管 Java 提供了许多配置选项并随着每个版本优化垃圾回收器,但这依然是所有 Java 应用必须承担的成本——无论是垃圾回收时间,还是为了减轻这种影响而额外耗费的时间。

ScyllaDB 避免了这一成本,因为它是用 C++ 实现的,提供了更精细的内存管理控制。通过完全控制内存分配和清理,ScyllaDB 不需要依赖垃圾回收器在整个应用层面进行此功能。它避免了“停止世界”暂停,并能够将计算时间专注于执行查询。

ScyllaDB 的最大架构差异在于它的 每核心分片架构(见图 1.8)。Cassandra 和 ScyllaDB 都通过哈希环将数据集分片到多个节点上,稍后在第 3 章你将了解更多关于哈希环的内容。ScyllaDB 更进一步,使用 Seastar 框架(seastar.io)将数据在节点内部进行分片,按 CPU 核心划分,为每个分片分配独立的 CPU、内存和网络带宽。

image.png

这种分片进一步限制了由于热流量模式造成的损害范围——损害仅限于该节点上的那个分片。然而,Cassandra 并没有遵循这种范式,它只对每个节点进行分片。如果一个数据分区接收到大量请求,这些请求可能会压垮节点,导致整个集群出现问题。

性能证明了重写的合理性。无论是在基准测试中(请参见《基准测试:Apache Cassandra(40 个节点) vs. ScyllaDB(4 个节点)》),还是在实际使用中(请参见《Discord 如何存储数万亿条消息》),ScyllaDB 的性能更好、更一致,并且比 Cassandra 需要更少的服务器来运行。

1.2.4 ScyllaDB 与 Amazon Aurora、Amazon DynamoDB、Google Cloud Spanner 和 Google AlloyDB 的比较

这里我将几种相似的系统放在一起讨论:Amazon Aurora、Amazon DynamoDB、Google Cloud Spanner 和 Google AlloyDB。它们通常可以描述为可扩展的云托管数据库。它们的目标是使用关系数据模型,并提供比开箱即用的 PostgreSQL 或 MySQL 更高的可扩展性。这种努力突显了市场上对可扩展数据库的需求,展示了 ScyllaDB 的价值。

这些系统有两个相关的缺点:云供应商的锁定和成本。由于这些数据库是由云供应商提供的,它们只能在特定供应商的云环境中运行。你不能在亚马逊 AWS 上运行 Google Cloud Spanner。如果你的应用程序严重依赖这些系统,当你决定切换云供应商时,可能会面临很高的工程成本,因为你需要将数据迁移到另一个可能具有不同存储范式的系统中。

如果你不使用该供应商(或任何供应商),这些选项对你来说根本不可用。而且,使用云供应商时,公司需要为这些服务支付费用。运营和维护一个数据库是具有挑战性的(这也是你阅读本书的部分原因),尽管这些云供应商提供了解决方案,可能让操作变得更简单,但这对客户来说可能是昂贵的。当然,自行运营数据库也可能会很昂贵。

然而,ScyllaDB 可以在任何地方运行。公司可以将其部署在本地,或在不同的云供应商平台上运行。它提供了一个可扩展且具备容错能力的数据库,可以在任何托管解决方案中使用。

1.2.5 ScyllaDB 与文档存储系统的比较

这里讨论的不是 Google Drive,而是通过给定的键存储非结构化文档的数据库,比如 MongoDB。这些系统支持对这些文档进行查询,允许用户在不定义数据库架构的情况下访问任意文档字段。

ScyllaDB 避免了这种灵活性,而是提供(相对)可预测的性能。通过要求用户在前期定义架构,ScyllaDB 明确了数据如何在集群中分布,便于用户和系统理解数据分布的方式。通过强制用户按照与数据分布匹配的模式查询数据,ScyllaDB 能够限制查询中涉及的节点数量,防止出现意外昂贵的查询。

另一方面,文档存储系统往往偏向于最初的易用性。在 MongoDB 中,不需要定义架构,但用户仍然需要考虑数据设计,以便有效地查询它。MongoDB 作为分布式系统运行,但与 ScyllaDB 不同的是,它在默认情况下不会尽量避免效率低下的查询,这些查询可能会涉及比预期更多的节点,导致潜在的性能问题。

在 CAP 定理中,MongoDB 是一个 CP(强一致性和分区容忍)系统。写入操作需要主节点的存在,并且在发生网络分区时,写入操作会被阻塞,直到选举出一个新的主节点。然而,ScyllaDB 在查询路径中优先考虑可用性,保持系统的正常运行,并依赖其可调的一致性。

1.2.6 ScyllaDB 与分布式关系数据库的比较

过去几年,数据库领域的一个有趣发展是分布式事务性数据库的兴起。这些系统——如 CockroachDB、TiDB 和 YugabyteDB——专注于提高传统关系数据库(如 PostgreSQL)的可用性,同时仍然提供强一致性。在 CAP 定理的分类中,它们是 CP 系统;它们更倾向于一致性,而非可用性。通过强调正确性,它们需要节点的法定人数来响应,以成功完成查询;如果法定人数丧失,数据库将失去可用性。而 ScyllaDB 提供了可调一致性来避免这个问题。通过允许较弱的一致性级别(例如 ONE),Scylla 可以在保持功能性的同时处理更大的可用性丧失。

在关系数据库中,写操作是一项计算密集型操作。数据库需要在每次写入时验证一致性。另一方面,Scylla 跳过了这一验证,选择在写入数据时追求速度和简便性。然而,这种取舍的代价是,在 Scylla 中,读取操作将比写入操作更慢,因为你需要从多个节点中收集数据,而这些数据存储在磁盘上的不同位置。你将在第 6 章和第 7 章中学到更多关于这种行为的内容,但重要的结论是,Scylla 中的写操作会比这些系统中的写操作更快。

1.2.7 何时应选择其他数据库

我已经描述了 ScyllaDB 相对于其他数据库的优势,但有时候,坦白说,它并不是最佳的选择。由于采用了 Cassandra 重写的方法,我不能将它描述为一个独特的数据库,但它确实通过增加操作和设计的复杂性来换取更优雅的故障处理方式。选择 ScyllaDB 需要你以不同的方式设计应用程序,因为它有特定的数据建模需求,必须最好地利用其能力,并且增加了比云托管的 PostgreSQL 服务器更多的复杂性。如果你不需要 ScyllaDB 的水平扩展性和精细的可用性,那么增加的操作开销可能不值得。如果你的应用程序很小,请求较少,并且不打算随时间增长,那么 ScyllaDB 可能会显得过于复杂。比如,博客上的评论数据库大概并不需要 ScyllaDB 集群,除非像我们许多人一样,你想用它作为一个尝试的借口。

操作和维护一个 ScyllaDB 集群并非是一个放手不管的工作。如果你无法投入时间去操作和维护集群,这可能是另一个信号,表明你可能更倾向于选择托管服务。团队必须明智地选择如何花费时间和金钱在他们所做的事情上;选择一个操作更少的方案也是一个合理的决定。

在接下来的章节中,你会看到关于 ScyllaDB 的一个特点,那就是它在数据建模方面可能对数据库设计的更改不够灵活。增加不符合初始设计的新查询模式可能会变得具有挑战性。虽然有一些方法可以绕过这些问题,但其他数据库可能在你处于原型设计和学习阶段时,能为你提供更多的灵活性。

最后,一些使用场景可能更倾向于使用更强的事务模型,比如 ACID。如果你处理的是金融数据,可能会希望使用关系数据库,以便在操作中实现隔离。一个常见的示例是并发访问银行账户。如果没有隔离,可能会发生并发操作导致数据库认为你账户中的金额与实际金额不符。会计师通常更倾向于在这些领域确保准确性,因此当处理需要更强数据库事务的应用时,可能会更倾向于使用关系数据库。尽管扩展关系数据库也有挑战,但处理这些挑战可能比放弃 ACID 的保证更可取。通过仔细设计和使用一些更高级的功能(你将在第 6 章中学到),ScyllaDB 可以更接近 ACID,但这不像关系数据库那样是“开箱即用”的体验。

1.3 ScyllaDB,实用的数据库

我们已经讨论了 ScyllaDB 到底是什么,它与其他系统有何不同,但它在实际应用中表现如何呢?在本节中,我们将把它作为一个实际部署的系统来探讨,展示 ScyllaDB 不仅是一个分布式数据库,还是一个实用的数据库。

1.3.1 故障容忍

如果你负责数据库的运维,你希望它能够优雅地处理故障,这样你就能避免凌晨 3:00 的警报,安稳地睡个好觉。ScyllaDB 被设计为一个容错的数据库,让你能安心休息。通过其可调一致性模型,ScyllaDB 可以在没有任何查询影响的情况下度过突发的宕机时间。采用仲裁一致性,意味着并不是每个节点都需要保持运行才能处理流量。如果服务器崩溃了,而底层硬件能够自我恢复,ScyllaDB 进程可以重新启动,重新加入集群,接收它错过的数据,然后继续服务流量,整个过程你都可以安睡,不知情。

如果由于某些不幸的原因,一个节点无法恢复,你也不需要执行像从备份中恢复那样复杂的操作。你只需要为集群配置一个新的节点,并告诉集群这个新节点将替代旧节点。由于 ScyllaDB 在集群中复制数据,你的新节点就会替代旧节点,其他副本会向它流式传输数据,直到该节点赶上进度并加入集群,恢复提供服务。

1.3.2 扩展性

如果你已经达到了现有数据存储的极限,或者处理增长对你很重要,扩展性就是人们选择 ScyllaDB 的主要原因之一。幸运的是,在 ScyllaDB 中,扩展性通常是简单直接的——在设计良好的集群中,你只需要添加更多的节点!即使是处理数 TB 的数据,添加一个节点也应该不会超过几个小时。

注:对不起,蜘蛛侠,更多节点带来更多责任。升级到新的 Scylla 版本或推出操作系统补丁意味着你需要更新所有节点,如果节点数量很多,这可能是一个耗时的操作。

类似于替换集群中的节点,添加节点的过程包括将新节点加入集群,注册该节点将拥有的数据片段,然后从其他副本接收数据,直到该节点的数据同步完成。虽然这个引导过程一次只限于一个节点,但它是一个简单易执行的操作。

1.3.3 生产使用

软件开发人员通常在选择数据存储时持保守态度,原因也很充分:数据库是所有数据的基础。一个数据库可能满足所有需求,但作为唯一运行该系统的人,还是有些令人担心。作为一个领域,软件开发的进步是在更多的人使用软件的过程中实现的,他们发现 bug,并找到解决方案。当考虑一些不太常见的解决方案时,你常常会听到一个大问题:“真的有人在使用这个吗?”

答案是:有的!ScyllaDB 是一个被实际用于生产系统的数据库,且正在逐渐受到越来越多的青睐。今天,已有多家公司在使用它:

  • Discord 将他们的万亿条消息存储在 ScyllaDB 中。
  • Epic Games 使用 ScyllaDB 作为二进制资源的缓存。
  • Comcast 将其 X1 有线电视平台的 DVR 数据存储在 ScyllaDB 中。

他们构建的系统使用 ScyllaDB,因为他们需要一个可扩展且容错的数据库。这些用例涉及高度分布式的读取操作,支持他们系统中的重要功能。

作为这本书的读者,你可能正在考虑使用 ScyllaDB 来构建类似的系统。我的目标是通过本书的学习,你能够掌握如何结构化模式、查询数据库并进行操作,最终能够自行构建系统。我已经花了很多时间介绍 ScyllaDB,现在我们来深入了解如何查询这个数据库吧!

总结

ScyllaDB 是一个分布式 NoSQL 数据库,兼容 Apache Cassandra 的 API,通过将数据分布在多个节点上,提供了可扩展性和容错性。

与关系型数据库相比,Scylla 允许通过增加节点来扩展数据库。

为了应对节点丢失的情况,Scylla 允许你调节需要在线的节点数量,以便平衡正确性和可用性。

ScyllaDB 更加侧重于可扩展性和容错性,而不是一致性——即数据库的完全正确性和准确性。它偏向最终一致性,随着时间的推移逐步收敛于正确性。

  • ALL 一致性级别要求每个节点都响应请求;
  • ONE 一致性级别只要求一个节点响应;
  • QUORUM 一致性级别要求大多数节点响应,以此平衡一致性和可用性。

根据 CAP 定理,分布式系统必须在一致性、可用性和分区容忍性之间做出权衡。ScyllaDB 被归类为可用且容忍分区的系统,牺牲了一致性。

Scylla 的水平扩展性——通过增加节点——与关系型数据库的单节点扩展方式相对立,后者通常只能通过添加额外资源进行垂直扩展。

与关系型数据库的 ACID(原子性、一致性、隔离性、持久性)保证不同,Scylla 提供了 BASE 保证:基本可用性、软状态和最终一致性。

ScyllaDB 是对 Cassandra 的重写,采用了非内存管理语言,并通过进一步分片数据集,在每个 CPU 核心上分配一个节点,从而扩展了 Cassandra 的复制功能。

当节点崩溃时,Scylla 会自我修复,通过从其他节点流式传输数据来帮助集群恢复。

今天,Scylla 已被许多公司投入生产使用;它是一个经过验证的存储解决方案。