天天看点

复制策略与复制的方式 【已翻译100%】(2/2)

服务器宕机意味着相关的日志变化部分会在尺度上增加,直到同伴节点再次运行起来,或者我们从复制目标中移除这个服务器条目。

到目前为止,这与你要组织 oplog 的方式非常相似。主要的不同是,组织需要记录的真实数据的方式。从 oplog 角度看,你准备向系统中写入发生的变化。并且,对之施行的唯一方式就是以它产生的相同顺序将其应用到 oplog 中。这会导致你只能一直拥有一个单主节点的系统。并且会引发在“大脑分裂”时数据丢失或需要手工合并的场景。

就多重可写组合而言,我们要保持足够的上下文(通常是所有对象),以便给用户更好的选择来解决冲突。这也在非顺序的方式中给我们一种重新回放日志的选择。

注意,无论如何,你都不能让一个新的服务器上线,如果你想让它一开始就运行良好的话。你必须从一个已知状态开始,通常是从一个已存在的数据库备份节点开始。像日志传送的那样,这个过程从本质上说,开始复制到(当前不存在的服务器上),当我们实际拥有新的服务器时,这将确保日志记录它们。在一个从服务器上备份和恢复数据库,然后,从源数据库那里配置接收复制。

这里的复杂性是这样的,你需要处理的操作,你可能已经做过了。这就是为什么通常是搭配vector clocks使用,这样你就可以自动解决这些冲突。当你不能解决这些冲突时,就会陷入手动用户干预。

多主系统(multi master systems)非常类似于多重可写组合(multi write partners),但是它们被设计成独立运作。常见的服务器可以是彼此间很少通信的。举例来说,一个可移动系统在一周中可能只能连上网络几个小时。同样地,我们不能限制复制操作的规模。实际上,常见的方法是快速把它复制给一个新的服务器。这意味着我们需要的复制,本质上可以从服务器历史上任何点,复制到一个新的服务器。

只要你没有删除,它就会工作地很好。因为你需要保持跟踪,并且复制它们,所以那样做比较难。比如,ravendb和couchdb都是多主系统。冲突以同样的方式工作,我们使用一个向量时钟(vector clock)判断一个值是否相冲突。

divergent writes

我提到的这几次,但我没有完全解释。对于我而言,我们假设我们使用2个服务器(是的,我当然知道会议法定人数(quorums),等等,这个讨论暂不相关)在主/从模式下运行。

在某一时刻,从服务器认为主服务器已经挂掉了就开始接管,并且主服务器不会通知,仍然会认为它是主服务器。在此期间,两个服务器都会接收到下面的写入信息:

那些操作发生之后,我们在两个服务器间恢复通讯,他们需要决定怎样去处理那些改变。

getting down to business

好的,已经很充分地讨论了那些术语的含义。让我们考虑使用它们的意义。在使用中,日志传送是迄今为止最简单的方法。好,假设你有一个日志机制,除了大多数数据库做的。它是一个严格地写入模型,并且绝对没有一个方法,或能处理发散地写入或能找出他们。日志传送的好处是它很容易得到这个结果而不需要关心实际包含的数据。我们直接在文件级别上工作,我们不关心数据是什么。问题是,我们几乎不能解决简单的冲突,类似写不同的对象。这是因为我们所有的改变,实际上是 在文件级别上工作。试图 合并改变来自多个日志文件可能会导致文件错误。站在好的一面,这可能是解决这个问题最有效的方式。

oplog是日志传输中的一个步骤,但它不是一个很大的操作。它不能解决分散写的问题。现在这是一个应用程序级别的协议。日志需要包含的信息具体到我们存储的实际数据类型。你需要编写显式的代码来处理这些问题。这很好,但它的所有操作序列也是有严格的。现在,你可以尝试合并不同的日志。然而,你还是需要担心冲突,说得更确切些,通常是没有数据本身,甚至也会帮你检测出冲突。

多重可写组合(multi write partners)意味着将其提升一个等级。他们跟踪版本历史(通常通过向量时钟)。在这里,情况更复杂,因为我们需要显式地决定如何处理冲突(自动解决或听从用户的决定),而且如何处理分布的更新。他们通常与某种形式的逻辑告诉你如何直接写。所以,所有写特定的数据块都进入首选的节点,去避免产生多个版本。数据需要包含一些信息,所以我们保持向量时钟的信息。一旦我们发送这些改变给我们的组合(partners),我们可以终止它们,保存在(磁盘)空间里。

多重主(multi master)意味着确保你的从机可能仅仅在偶然情况下才能看到另一个,而且在网络拓扑结构上不能有假设。它可以处理一个节点上发生的事件,从中获取一些数据拷贝,并且停掉一段时间(或是永远)。每一个节点都是完全独立的,并且它们之间应该是可以彼此合作的,但不是说它们之间就是互相需要的。这种方法的缺点是我们永远都需要保持记录一些信息。尤其是,我们需要保持对删除的记录,以确保我们能从远程的机器中获取这些信息。

what about set operations?

有趣的是,这也许也是最难解决的问题。当你已经允许下面的操作发生时考虑这样一种情况:

结果应该是什么呢?真的没有一个很好地答案去回答这个问题。应该将users/8设置为有效:真的吗?那users/7呢,应该被删除还是被保持?

这将变得困难,因为你没有更好的选择。这里的难点实际上是冲突的判定。并没有一个恰当的方法来处理带有冲突的操作集。通常的解决方案是,将其翻译为产生的实际操作(delete users/1,user/2, users/3 – writer users/8, users/5),这样就可以了。基于集合的操作被翻译为实际发生的各个独立操作。在此基础上,我们能更容易的检测冲突。

从操作上来说,日志传送是最容易处理的。你知道你想要获得什么,并且你可以处理它。oplog 也很简单,你有个单主节点,它也能工作。多重主与多重可写组合需要你明确的留意冲突,选择合适的节点来减少冲突,等等。

在实践中,至少在涉及 ravendb 的情景中,能让服务器离线几周或几个月的能力似乎不常用到。常见的部署模型服务器的运行稳定的伙伴。有一些你可以对 multi write partners 做的优化,很难或不可能对 multi master 去做。

在这一点上我目前个人的偏好是 日志泊运 或 multi write master 都可以。我认为他们中的任何一个都能相当简单的实施和支持操作。我想我会在我的下一篇文章中讨论使用其中一项对时间序列课题进行实际设计。