在Couchbase中处理耐久性要求失败

时间:2018-10-04 13:45:23

标签: transactions couchbase durability

最近,我开始研究Couchbase Server作为该项目的候选人。我现在正在研究的一个特定场景是如何使Couchbase充当“真理之源”,这就是为什么我要研究持久性方面。

这是ACID Properties and Couchbase的摘录:

  

如果耐久性要求失败,则Couchbase可能仍会保存   文档,并最终将其分布在整个集群中。我们所知道的   据SDK所知,它没有成功。您可以选择   根据这些信息采取行动,将更多的ACID属性引入您的   应用。

所以想象下。我插入/更新文档,并且主节点失败,直到数据写入任何副本为止。假设主要对象消失了很长时间。现在,我现在还不知道是否将数据写入磁盘。因此,令人恐惧的是“ Couchbase可能仍会保存文档并最终将其分布到整个群集中”。意思是,据客户所知,数据不是正确的,因此用户会看到一个错误,但是如果主数据库重新联机,它可能会突然出现在系统中。

我是否正确阅读了此声明?如果是,用Couchbase处理它的最佳实践是什么?

3 个答案:

答案 0 :(得分:3)

简短答案:

打开自动故障转移,就可以了。

更长的答案:

听起来您担心这里的边缘情况很窄。这是我的理解:

  1. 您使用SDK保存了文档,并赋予了persists_to持久性要求。
  2. Couchbase确认文档已保存到内存中。
  3. SDK开始检查以确保它已持久保存到磁盘和/或已复制。
  4. 在非常短暂的时间内,该节点关闭。该文档已保留在磁盘上,但是未复制到另一个节点,并且主节点未进行故障转移
  5. SDK操作将返回一个错误,表明它不满足持久性要求。 (对此我可能是错的,它可能会返回不同的错误,这意味着您可以采取不同的措施)。
  6. 您通知用户发生故障。
  7. 该节点重新启动,重新加入群集,文档就在那里。
  8. 困惑的用户?

如果是正确的话,关键是步骤4。首先,这似乎是非常罕见的情况。担心这种情况,所有这三件事都必须是正确的。我对Couchbase的内部知识了解并不牢固,因此可能无法实现这种情况(但我会继续坚持下去)。

如果您在良好的网络和良好的计算机上运行Couchbase,则网络拆分/节点中断不应该经常发生。因此,您可以打开自动故障转移。请记住,我们的文档没有将其存入磁盘。因此,当发生故障转移时,该文档仅在RAM中,因此该文档永久消失了(并且自从您告诉用户以来,没有混乱)。

同样,我不是Couchbase内部专家,所以,据我所知,这一切,但这听起来像您需要做的就是打开自动故障转移功能,一切都会好起来的。默认情况下它是关闭的;这个想法是,您应该首先了解什么,然后选择加入。但是对于大多数系统,请使用自动故障转移。

答案 1 :(得分:1)

这就是我发现要与Couchbase的人交谈的地方:

场景1

  

一种情况可能是在被确认为   保留,但是在复制之前,该节点失败。在那里面   在这种情况下,如果不对节点进行故障转移,则当该节点重新联机时,   项目将被复制。

场景#2

  

另一种情况是您可能启用了自动故障转移,并且   在主服务器收到之后但在复制之前或   持久存在后,自动故障转移就会启动并将副本带到主副本。在   在这种情况下,您的应用程序将会看到无法实现   要求耐用性。如果前一个主要的确出现   重新联机,在重新加入群集之前,它将与   当前群集的状态,表示项目所在的位置   活动状态现在是当前状态。

所以我问过“ 当前主服务器恢复在线状态并保留本地但未复制的项目并开始重新同步时,这些项目会被抹掉吗?”-

  

是的,这确实是故意的。你以前可以看一下   将项目保留为没有结束的“替代历史记录”。什么时候   发生故障,集群选择了一个新的起点,   每个人都同意,并开始了从那里开始的宇宙。   当旧节点恢复并尝试加入此Universe时,它必须   在对那个宇宙有共同理解的情况下这样做   表示删除未传递的数据。

     

当然,实际上,由于复制是内存到内存和磁盘   IO往往会有更高的延迟(物品和物品的复制   项目的持久性都是同时安排的),   往往被复制得比持久的要多,但是并不能保证。   此外,该应用程序(通过SDK)具有一定的能力来影响结果   我们讨论的耐用性要求功能也是如此。

完整的对话是here

答案 2 :(得分:0)

此问题的更新:

Couchbase 6.5引入了对事务的支持:

transactions.run((txnctx) -> {
    // get the account documents for Andy and Beth  
    TransactionJsonDocument andy = txnctx.getOrError(collection, "Andy");
    JsonObject andyContent = andy.contentAsObject();
    int andyBalance = andyContent.getInt("account_balance");
    TransactionJsonDocument beth = txnctx.getOrError(collection, "Beth"); 
    JsonObject bethContent = beth.contentAsObject();
    int bethBalance = bethContent.getInt("account_balance");

    // if Beth has sufficient funds, make the transfer
    if (bethBalance > transferAmount) {
            andyContent.put("account_balance", andyBalance + transferAmount);
            txnctx.replace(andy, andyContent);
            bethContent.put("account_balance", bethBalance - transferAmount);
            txnctx.replace(beth, bethContent);
    }
    else throw new InsufficientFunds();  
    // Commit transaction - if omitted will be automatically committed 
    txnctx.commit();
});

耐久性也得到了改善,现在您可以在3个级别之间进行选择:多数,persistToActive,persistToMajority

了解更多: