HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

下一次 HighLoad++ 会议将于 6 年 7 月 2020 日至 XNUMX 日在圣彼得堡举行。
详情及门票 链接。 HighLoad++ 西伯利亚 2019。“克拉斯诺亚尔斯克”大厅。 25 月 12 日 00:XNUMX。 论文和 介绍.

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

实际需求与理论有时会发生冲突,而对于商业产品来说重要的方面却没有被考虑在内。 本演讲介绍了一个基于商业产品要求的学术研究选择和组合不同方法来创建因果一致性组件的过程。 听众将了解逻辑时钟、依赖性跟踪、系统安全、时钟同步的现有理论方法,以及 MongoDB 选择某些解决方案的原因。

米哈伊尔·秋列涅夫(以下简称MT): – 我将讨论因果一致性 – 这是我们在 MongoDB 中开发的一个功能。 我在一个分布式系统小组工作,我们大约两年前做的。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

在这个过程中,我必须熟悉很多学术研究,因为这个特性已经研究得相当好了。 事实证明,由于任何生产应用程序中都可能存在非常具体的要求,没有一篇文章适合生产数据库的要求。

我将讨论我们作为学术研究的消费者如何从中准备一些东西,然后将其作为方便且安全使用的现成菜肴呈现给我们的用户。

因果一致性。 让我们定义一下概念

首先,我想笼统地说一下什么是因果一致性。 有两个角色——伦纳德和佩妮(电视剧《生活大爆炸》):

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

假设 Penny 在欧洲,Leonard 想为她举办一个惊喜派对。 他想不出还有什么比把她从朋友名单中剔除、向所有朋友发送更新消息更好的了:“让 Penny 开心吧!” (她在欧洲,当她睡觉的时候,她看不到这一切,也看不到,因为她不在那里)。 最终,她删除了这篇文章,将其从动态中删除并恢复了访问权限,这样她就不会注意到任何事情,也不会出现丑闻。
这一切都很好,但我们假设系统是分布式的,并且出现了一些问题。 例如,如果事件之间没有因果关系,则 Penny 的访问限制可能是在该帖子出现后发生的。 实际上,这是需要因果一致性才能执行业务功能的示例(在本例中)。

事实上,这些都是数据库的非常重要的属性——很少有人支持它们。 让我们继续讨论模型。

一致性模型

数据库中的一致性模型到底是什么? 这些是分布式系统对客户端可以接收哪些数据以及以什么顺序接收的一些保证。

原则上,所有一致性模型都取决于分布式系统与在笔记本电脑的一个节点上运行的系统的相似程度。 这就是在数千个地理分布式“节点”上运行的系统与笔记本电脑的相似之处,其中所有这些属性原则上都是自动执行的。

因此,一致性模型仅适用于分布式系统。 以前存在并以相同垂直尺度运行的所有系统都没有遇到此类问题。 有一个缓冲区高速缓存,所有内容总是从其中读取。

模型强

实际上,第一个模型是“强”(或通常所说的“上升能力线”)。 这是一个一致性模型,可确保每次更改一旦确认发生,对系统的所有用户都是可见的。

这将创建数据库中所有事件的全局顺序。 这是一个非常强的一致性属性,而且通常非常昂贵。 然而,它得到了很好的支持。 它只是非常昂贵且缓慢 - 只是很少使用。 这就是所谓的上升能力。

Spanner 支持另一个更强大的属性 - 称为外部一致性。 我们稍后再讨论。

因果

下一个是因果关系,这正是我所说的。 强和因果之间还有几个子级别,我不会谈论,但它们都归结为因果。 这是一个重要的模型,因为它是所有模型中最强的,在存在网络或分区的情况下具有最强的一致性。

因果实际上是一种事件通过因果关系联系起来的情况。 他们常常被认为是从客户的角度理解您的权利。 如果客户观察到了一些值,他就看不到过去的值。 他已经开始看到前缀读数了。 这一切都归结为同一件事。
作为一致性模型的因果关系是服务器上事件的部分排序,其中来自所有客户端的事件以相同的顺序观察。 在这种情况下,伦纳德和佩妮。

最终的

第三个模型是最终一致性。 这绝对是所有分布式系统都支持的,是有意义的最小模型。 这意味着:当我们对数据进行一些更改时,它们在某些时候会变得一致。

这种时候她什么也不能说,否则她就会变成外在一致性——那将是一个完全不同的故事。 尽管如此,这是一个非常流行、最常见的模型。 默认情况下,分布式系统的所有用户都使用最终一致性。

我想举几个对比的例子:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

这些箭头是什么意思?

  • 潜伏。 随着一致性强度的增加,它会变得更大,原因很明显:您需要进行更多记录,从参与集群的所有主机和节点获得数据已经存在的确认。 因此,最终一致性有最快的答案,因为通常,您甚至可以将其保存到内存中,原则上这就足够了。
  • 可用性。 如果我们将其理解为系统在出现网络中断、分区或某种故障时做出响应的能力,那么容错能力会随着一致性模型的降低而增加,因为对我们来说,一台主机同时存在就足够了时间产生一些数据。 最终一致性根本不保证数据的任何内容——它可以是任何数据。
  • 异常现象。 当然,与此同时,异常的数量也在增加。 在强一致性中,它们几乎根本不应该存在,但在最终一致性中,它们可以是任何东西。 问题出现了:如果最终一致性包含异常,为什么人们会选择它? 答案是最终一致性模型是适用的,并且异常存在,例如在短时间内; 可以使用向导读取并且或多或少读取一致的数据; 通常可以使用强一致性模型。 在实践中,这是有效的,并且异常的数量通常在时间上是有限的。

CAP定理

当您看到一致性、可用性这些词时,您会想到什么? 没错——CAP定理! 现在我想消除这个神话……不是我,而是马丁·克莱普曼(Martin Kleppmann),他写了一篇精彩的文章,一本精彩的书。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

CAP定理是2000年代制定的一条原则,一致性、可用性、分区:任意取两个,不能选三个。 这是一个特定的原则。 几年后,吉尔伯特和林奇证明了它是一个定理。 然后这开始被用作口头禅——系统开始分为CA、CP、AP等。

这个定理实际上在以下情况下被证明了......首先,可用性不被认为是从零到数百的连续值(0 - 系统“死机”,100 - 快速响应;我们习惯这样考虑) ,但作为算法的一个属性,它保证其所有执行都会返回数据。

根本没有提到响应时间! 有一种算法可以在 100 年后返回数据 - 一种绝对精彩的可用算法,它是 CAP 定理的一部分。
第二:该定理针对同一键的值的变化而得到证明,尽管这些变化是可调整大小的。 这意味着实际上它们实际上没有被使用,因为模型是不同的最终一致性、强一致性(也许)。

这一切是为了什么? 此外,CAP 定理以其被证明的形式实际上不适用并且很少使用。 从理论上来说,它在某种程度上限制了一切。 事实证明,某个原理直观上是正确的,但总体上尚未得到证明。

因果一致性是最强的模型

现在发生的事情是,您可以使用分区获得所有三件事:一致性、可用性。 特别是,因果一致性是最强的一致性模型,在存在分区(网络中断)的情况下仍然有效。 这就是为什么它如此令人感兴趣,这就是为什么我们接受它。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

首先,它简化了应用程序开发人员的工作。 特别是,来自服务器的大力支持:保证一个客户端内发生的所有记录都以相同的顺序到达另一客户端。 其次,它能承受隔断。

MongoDB 内部厨房

想起今天是午餐,我们就去厨房。 我会告诉你系统模型,即对于那些第一次听说这样一个数据库的人来说MongoDB是什么。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

MongoDB(以下简称“MongoDB”)是一个支持水平扩展,即分片的分布式系统; 并且在每个分片内还支持数据冗余,即复制。

MongoDB(不是关系数据库)中的分片执行自动平衡,即每个文档集合(或关系数据中的“表”)被分成多个片段,服务器自动在分片之间移动它们。

为客户端分发请求的查询路由器是其工作的某个客户端。 它已经知道数据所在的位置和内容,并将所有请求定向到正确的分片。

另一个重要点:MongoDB 是单一主控。 有一个主数据库 - 它可以获取支持其包含的键的记录。 您不能进行多主机写入。

我们发布了 4.2 版本 - 那里出现了新的有趣的东西。 特别是,他们将 Lucene - 搜索 - 即可执行 java 直接插入到 Mongo 中,这样就可以通过 Lucene 执行搜索,就像在 Elastica 中一样。

他们做了一个新产品——Charts,它也可以在Atlas(Mongo自己的云)上使用。 他们有一个免费套餐 - 您可以尝试一下。 我真的很喜欢图表——数据可视化,非常直观。

成分 因果一致性

我统计了大约 230 篇关于这个主题的文章——来自 Leslie Lampert。 现在我凭记忆将这些材料的部分内容转达给大家。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

这一切都始于 Leslie Lampert 于 1970 世纪 XNUMX 年代撰写的一篇文章。 如您所见,有关此主题的一些研究仍在进行中。 现在,因果一致性正在引起人们对分布式系统开发的兴趣。

限制

有什么限制? 这实际上是要点之一,因为生产系统施加的限制与学术文章中存在的限制非常不同。 它们通常是相当人为的。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

  • 首先,正如我已经说过的,“MongoDB”是一个单一的主机(这大大简化了)。
  • 我们认为系统应该支持大约10个分片。 我们无法做出任何明确限制该值的架构决策。
  • 我们有云,但我们假设一个人仍然有机会下载二进制文件,在笔记本电脑上运行它,并且一切都运行良好。
  • 我们假设一些研究很少假设的事情:外部客户可以为所欲为。 MongoDB 是开源的。 因此,客户可能会变得如此聪明和愤怒——他们可能想破坏一切。 我们推测拜占庭费勒斯可能起源于拜占庭。
  • 对于边界之外的外部客户端,有一个重要的限制:如果禁用此功能,则不应观察到性能下降。
  • 另一点通常是反学术的:以前版本和未来版本的兼容性。 旧驱动程序必须支持新更新,并且数据库必须支持旧驱动程序。

一般来说,所有这些都会施加限制。

因果一致性成分

我现在将讨论一些组件。 如果我们一般考虑因果一致性,我们可以选择块。 我们从属于某个块的作品中进行选择:依赖跟踪,选择时钟,这些时钟如何彼此同步,以及我们如何确保安全 - 这是我将要讨论的内容的粗略概述:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

完整的依赖跟踪

为什么需要它? 这样,当复制数据时,每个记录、每个数据更改都包含有关其所依赖的更改的信息。 第一个也是幼稚的变化是,每条包含记录的消息都包含有关先前消息的信息:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

在此示例中,大括号中的数字是记录编号。 有时甚至会整体转移这些带有值的记录,有时会转移一些版本。 最重要的是,每个更改都包含有关前一个更改的信息(显然其自身包含所有这些信息)。

为什么我们决定不使用这种方法(全面跟踪)? 显然,因为这种方法是不切实际的:对社交网络的任何更改都取决于该社交网络之前的所有更改,例如在每次更新中传输 Facebook 或 VKontakte。 尽管如此,有很多关于完全依赖跟踪的研究——这些都是前社交网络;在某些情况下它确实有效。

显式依赖跟踪

下一篇更有限。 这里还考虑了信息的传输,但仅限于明显相关的信息。 一般来说,什么取决于什么,由应用程序决定。 复制数据时,查询仅在满足先前的依赖关系(即显示)时才返回响应。 这就是因果一致性工作原理的本质。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

她看到记录 5 依赖于记录 1、2、3、4 - 因此,当所有先前的更改都已通过数据库时,她会在客户端有权访问 Penny 的访问决策所做的更改之前等待。

这也不适合我们,因为信息仍然太多,而且会减慢速度。 还有另一种方法...

兰波特时钟

他们已经很老了。 Lamport Clock 的意思是将这些依赖关系折叠成一个标量函数,称为 Lamport Clock。

标量函数是一些抽象数字。 它通常被称为逻辑时间。 对于每个事件,该计数器都会增加。 进程当前已知的计数器发送每条消息。 很明显,进程可能不同步,它们可能有完全不同的时间。 尽管如此,系统还是以某种方式通过此类消息传递来平衡时钟。 在这种情况下会发生什么?

我将这个大分片分成两部分,以明确说明:朋友可以生活在一个节点中,其中包含该集合的一部分,而 Feed 可以生活在另一个节点中,其中包含该集合的一部分。 是否清楚他们如何能够越轨? 第一个提要会说:“已复制”,然后是“朋友”。 如果系统不提供某种保证,即在 Friends 集合中的 Friends 依赖项也被传递之前不会显示 Feed,那么我们就会遇到我提到的情况。

您会看到 Feed 上的计数器时间如何按逻辑增加:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

因此,Lamport Clock 和因果一致性(通过 Lamport Clock 进行解释)的主要属性是:如果我们有事件 A 和 B,并且事件 B 依赖于事件 A*,那么事件 A 的 LogicalTime 小于事件 B 的逻辑时间。

* 有时他们也说A发生在B之前,即A发生在B之前——这是一种对总体发生的整个事件集进行部分排序的某种关系。

反之则不正确。 这实际上是 Lamport Clock 的主要缺点之一——偏序。 有一个关于同时事件的概念,即既没有(A 发生在 B 之前)也没有(A 发生在 B 之前)的事件。 一个例子是伦纳德同时将其他人添加为朋友(甚至不是伦纳德,而是谢尔顿)。
这是使用 Lamport 时钟时经常使用的属性:他们专门查看该函数,并由此得出结论,这些事件可能是相关的。 因为一种方式是正确的:如果 LogicalTime A 小于 LogicalTime B,则 B 不可能在 A 之前发生; 如果更多,那么也许吧。

矢量时钟

Lamport 时钟的逻辑发展是矢量时钟。 它们的不同之处在于,这里的每个节点都包含自己单独的时钟,并且它们作为矢量传输。
在本例中,您会看到向量的第 1 个索引负责 Feed,向量的第一个索引负责 Friends(每个节点)。 现在它们会增加:“Feed”的零索引在写入时增加 - 2, 3, XNUMX:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

为什么矢量时钟更好? 因为它们允许您找出哪些事件是同时发生的以及它们何时发生在不同的节点上。 这对于 MongoDB 这样的分片系统来说非常重要。 然而,我们没有选择这个,尽管它是一件很棒的事情,而且效果很好,而且可能会适合我们......

如果我们有 10 个分片,即使我们对其进行压缩或提出其他方法,我们也无法传输 10 个组件 - 有效负载仍然比整个向量的体积小几倍。 于是,我们咬紧牙关,放弃了这种做法,转向了另一种做法。

扳手 TrueTime。 原子钟

我说过会有一个关于斯潘纳的故事。 这是一件很酷的事情,直接来自 XNUMX 世纪:原子钟、GPS 同步。

有什么想法吗? “Spanner”是 Google 的一个系统,最近甚至可供人们使用(他们向其中添加了 SQL)。 每笔交易都有一些时间戳。 由于时间是同步的*,每个事件都可以被分配一个特定的时间 - 原子钟有一个等待时间,之后保证会“发生”不同的时间。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

因此,只需写入数据库并等待一段时间,事件的可串行性就自动得到保证。 他们拥有原则上可以想象的最强的一致性模型——它就是外部一致性。

* 这是 Lampart 时钟的主要问题 - 它们在分布式系统上永远不会同步。 它们可能会出现分歧;即使使用 NTP,它们仍然不能很好地工作。 “Spanner”有一个原子钟,同步似乎是微秒。

为什么我们不选择? 我们不假设我们的用户有内置原子钟。 当它们出现时,内置在每台笔记本电脑中,将会有某种超酷的 GPS 同步 - 那么是的......但目前最好的可能是亚马逊,基站 - 对于狂热者......所以我们使用其他手表。

混合时钟

这实际上是 MongoDB 在确保因果一致性时所采取的措施。 他们是如何混血的? 混合是一个标量值,但它有两个组成部分:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

  • 第一个是 Unix 纪元(自“计算机世界开始”以来已经过去了多少秒)。
  • 第二个是一些增量,也是一个 32 位无符号整数。

事实上,仅此而已。 有这样的做法:负责时间的部分始终与时钟同步; 每次发生更新时,这部分都会与时钟同步,结果表明时间总是或多或少正确,并且增量允许您区分在同一时间点发生的事件。

为什么这对 MongoDB 很重要? 因为它可以让你在某个时间点做某种备份餐厅,即事件按时间索引。 当需要某些事件时,这一点很重要; 对于数据库来说,事件是数据库中以特定时间间隔发生的更改。

我只告诉你最重要的原因(请不要告诉任何人)! 我们这样做是因为这就是 MongoDB OpLog 中组织化、索引化的数据。 OpLog 是一种数据结构,绝对包含数据库中的所有更改:它们首先进入 OpLog,然后在复制日期或分片的情况下应用到存储本身。

这是主要原因。 尽管如此,开发数据库也有实际要求,这意味着它应该很简单——代码很少,需要重写和测试的损坏的东西尽可能少。 我们的操作日志由混合时钟索引这一事实很有帮助,让我们能够做出正确的选择。 它确实得到了回报,并且在第一个原型上神奇地发挥了作用。 太酷了!

时钟同步

科学文献中描述了多种同步方法。 当我们有两个不同的分片时,我正在谈论同步。 如果有一个副本集,则不需要任何同步:这是“单主”; 我们有一个 OpLog,所有更改都落入其中 - 在这种情况下,所有内容都已在“Oplog”本身中按顺序排序。 但如果我们有两个不同的分片,时间同步在这里就很重要。 这就是矢量时钟发挥更大作用的地方! 但我们没有。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

第二个是合适的——这是“心跳”。 可以交换每个单位时间发生的一些信号。 但心跳太慢,我们无法向客户端提供延迟。

当然,真正的时间是一件美妙的事情。 但是,这可能是未来......虽然它已经可以在 Atlas 中完成,但已经有了快速的“Amazon”时间同步器。 但它不会提供给所有人。

八卦是指所有消息都包含时间。 这大约就是我们使用的。 节点之间的每条消息、驱动程序、数据节点路由器,绝对 MongoDB 的所有内容都是某种元素,即包含运行时钟的数据库组件。 它们到处都有混合时间的意义,它被传递。 64位? 这允许,这是可能的。

这一切是如何协同工作的?

在这里,我正在查看一个副本集,以使其更容易一些。 有小学和中学之分。 辅助节点进行复制,并不总是与主节点完全同步。

插入发生在“Primery”中并具有一定的时间值。 如果这是最大值,则此插入会将内部计数增加 11。 或者它会检查时钟值,如果时钟值更大,则同步到时钟。 这使您可以按时间进行组织。

在他录制完之后,一个重要的时刻发生了。 时钟位于“MongoDB”中,并且仅在写入“Oplog”时才会递增。 这是改变系统状态的事件。 在绝对所有经典文章中,事件被认为是当消息到达节点时:消息已到达,这意味着系统已更改其状态。

这是因为在研究过程中并不完全清楚如何解释该消息。 我们确信,如果没有反映在“Oplog”中,那么它不会以任何方式被解释,系统状态的变化只是“Oplog”中的一个条目。 这为我们简化了一切:模型简化了它,并允许我们将其组织在一个副本集中,以及许多其他有用的东西。

返回已写入“Oplog”的值 - 我们知道“Oplog”已包含该值,其时间为 12。现在,假设从另一个节点(Secondary)开始读取,并且在 ClusterTime 之后传输消息。 他说:“我需要至少 12 点之后或 XNUMX 点期间发生的所有事情”(见上图)。

这就是所谓的因果一致性(CAT)。 理论上有这样一个概念,这是某个时间片,它本身是一致的。 在这种情况下,我们可以说这是在时间 12 观察到的系统状态。

现在这里还什么都没有,因为这种模拟的是当您需要辅助节点从主节点复制数据时的情况。 他等待……现在数据已经到达——他将这些值返回。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

这几乎就是一切的运作方式。 几乎。

“几乎”是什么意思? 让我们假设有人已经阅读并理解了这一切是如何运作的。 我意识到每次 ClusterTime 发生时,它都会更新内部逻辑时钟,然后下一个条目加一。 这个函数需要 20 行。 假设这个人传输最大的 64 位数字减一。

为什么要“减一”呢? 因为内部时钟将被替换为这个值(显然,这是最大可能的并且大于当前时间),那么“Oplog”中将出现一个条目,并且时钟将增加另一个单位 - 并且已经有是最大值(只有所有单位,没有其他地方可去),非圣整数)。

很明显,在此之后系统将变得绝对无法访问任何内容。 它只能卸载和清洁——大量的手工工作。 完全可用:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

此外,如果这被复制到其他地方,那么整个集群就会崩溃。 这是绝对不可接受的情况,任何人都可以非常快速、轻松地组织起来! 因此,我们认为这一刻是最重要的时刻之一。 如何预防呢?

我们的方式是对 clusterTime 进行签名

这就是它在消息中的传输方式(在蓝色文本之前)。 但我们也开始生成签名(蓝色文本):

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

签名由存储在安全范围内的数据库内的密钥生成; 其本身已生成并更新(用户看不到任何有关它的信息)。 生成哈希值,每条消息在创建时进行签名,并在接收时进行验证。
人们的脑海中可能会出现这样的问题:“这会在多大程度上减慢速度?” 我告诉过你它应该很快就能工作,特别是在没有这个功能的情况下。

在这种情况下使用因果一致性意味着什么? 这是为了显示 afterClusterTime 参数。 如果没有这个,它无论如何都会简单地传递值。 从 3.6 版本开始,闲聊总是有效的。

如果我们不断生成签名,即使没有某个功能,也会减慢系统速度,这不符合我们的方法和要求。 那么我们做了什么?

快点做吧!

这是一个相当简单的事情,但其中的技巧很有趣——我会分享它,也许有人会感兴趣。
我们有一个存储签名数据的哈希值。 所有数据都会经过缓存。 缓存不标注具体时间,而是标注Range。 当某个值到达时,我们生成一个 Range,屏蔽掉最后 16 位,然后对该值进行签名:

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

通过接收这样的签名,我们将系统速度(相对)提高了 65 倍。 它效果很好:当我们进行实验时,当我们进行顺序更新时,时间实际上减少了一万倍。 很明显,当他们意见不合时,这是行不通的。 但在大多数实际情况下它是有效的。 Range签名与签名的结合解决了安全问题。

我们学到了什么?

我们从中吸取的教训:

  • 我们需要阅读材料、故事、文章,因为我们有很多有趣的东西。 当我们研究某些功能时(尤其是现在,当我们进行交易等时),我们需要阅读和理解。 这需要时间,但它实际上非常有用,因为它让我们清楚地知道我们在哪里。 我们似乎没有想出任何新东西——我们只是采用了原料。

    一般来说,学术会议(例如Sigmon)的思维会有一定的差异——每个人都关注新的想法。 我们的算法有什么新内容? 这里没有什么特别新的东西。 新颖之处在于我们将现有方法融合在一起的方式。 所以,首先要读经典,从兰帕特开始。

  • 在生产中,要求完全不同。 我确信你们中的许多人面对的并不是抽象真空中的“球形”数据库,而是正常的、真实的存在可用性、延迟和容错问题的数据库。
  • 最后一件事是,我们必须考虑不同的想法,并将几篇完全不同的文章组合成一种方法。 例如,关于签名的想法通常来自一篇考虑 Paxos 协议的文章,对于非拜占庭失败者来说,它位于授权协议之内,对于拜占庭失败者来说,它位于授权协议之外……总的来说,这正是我们所希望的。最终做了。

    这里绝对没有什么新鲜事! 但一旦我们把它们混合在一起……就等于说奥利维尔沙拉食谱是无稽之谈,因为鸡蛋、蛋黄酱和黄瓜已经被发明了……这是同一个故事。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

我就讲完这个。 谢谢你!

问题

观众提问(以下简称B): – 谢谢米哈伊尔的报告! 关于时间的话题很有趣。 您正在使用闲聊。 他们说每个人都有自己的时间,每个人都知道自己当地时间。 据我了解,我们有一个驱动程序 - 可能有很多带有驱动程序的客户端,也有查询规划器,也有分片......如果我们突然出现差异,系统会归结为什么呢:有人决定它是为了领先一分钟,有人落后一分钟? 我们最终会去哪里?

公吨: – 确实是个好问题! 我只是想谈谈碎片。 如果我正确理解这个问题,我们会遇到以下情况:有分片 1 和分片 2,读取发生在这两个分片上 - 它们有差异,它们彼此不交互,因为它们知道的时间不同,尤其是它们存在于 oplog 中的时间。
假设分片 1 创建了 2 万条记录,分片 2 根本没有执行任何操作,并且请求到达了两个分片。 第一个的 afterClusterTime 超过一百万。 在这种情况下,正如我所解释的,分片 XNUMX 根本不会响应。

在: – 我想知道他们如何同步并选择一个逻辑时间?

公吨: - 非常容易同步。 分片,当 afterClusterTime 到来时,他在“Oplog”中找不到时间,则不会发起批准。 也就是说,他用手将自己的时间提高到这个值。 这意味着它没有与此请求匹配的事件。 他人为地创造了这个事件,从而变得因果一致。

在: – 如果此后他又遇到一些其他事件,而这些事件在网络中的某个地方丢失了怎么办?

公吨: – 碎片的设计方式是它们不会再来,因为它是单一的主设备。 如果他已经报名了,那么他们就不会来,而是稍后会来。 不可能发生某些事情卡在某个地方,然后他不写,然后这些事件到达 - 并且因果一致性被打破。 当他不写时,他们都应该下一个(他会等待他们)。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

在: – 我有几个关于队列的问题。 因果一致性假设存在需要执行的特定操作队列。 如果我们的其中一个包裹消失了怎么办? 10号、11号来了……12号已经消失了,其他人都在等待它的实现。 我们的车突然坏了,我们无能为力。 在执行之前累积的队列是否有最大长度? 当任何一种状态丢失时会发生什么致命故障? 而且,如果我们写下有一些先前的状态,那么我们应该以某种方式从它开始吗? 但他们并没有把他推开!

公吨: –也是一个很好的问题! 我们在做什么? MongoDB 有仲裁写入、仲裁读取的概念。 什么情况下消息会丢失? 当写入不是法定人数或读取不是法定人数时(某种垃圾也可能会粘住)。
关于因果一致性,进行了大规模的实验测试,结果是在写入和读取非法定人数的情况下,会发生违反因果一致性的情况。 正是你所说的!

我们的建议:在使用因果一致性时至少使用法定人数阅读。 在这种情况下,即使仲裁记录丢失,也不会丢失任何内容……这是一个正交情况:如果用户不希望数据丢失,则需要使用仲裁记录。 因果一致性并不能保证持久性。 持久性由复制和与复制相关的机制来保证。

在: – 当我们创建一个为我们执行分片的实例(分别不是master,而是slave)时,它依赖于自己机器的Unix时间或“master”的时间; 是第一次同步还是定期同步?

公吨: – 我现在就澄清一下。 分片(即水平分区)——总有一个主分片。 一个分片可以有一个“主分片”,也可以有多个副本。 但分片始终支持记录,因为它必须支持某个域(分片有 Primary)。

在: ——所以一切都完全取决于“主人”? 是否总是使用主时间?

公吨: - 是的。 你可以形象地说:当进入“master”、进入“Oplog”时,时钟正在滴答作响。

在: – 我们有一个连接的客户端不需要知道任何时间?

公吨: – 你根本不需要知道任何事情! 如果我们谈论它在客户端是如何工作的:当客户端想要使用因果一致性时,他需要打开一个会话。 现在一切都已就绪:会话中的事务、检索权限……会话是客户端发生的逻辑事件的顺序。

如果他打开此会话并在那里说他想要因果一致性(如果会话默认支持因果一致性),则一切都会自动进行。 驱动程序会记住这个时间,并在收到新消息时增加它。 它会记住前一个从返回数据的服务器返回的响应。 下一个请求将包含 afterCluster(“时间大于此”)。

客户不需要知道任何事情! 这对他来说是完全不透明的。 如果人们使用这些功能,他们可以做什么? 首先,您可以安全地读取辅助节点:您可以写入主节点并从地理复制的辅助节点中读取数据,并确保其正常工作。 同时,在主服务器上记录的会话甚至可以转移到辅助服务器,即您可以使用多个会话,而不是一个会话。

在: – 计算科学的新层 – CRDT(无冲突复制数据类型)数据类型 – 与最终一致性主题密切相关。 您是否考虑过将这些类型的数据集成到数据库中?您对此有何评论?

公吨: - 好问题! CRDT 对于写冲突是有意义的:在 MongoDB 中,单主。

在: – 我有一个来自开发人员的问题。 在现实世界中,当拜占庭失败发生时,会出现这样的耶稣会情况,受保护范围内的邪恶人士开始刺探协议,以特殊方式发送工艺包?

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

公吨: – 外围的恶人就像特洛伊木马! 外围的坏人可以做很多坏事。

在: – 很明显,粗略地说,在服务器上留下一个洞,你可以通过它放置大象动物园并永远崩溃整个集群......手动恢复需要时间......这,温和地说,是错误的。 另一方面,这很有趣:在现实生活中,在实践中,是否存在自然发生类似内部攻击的情况?

公吨: – 由于我在现实生活中很少遇到安全漏洞,所以我不能说它们是否确实发生。 但如果我们谈论开发理念,我们会这样想:我们有一个边界,可以为负责安全的人员提供服务——这是一座城堡,一堵墙; 在边界内你可以做任何你想做的事。 很明显,有些用户只能查看目录,有些用户只能删除目录。

根据权利的不同,用户造成的损害可能是一只老鼠,也可能是一头大象。 显然,拥有完全权限的用户可以做任何事情。 权限有限的用户造成的伤害会小得多。 特别是它不能破坏系统。

在: – 在受保护的范围内,有人试图为服务器创建意想不到的协议,以便完全摧毁服务器,如果幸运的话,整个集群......它曾经变得那么“好”吗?

公吨: “我从来没有听说过这样的事情。” 通过这种方式可以使服务器崩溃这一事实已不是什么秘密。 内部失败,来自协议,作为授权用户可以在消息中写这样的内容......事实上,这是不可能的,因为它仍然会被验证。 可以为不需要的用户禁用此身份验证 - 那么这就是他们的问题; 粗略地说,他们自己破坏了墙壁,你可以把大象推进去,大象会践踏……但总的来说,你可以装扮成修理工,来把它拉出来!

在: – 感谢您的报告。 谢尔盖(Yandex)。 Mong中有一个常数限制了副本集中投票成员的数量,这个常数是7(七)。 为什么这是一个常数? 为什么这不是某种参数?

公吨: – 我们有 40 个节点的副本集。 总是有多数的。 不知道哪个版本...

在: – 在Replica Set中,你可以运行无投票权的成员,但是最多有7个投票权的成员。如果我们的Replica Set分布在3个数据中心,那么在这种情况下,我们如何才能在关闭时幸存下来? 一个数据中心很容易关闭,而另一台机器可能会掉下来。

公吨: – 这已经有点超出了报告的范围。 这是一个一般性问题。 也许我可以稍后再告诉你。

HighLoad++,Mikhail Tyulenev (MongoDB):因果一致性:从理论到实践

一些广告🙂

感谢您与我们在一起。 你喜欢我们的文章吗? 想看更多有趣的内容? 通过下订单或推荐给朋友来支持我们, 面向开发人员的云 VPS,4.99 美元起, 我们为您发明的入门级服务器的独特模拟: VPS (KVM) E5-2697 v3(6 核)10​​4GB DDR480 1GB SSD 19Gbps XNUMX 美元或如何共享服务器的全部真相? (适用于 RAID1 和 RAID10,最多 24 个内核和最多 40GB DDR4)。

Dell R730xd 在阿姆斯特丹的 Equinix Tier IV 数据中心便宜 2 倍? 只有这里 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 电视低至 199 美元 在荷兰! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - 99 美元起! 阅读 如何建设基础设施公司同级使用价值730欧元的Dell R5xd E2650-4 v9000服务器一分钱?

来源: habr.com

添加评论