您能解释一下为什么即使使用基于定额的读写时Cassandra还是不能线性化吗?
线性可定义为
如果操作B在成功完成操作A之后开始,则操作B必须看到系统处于与操作A完成时相同的状态,或者是更新的状态。
答案 0 :(得分:2)
编辑:事后看来,这不是最好的解释。我建议阅读下面的Anurag答案,该答案更为简洁。
由于正常的Cassandra操作无法观察到其正在改变的现有状态,因此仅将仲裁一致性视为“可线性化”。
例如,如果要调整银行帐户的余额,则需要知道当前余额才能进行调整。考虑执行以下操作的客户端:
A. SELECT balance FROM account WHERE id='x' (assume this returns 5.12)
B. UPDATE account SET balance=4.12 WHERE id='x' (subtract 1$ from balance)
问题是,从Cassandra的角度来看,操作B
无法有效地“看到” A
,因为它没有考虑数据的现有状态或可能正在发生的任何其他操作对于这个问题。提交B
期间,另一个客户可能正在更新同一帐户的余额。
Lightweight Transactions in Cassandra 2.0描述了轻量级事务如何通过提供可确保对给定分区按顺序执行操作且不会被其他中断中断的构造来提供“线性化一致性”。因此,您现在可以代替我之前的示例:
A. SELECT balance FROM account WHERE id='x' (assume this returns 5.12)
B. UPDATE account SET balance=4.12 WHERE id='x' IF balance=5.12
使用IF balance=5.12
指示Cassandra开始进行轻量级交易,该交易使用paxos consesus protocol进行领导选举并确保顺序进行操作。如果余额状态不符合条件,则将不应用更新(在成功响应中带有was_applied
布尔列的情况下指示)。如果C *在某个超时时间内(由于争用或其他一些因素)无法实现此目标,则该操作将失败,将不被应用,并且客户端将面临超时。
答案 1 :(得分:2)
摘要: 在Cassandra中写可能不会感到原子。有些节点的写入速度要快于其他节点,因此即使我们依赖仲裁,结果也取决于返回值的节点集以及该点持有的值。
此外,要解释线性化定义,以粗体显示
如果在操作A成功完成之后开始了操作B,则 操作B必须看到系统处于与开启状态相同的状态 完成操作A,或状态为新的(但再也不会恢复为旧状态)。
从Martin Klepmann的“数据密集型应用程序”书中复制
可线性化和仲裁 直观地,似乎严格的法定读写应该在Dynamo样式的模型中线性化。但是,当我们具有可变的网络延迟时,就有可能出现竞态条件,如图9-6所示。
在图9-6中,x的初始值为0,并且写入器客户端通过将写入发送到所有三个副本(n = 3,w = 3)将x更新为1。同时,客户端A从两个节点的定额(r = 2)中读取,并在其中一个节点上看到新值1。同样在写操作的同时,客户端B从两个节点的不同仲裁读取数据,并从两个节点取回旧值0。
满足仲裁条件(w + r> n),但是此执行还是不可线性化的:B的请求在A的请求完成后开始,但是B返回旧值,而A返回新值。 (这再次是图9-1中的Alice和Bob情况。)
有趣的是,可以以降低性能为代价使Dynamo样式仲裁线性化:在将结果返回给应用程序之前,读取器必须同步执行读取修复(请参见第178页的“读取修复和反熵”)[23] ],而写者必须先发送一定数量的节点的最新状态,然后再发送其写[24、25]。但是,由于性能下降,Riak不执行同步读取修复[26]。 Cassandra确实在仲裁读取后等待读取修复完成[27],但是如果使用同一笔最后一次解决冲突的冲突解决方案,如果对同一密钥进行多次并发写入,它将失去线性化能力。
此外,只能以这种方式实现线性化的读写操作。线性化比较设置操作无法执行,因为它需要共识算法[28]。
总而言之,最安全的假设是具有Dynamo样式复制的无领导者系统不提供线性化功能。
关于线性化与串行化的更多解释:
答案 2 :(得分:1)
根据您的定义,当Cassandra的读写设置设置为quorum时,就可以线性化。
old docs on serial consistency
但是,似乎无条件更新才是“破坏”线性化的能力,需要在驱动程序级别禁用这些更新,才能将Cassandra标记为“ linearizable”。
因此可以用Cassandra实现线性化。但是,cassandra本身不会强制线性化。