让我用纯粹直观的术语来解释 CAP。首先,C、A 和 P 是什么意思:
从系统设计的角度来看,这些意味着什么?CAP 定义的张力是什么?
为了实现 P,我们需要副本。很多!我们保留的副本越多,即使某些节点处于离线状态,我们需要的任何数据都可用的机会就越大。对于绝对“P”,我们应该将每个数据项复制到系统中的每个节点。(显然在现实生活中我们会在 2、3 等上妥协)
为了实现 A,我们不需要单点故障。这意味着“主/从”或“主/从”复制配置不再适用,因为主/主是单点故障。我们需要使用多个主配置。要实现绝对“A”,任何单个副本都必须能够独立于其他副本处理读取和写入。(实际上我们在异步、基于队列、仲裁等方面做出了妥协)
为了实现C,我们需要系统中的“单一版本的真理”。这意味着如果我写入节点 A 然后立即从节点 B 读回,节点 B 应该返回最新值。显然,这在真正分布式的多主机系统中是不可能发生的。
那么,您的问题的解决方案是什么?可能是为了放松一些约束,并在其他约束上妥协。
例如,要在具有n 个副本的系统中实现“完全写入一致性”保证,读取次数 + 写入次数必须大于或等于 n:r + w >= n。 这很容易用一个例子来解释:如果我将每个项目存储在 3 个副本上,那么我有几个选项来保证一致性:
A)我可以将项目写入所有 3 个副本,然后从 3 个副本中的任何一个读取,并确信我得到了最新版本 B)我可以将项目写入其中一个副本,然后读取所有 3 个副本并选择3 个结果中的最后一个 C)我可以写入 3 个副本中的 2 个,并从 3 个副本中的 2 个读取,并且我保证我将在其中一个上拥有最新版本。
当然,上面的规则假设在此期间没有节点发生故障。为了确保 P + C,您将需要更加偏执...
还有几乎无限数量的“实施”黑客攻击 - 例如,如果存储层无法写入最小仲裁,则可能会导致调用失败,但即使在返回成功后也可能继续将更新传播到其他节点。或者,它可能会放松语义保证并将合并版本控制冲突的责任推到业务层(这就是亚马逊的 Dynamo 所做的)。
不同的数据子集可以有不同的保证(即单点故障对于关键数据可能是可以的,或者在最小数量的写入副本成功写入新版本之前阻塞您的写入请求可能是可以的)
还有更多要谈的,但如果这有帮助,请告诉我,如果您有任何后续问题,我们可以从那里继续......
[继续...]
解决 90% 情况的模式已经存在,但每个 NoSQL 解决方案都在不同的配置中应用它们。这些模式是诸如分区(基于稳定/散列或基于变量/查找)、冗余和复制、内存缓存、分布式算法(如 map/reduce)之类的东西。
当您深入研究这些模式时,底层算法也相当普遍:版本向量、merckle 树、DHT、gossip 协议等。
大多数 SQL 解决方案也是如此:它们都实现了索引(在底层使用 b 树),具有基于已知 CS 算法的相对智能的查询优化器,都使用内存缓存来减少磁盘 IO。差异主要在实施、管理经验、工具集支持等方面
不幸的是,我无法指出一些包含您需要知道的所有知识的中央知识库。一般来说,首先要问自己真正需要哪些 NoSQL 特性。这将指导您在键值存储、文档存储或列存储之间进行选择。(这些是 NoSQL 产品的 3 个主要类别)。从那里您可以开始比较各种实现。
[2011 年 4 月 14 日再次更新]
好的,这是真正证明赏金合理的部分。我刚刚在 NoSQL 系统上找到了以下 120 页的白皮书。这非常接近于我之前告诉你的“NoSQL 圣经”不存在。阅读并高兴:-)
NoSQL 数据库,Christof Strauch