很可能,您从未认真思考过构建自己的数据库需要什么。而且您可能永远不会发现自己需要这样做。
但是,即使只是作为一个思想实验,也请考虑一下:如果作为一项核心业务需求,您发现需要为来自断开连接的操作的数据捕获提供支持,以便更新可能由不同的方在同一时间或重叠的时间内进行,而不会发生冲突,该怎么办?如果您的服务要求您几乎全天候持续接收大量数据,以至于您真的无法承受在任何时候中断数据摄取,以免发现自己落后于当前状态太远,以至于几乎无法追赶,又该怎么办? 考虑到这一切,是否有任何商业上可用的数据库可以用来满足这些要求?
没错。那么,这会让你陷入何种境地?那时你会怎么做?我们想与 Theo Schlossnagle 探讨这些问题,他实际上构建了自己的时序数据库。作为 Circonus 的创始人兼首席技术官,该组织对已经庞大且呈指数级增长的物联网(Internet of Things)设备数量进行遥测分析,Schlossnagle 有充分的理由进行这项投资。
Akamai 全球性能和运营首席架构师 Justin Sheehy 向 Schlossnagle 询问了这项工作背后的思考,以及在构建数据库过程中做出的一些关键决策,以及在此过程中学到的一些经验。代表 ,AWS(亚马逊网络服务)的高级应用科学家 Chris McCubbin 也参与了讨论。
JUSTIN SHEEHY 作为曾经做出编写自己的数据库这个可疑决定的人,我知道这可能被证明是正确的做法,但——对于大多数公司而言——我认为结果并非如此。这不仅仅是一个商业问题,而且也存在一些有趣的工程维度。那么,Theo,你为什么觉得有必要编写自己的时序数据库?
THEO SCHLOSSNAGLE 原因有很多。首先,几乎所有流入我们遥测分析平台的数据都以数字随时间变化的形式出现。我们目睹了数据量和数据广度的指数级增长。事实上,据我们估计,在过去十年中,我们看到增长了约 1x1012 倍。显然,计算平台并没有跟上这个步伐。存储成本也没有下降 1x1012 倍。也就是说,我们经历的数据增长率与存储和分析所有这些数据所需的经济现实严重脱节。
因此,我们决定创建自己的数据库的首要原因是简单的经济学。基本上,最终,你可以解决任何问题,除了钱。看起来,通过限制问题空间,我们可以获得更便宜、更快速的解决方案,并且最终会随着时间的推移更易于维护。
JS 你考虑过任何开源数据库吗? 如果是,你是否发现有任何数据库似乎几乎足以满足你的需求,但由于某些有趣的原因而被你拒绝? 另外,我很好奇你在四处寻找时是否遇到了任何让你感兴趣的创新?——或者,就此而言,任何你真正想避免的事情?
TS 我深受 DynamoDB 和 Cassandra 以及其他一致性哈希数据库(如 Riak)的影响。尽管我发现这些设计很鼓舞人心,但我对它们的一致性哈希方法倾向于限制你对受约束数据集所能做的事情感到非常沮丧。
我们想要的是一个类似于 DynamoDB 或 Riak 或 Cassandra 等一致性哈希数据库的拓扑结构,但我们也想做一些小的调整,并且我们希望所有数据类型都是 CRDT(无冲突复制数据类型)。我们最终构建了一个完全使用 CRDT 的数据库。这从根本上改变了可能实现的功能,特别是围绕你如何在写入数据库时取得进展。
还有一些其他细微之处。首先,大多数一致性哈希系统在环中使用 vBucket 的概念,例如,你有 15 个主机和 64 个虚拟桶,数据落入其中,主机最终协商以确定它们中的哪些拥有哪些桶。
在我们的系统中,我们想要消除这种粗粒度。因此,我们实际上使用 SHA-256 作为我们的哈希方案,并且我们使用 2256 个 vBucket。因此,每个数据点落在哪里是由节点和环落在哪里驱动的,而不是由 vBucket 所有权驱动的。
这使我们能够进入我们称之为“双边环”的结构。在一个典型的持续哈希环中,你有一组主机,并且每个主机在环周围都有多个表示。我们所做的改为允许环被分成两半,环的前 180 度——环的前 pi——包含一半的节点,而另一个 pi 包含剩余的节点。
然后,为了将数据分配给节点,我们使用了我们称之为“跳跃行走”的方法。基本上,它在环上前后翻转 pi 弧度,从而保证你从环的一侧交替到另一侧,事实证明,当涉及到将环的一半放在一个 AZ(可用区)上,另一半放在另一个 AZ 上——或者放入一个区域或另一个区域,或者放入一个云或另一个云中时,这是非常有优势的。
使用 CRDT 而不是需要共识才能取得进展的一个有趣方面是,它可以让你,例如,将环的一半放在石油钻井平台上,另一半放在 Azure 云中,然后在 VSAT(甚小孔径终端)链路正常工作时,让所有内容正确同步。这样,即使它们断开连接,你也可以拥有所有相同的功能和保证。
JS 我也做了一些关于 CRDT 的工作,发现它们很有趣,因为你拥有可以由多个方更新的数据类型——可能在多台计算机上,在同一时间或重叠的时间内——而不会发生冲突。由于更新是自动解决的,因此你不需要传统的数据库意义上的隔离来确保一次只有一个方能够对给定的数据结构执行事务。事实上,这可以任意发生,并且仍然会全部理顺。
此外,还有不同的方法来解决这个问题,无论是通过交换性还是收敛操作——请记住,在过去的 10 多年里,已经对这些进行了大量研究。因此,你可以获得共识的一些好处,而无需禁止多个方在任何时候对同一数据采取行动。这就是为什么我认为这是一个令人兴奋的研究和实施领域。
CHRIS McCUBBIN 这如何应用于最适合时序数据库的数据类型和操作?迄今为止,这甚至是 CRDT 研究的重点吗?
TS 到目前为止,许多 CRDT 研究都集中在断开连接的操作上,当然,当你想到时序数据库时,这并不是首先想到的。但是 CRDT 方法的真正优势在于,如果你可以将整个操作集限制为 CRDT,则可以放弃诸如 Paxos、Multi-Paxos、Fast Paxos、Raft、Extended Virtual Synchrony 以及所有其他类似算法的共识算法。这并不是要贬低任何这些算法。只是,一旦可以实现无需法定人数即可取得进展的能力,它们就会带来很多不必要的包袱。
有几个原因使 CRDT 对时序数据库极具吸引力。其一是,大多数时序数据库——尤其是那些以我们这样的量级工作的数据库——从机器而不是人那里获取数据。连接这些机器的网络通常很宽,而且我将其描述为“始终在线且可操作”。这意味着,如果你的数据库的摄取端发生任何类型的服务中断,你停机的每一刻都将使状态恢复变得更加困难。
因此,如果我遇到停机,导致我的数据库在一个小时内失去法定人数,那么一旦服务恢复,我就无法立即恢复。首先,我需要处理过去一小时的数据,因为无论系统可用性如何,数据库摄取端的负担都会随着时间的推移而持续累积。也就是说,构建用于始终在线数据摄取的时序数据库有非常强烈的动机,否则——在发生服务中断或灾难性故障时——你会发现,在服务恢复后,你的状态将远远落后于当前状态,以至于根本无法追赶。
JS 听起来,出于周全的考虑,你用一个非常困难的问题换取了另一个问题——我的意思是,你摆脱了与共识算法相关的问题。然而,我了解到,许多所谓的 CRDT 实现实际上并没有达到这种标准。我很好奇你是如何达到可以确信你的数据结构实现真正符合 CRDT 标准的程度的。
TS 确实,很多 CRDT 都非常复杂,尤其是在它们表示某种复杂的相互关联的状态的情况下。一个典型的例子是用于文档编辑、字符串插入以及类似事物的 CRDT。但是,绝大多数机器生成的数据都是写入一次、永不删除、永不更新、仅追加的类型。这是一种由幂等事务产生的数据类型,当设备测量某个特定时间点的事物外观时,就会发生幂等事务。正是机器生成数据中的幂等性元素真正适合使用简化的 CRDT。
在我们的例子中,冲突解决是主要目标,因为对于时序数据,对于来自特定传感器的特定时间戳,只能有一个测量值。为了确保这一点,我们使用了一种非常简单的架构来确保任何测量的最大绝对值都将胜出。如果由于某种原因,设备应为同一时间点向我们提供两个样本,我们的系统将收敛于最大的绝对值。我们还有一个带外使用的世代计数器。这一切都只是为了提供简单的冲突解决。
综上所述,在一年中,当我们可能有万亿个样本传入时,我们通常最终会得到零个需要冲突解决的实例,仅仅因为机器生成的数据不是那种类型。
正如可能预期的那样,Schlossnagle 和他的团队在设计和开发他们的时序数据库时并没有从头开始。相反,他们查看了可以使用哪些框架以及可以借用哪些库。
首先,他们确定了最关键的是什么,以及他们愿意做出哪些权衡。例如,他们知道他们需要将向前和向后兼容性视为基本要求,因为他们无法承受任何会中断数据摄取的事情。
他们还了解到,将数据实际写入原始设备将是最难做对的事情之一。因此,他们设计数据库的方式是,只有少数几个地方实际将数据写入磁盘本身。相反,利用了许多现有的嵌入式数据库技术,系统内经过优化的路径已被设计为利用每种数据库技术的优势,同时规避其各自的弱点。
JS 很明显,你将 CRDT 视为解决你的首要设计约束之一的方法:需要提供始终在线的数据摄取。系统中还有哪些其他约束影响了你的设计?
TS 我们从第一手经验中了解到,无论何时你拥有一个跨多个集群运行的系统,你都不希望有某些节点比所有其他节点更关键,因为这可能会导致操作问题。这里的一个经典问题是 Hadoop 基础设施中的 NameNode,或者基本上,任何需要比所有其他节点更可用的特殊元数据节点。如果我们只是为了消除单点故障,那么这绝对是我们想要避免的事情。这在很大程度上影响了我们的设计。
此外,虽然我们专注于规模经济,因为我们正在接收一些真正高容量的遥测数据,但我认为我们没有尽早考虑的一个挑战是,我们以后如何设法在所有这些数据中找到东西。也就是说,如果你在一年内有万亿个样本进入你的系统,你将如何在所有这些数据中找到一些东西?你甚至将如何能够浏览所有这些数据?
例如,在物联网领域,如果你正在从 100 亿个传感器中获取测量数据,那么你将如何根据跨分布式系统的元数据搜索来隔离从某些传感器获得的数据?我认为这通常不会构成特别困难的计算挑战,但是因为它不是我们预先设计的东西,所以肯定会在我们的实施过程中导致很多痛苦和折磨。
JS 你很少听到人们谈论他们如何需要根据他们学到的与他们最初的假设相悖的东西来改变他们的方法,或者暴露一些尚未提供的东西——就像你在这里谈论的事情一样。如果我理解正确,你最初没有包括对某些你认为不太重要的数据的探索性查询,只是后来才意识到它实际上很重要。
TS 这是一个公平的描述。更具体地说,让我们假设,对于任何基于遥测的时序系统,你都将有一串附加到某些传感器的测量值。假设你正在测量服务器上的 CPU 使用率。对于这种情况,你将拥有一个 CPU 的唯一标识符,该标识符链接到一些测量值——无论是每秒、每分钟还是每十分之一秒——这些测量值表示该 CPU 的实际使用情况。
我们发现,在一个系统中,你最多可以拥有 1 亿甚至 10 亿个这样的字符串,这意味着可能很难找到一个特定的字符串并进行探索。作为一个独立的计算机科学问题,这并不难解决。
使问题复杂化的是,围绕这些字符串的元数据会随着时间推移而不断变化。容器技术就是一个很好的例子。假设你将你的 CPU 使用率数据附加到一个你在 Kubernetes 下运行的容器,然后你决定在一年内每天进行 40 次启动。这意味着,在你之前拥有 1 亿个数据流的地方,你现在拥有 14,600 倍的数据流 [365 天 x 40 次启动]——因此,你面临着真正的基数挑战。
JS 考虑到你始终在线、始终摄取的系统以及保护你为客户存储的所有数据的明显需求,我很好奇你是如何处理版本升级的。当你计划更改系统中的某些根深蒂固的设计元素时,你不能指望干净地重启。我自己处理过几次这种担忧,所以我知道它对你的工程选择有多大的影响。
TS 我认为你会发现数据库计算领域普遍存在很多相似之处。在我们的例子中,因为我们知道完美向前兼容性的挑战,我们尝试确保每个版本之间的升级都尽可能无缝,这样我们就不会最终需要重建整个系统。但更重要的担忧是,我们真的无法承受摄取服务的中断,这意味着我们需要将向前和向后兼容性视为绝对基本的要求。当然,你也可以对任何存储大量数据并拥有广泛用户群的数据库说同样的话。
Postgres 是一个很好的例子,说明数据库如何在应对这一挑战方面真正挣扎,因为无论何时你为 30TB 的数据库进行磁盘表格式更改,除非你可以通过复制和类似方法执行一些严肃的魔术,否则你可以指望某种形式的长期中断。尽管如此,我认为 Postgres 在过去几年中在这方面变得好多了,因为它已经意识到数据库变得多么庞大,以及当人们进行破坏向前兼容性的更改时,这些中断会持续多久。
JS 前向和后向兼容性不仅仅是存储你需要担心的问题。这些相同的担忧也适用于你在系统中运行的所有节点,因为你不能让所有节点在完全相同的时间更改版本。此外,以我的经验来看,从工程角度来看,兼容性问题被证明要困难得多,因为那时你或多或少一直生活在其中——而不仅仅是在你需要升级存储时。
TS 这绝对不仅仅是关于磁盘格式和功能。协议兼容性也需要考虑在内,特别是关于复制和查询以及类似的事情。有一些框架,例如 Google Protobuf [协议缓冲区] 和 gRPC,它们包含一些为此提供的进步。我们使用 FlatBuffers,具有讽刺意味的是,它也来自 Google。所有这些框架都有助于为兼容性提供未来的保障。因此,你可以序列化数据并添加新字段,但是长期以来一直存在的人仍然可以读取数据,而无需了解所有这些新字段。同样,即使缺少这些字段,新人也能够读取旧数据。这绝对有助于缓解许多实施方面的担忧。但是设计方面的担忧仍然存在,所以我认为你需要以这种方式对待它。事实上,我很想了解当前行业中涌现的任何关于如何设计以应对这种向前兼容性挑战的最佳实践。
我的另一个保留意见是,这些框架,尽管它们提供了所有优势,但往往非常特定于语言。如果你可以使用某个工具在 Erlang 中获得良好的效果,那么它不太可能对在 Go 中工作的人有太大帮助,就像为 Rust 编写的工具不一定对必须在 C 环境中工作的人有太多帮助一样。当你考虑到不仅仅有少数几种常用的生产系统语言时,很容易看出这会使事情变得非常棘手。
JS 我完全同意,但让我们回到真正推动你的时序数据库开发的原因。我尤其有兴趣了解你设法利用的任何预先存在的东西。我们已经稍微谈到了 FlatBuffers,但我认为你还可以利用其他一些软件,甚至硬件。
TS 首先让我说,FlatBuffers 提供了一个特别好的例子,因为它为序列化和反序列化提供了现成的解决方案的重用,这肯定是任何工程师最不吸引人的任务之一。然而,更重要的是,通过围绕所有这些提供一个不错的工具包,FlatBuffers 还为网络提供了重要的向后兼容性和字节序保证,这非常宝贵。这也适用于 Protobuf 和 Cap'n Proto。
不过,我会说,我们并非对所有这些框架都同样着迷。特别是 Avro 和 Thrift,它们公然坚持忽略无符号类型,已被证明在实践中非常难以使用。我们最终决定只关注那些真正理解通用系统类型的序列化/反序列化解决方案。
除此之外,我们还依赖大量的库。事实上,我们使用的大多数数据结构都来自开源库。Concurrency Kit 是一个很好的例子,它提供了一组基本的数据结构和原语,这对于生成非基于 Actor 的、高并发、高性能的系统非常有帮助。
然后是关于将东西存储在磁盘上的问题,这始终是一个有趣的挑战。人们说你永远不应该编写自己的数据库的一个原因是,很难将东西写入磁盘,同时确保它是安全的并且实际位于你认为的位置。我们设计的系统是,我们只有少数几个地方将数据写入磁盘本身。在其他大多数地方,我们依赖现有的嵌入式数据库系统,随着时间的推移,我们已经学会使它们尽可能可插拔。今天,我们总共使用四种内部嵌入式数据库技术,其中最流行的两种是 LMDB [闪电内存映射数据库] 和 RocksDB,它是 LevelDB 的 Facebook 衍生产品。
JS 当你提到直接将东西存储在磁盘上时,我会想到所有关于坐在文件系统之上的一般选择如何带来大量冲突,这些冲突可能会阻止你正确设计数据库的说法。然而,我知道你做出了一个有意识的决定,选择一种特定类型的文件系统技术。是什么驱动了这种选择,你现在对此有何感想?
TS 当你在文件系统之上操作时,绝对会付出性能代价。其中大部分与你在运行数据库时没有帮助的包袱有关。话虽如此,当你要将数据写入原始设备时,仍然有一些重要的数据完整性问题需要解决。底线是:我可以将东西写入原始设备。我可以将其同步到那里。我可以读回它以确保它是正确的。但是然后我可以返回稍后读取它,它将不再正确。位腐烂是真实存在的,尤其是在你使用大规模系统时。如果你要写出一个 EB 的数据,我可以保证它不会全部返回。关于你如何处理这个问题,存在一些疑问。
我们选择使用 ZFS 实际上是为了及时交付价值。也就是说,ZFS 为我们提供了可增长的存储卷;在操作过程中无缝添加更多磁盘的能力;内置压缩;围绕快照保护的一些安全保证;校验和;以及数据自动恢复的规定。能够一次性获得所有这些功能,使得付出使用文件系统的性能代价是值得的。
当然,另一方面是,无论如何我们都必须自己构建大部分功能。我们是否可以构建它以获得更好的性能?可能可以,因为我们可以免除很多不必要的包袱,例如 Posix 兼容性,这是 ZFS 提供的功能。但这可能也需要六到七年的产品开发。相反,我们能够立即获得我们需要的。它的代价是性能损失,我们愿意付出这个代价。
JS 我相信你已经考虑过的另一个考虑因素是,ZFS 在公众眼中有着复杂的历史,许多人对其法律地位表示严重怀疑。在你的客户中,你是否遇到过任何关于你选择使用 ZFS 的困难?
TS 成功始终是在公众舆论的法庭上定义的。所以,是的,我会说 ZFS 赌博从一开始就是一个冒险的命题。随着时间的推移,由于 Linux 版 OpenZFS 的采用,它被证明是一个安全的市场选择。尽管如此,我感觉如果 ZFS 没有在 Linux 上轻松可用,由于人们普遍不愿部署 ZFS,我们将需要重新平台化。
2016 年,我们进行了一些认真的讨论,讨论鉴于我们的大多数客户都部署在 Linux 上,我们是否可以继续使用 ZFS。我们坚持了下来,并将该决定推迟了足够长的时间,以便 Linux 版 OpenZFS 能够问世并使我们的选择合法化。但是有一段时间我们几乎要放弃 ZFS 了。
JS 我完全理解你的决定,但我仍然对你为什么选择使用四种嵌入式数据库技术感到困惑。我假设它们不是坐在文件系统之上的;你而是给它们直接设备访问权限,对吗?
TS 不,我们的嵌入式数据库也位于 ZFS 之上。
JS 四种嵌入式数据库技术如何对你有所帮助?
TS 从根本上说,答案是:单一的通用技术很少能完美地适应问题;总是有妥协。那么,我为什么会犹豫使用 LMDB 呢?事实证明,大规模写入 LMDB 可能比写入日志文件末尾要慢得多,这就是 LSM [日志结构合并] 风格的数据库(如 Rocks)的工作方式。但是,从像 RocksDB 这样的数据库读取数据比从像 LMDB 这样的 B+ 树数据库读取数据要慢得多。当你在构建一个跨越数年数据并涵盖各种访问模式和用户需求的大规模数据库系统时,你必须考虑到所有这些权衡和让步。
最终,我们选择优化系统内的各种路径,以便我们可以利用这些数据库技术中每一种的优势,同时规避其弱点。例如,正如你可能想象的那样,我们将所有来自外部世界的数据写入 LSM 架构(RocksDB),因为这不会给我们带来任何固有的性能约束。你只需将数据写入文件,并且只要你能足够快地对事物进行排序,你就可以跟上。尽管如此,鉴于这些数据库可能会随着时间的推移而大幅增长,你需要密切关注这一点。我的意思是,如果你有一个 30TB 的 RocksDB 数据库,你将会陷入困境。
我们有很多技术可以控制这一点。其中许多技术与时间分片数据有关。我们将拥有一个 Rocks 数据库,它表示本周的数据。然后,随着本周结束,我们将打开一个新的数据库。除此之外,在前一周的数据库保持一段时间未修改后,我们将 ETL [提取、转换、加载] 它为另一种 LMDB 格式,这种格式更好地服务于读取查询——这意味着我们重新优化它。
最后,我们用于处理摄取的 Rocks 数据库是一个键值存储,但这些值随后以非常面向列的方式存储。我们还将所有这些粘合在一起,以便你可以从写入端读取,并偶尔写入读取端。最后,使用和混合这两种不同的技术使我们能够针对我们预测的工作负载进行优化。
鉴于 Circonus 系统需要处理和处理的数据量,优化至关重要。事实上,该数据库包含数千个可调参数以实现优化。然而,要充分利用这些功能,需要对系统性能的各个方面具有非凡的可见性。为此,Schlossnagle 说 HDR [高动态范围] 对数线性量化直方图用于“跟踪一切”随时间的变化,甚至进行实验以找出通过更改某些孤立的调整如何优化性能。
尽管如此,团队对系统的构建方式有任何遗憾吗?只有少数几个。
JS 无论何时你为他人构建数据库,在你希望使其可配置或可调的程度之间都存在一种张力。该光谱的一端是使几乎每个变量都尽可能供用户访问的选项。另一个极端是使一切尽可能成为交钥匙工程,这样一切都运行良好,用户很难意外地破坏东西。显然,光谱远没有那么线性,但这种张力仍然存在。我很好奇地想了解你为解决这个问题所采取的方法。更重要的是,我想听听你在这个过程中学到了什么,以及你随后发现需要做出哪些调整。
TS 我自己的经验,两种方式都做过,表明没有正确的答案。不过,我会说,除非你的用例碰巧非常简单,否则这种自动调整、自我配置的软件始终有效的概念几乎是白日梦。即使你选择让每个配置参数或设置都可调,实际上也不可能使其所有这些调整组合都有效。如果你不小心,你真的可能会破坏你的系统。
然而,我们可能在系统中拥有 5,000 到 10,000 个可调参数,我们可以在线配置这些参数。事实上,绝大多数这些参数都仅在内部记录。通过二级/三级支持,我们能够调查系统,推测可能导致某些特定问题的原因,然后尝试热补丁修复它。来自此的反馈然后告知从那时起软件的默认处理参数。
我们还有一些自调整系统——主要围绕并发控制、节流、退避以及类似的东西——它们或多或少只是测量使用模式,然后相应地进行自我调整。这些仅限于我们拥有广泛实际经验、以前见过这些模式并因此有能力构建合适模型的案例。
JS 我不得不说,拥有多达 10,000 个杠杆确实似乎给了你很多权力。但是你的支持人员如何找出要触摸哪一个呢?也就是说,你做了什么来提供人们可以用来真正理解系统运行时的实时检查功能?
TS 这是我可以谈论很多的事情,因为我们技术真正有趣的部分之一与我们使用高清晰度直方图有关。我们有一个 HDR [高动态范围] 对数线性量化直方图的开源实现,称为 circllhist,它既非常快速又内存高效。在它的帮助下,我们能够跟踪每个 IOP [输入/输出操作]、数据库操作、队列中的时间以及在系统中移交给另一个核心所需的时间的功能边界的性能。这是我们用来跟踪系统上所有内容的东西,包括每个 RocksDB 或 LMDB get()
或 put()
。其中每一个的延迟都以纳秒为单位进行跟踪。在一个小的 Web 控制台中,我们能够查看任何这些直方图并观察它们随时间的变化。此外,由于这恰好是一个时序数据库,我们可以将该数据放回数据库中,并将我们的工具连接到它,以获得例如写入数字数据的延迟的第 99.9 个百分位数的时序图。
一旦捕获了你想要排除故障或优化的部分的性能特征,你就拥有了进行受控实验所需的东西,你可以在其中一次更改一个调整。这为你提供了一种通过仅更改一个参数然后跟踪它如何更改系统性能来收集直接反馈的方法,同时还要查找系统中其他任何部分的任何意外回归。我应该补充一点,这一切都作为开源框架的一部分 [https://github.com/circonus-labs/libmtev] 提供。
JS 听起来这真的对你有所回报,并且整个 undertaking 已经产生了令人印象深刻的回报。但我想知道,如果你今天才开始构建你的时序数据库,你会在哪些方面以截然不同的方式进行?
TS 当然!有很多事情我们会以不同的方式处理。我们在这里谈论的系统现在已经有九年历史了,因此从那时起引入了很多我们可以利用的创新。此外,在“事后诸葛亮”的标题下,我希望我选择了某些不同的数据结构,这些数据结构可以更好地从内存数据世界过渡到磁盘数据世界——特别是在内存索引和内存缓存中,在一定的容量下,你实际上确实想要采用缓存式方法,但出于可用性原因,你也希望它在磁盘上。
而且你真的希望能够将其视为半永久性的。例如,想想一个 130GB 的内存自适应基数索引。嗯,事实证明构建一个 130GB 的部分并非易事。如果我能让这些数据结构无缝地映射到磁盘上的数据结构就好了。当然,这些数据结构在 2011 年几乎没有什么实际用途,因为如果没有 NVMe [非易失性存储器标准] 等技术的支持,它们会太慢。尽管如此,使这些数据结构与内存无关——指针不变性——将是一项非常好的投资。事实上,我们现在正在进行中。
在这一点上,我可能会做的最大改变——回顾我们产品随着时间推移出现的所有 bug——就是我不会用 C 和 C++ 来编写它。相反,如果当时 Rust 已经出现,我会使用 Rust。用这种方式编写系统会非常棒,因为 Rust 通过引入借用检查器和内存所有权模型,基本上已经设法消除了导致我们软件故障的大部分问题。
但现在,我不得不说为时已晚;此时此刻在 Rust 上改造我们的平台并重新教育我们的团队将是一个棘手的问题。尽管如此,我仍然认为这是一个错失的机会,因为我认为基于 Rust 的系统会在我们过去几年遇到的许多用例中更好地为我们服务。
版权 © 2020 由所有者/作者持有。出版权已许可给 。
最初发表于 Queue 杂志第 18 卷,第 6 期——
在 数字图书馆 中评论这篇文章
Shaul Kfir, Camille Fournier - DAML:分布式账本的合约语言
一旦我们开始在公共云和框架中使用共享基础设施,我们将看到我们在 Web 世界中见证的那种寒武纪爆发。学习足够的 Ruby on Rails 和 Heroku 只花了三个星期,就推出了该经纪公司的管理系统的第一个版本。那是因为我只需要考虑模型、视图和控制器。当然,最困难的部分是构建一个安全的钱包。