如何在Cassandra中以独特和原子的方式在多个表中实现插入?

时间:2016-01-15 17:52:30

标签: transactions cassandra

我有一个数据模型,其中域对象有两个必须都是唯一的字段,并且对象必须可以通过两个独立获取。 其中一个是随机生成的,因此我们可以假设没有可能的碰撞。 另一个是用户选择的。以下是我提出的建议:

CREATE TABLE object_primary (
    generated_value text PRIMARY KEY,
    data blob
);

CREATE TABLE object_unique_index (
    user_value text PRIMARY KEY,
    generated_value text
);

这里我使用object_unique_index作为主表和资源锁的索引,其中资源是用户选择的全局唯一值。

初步想法:

  • 插入object_unique_index必须使用IF NOT EXISTS。因此我不能使用批次。
  • 插入到object_primary并不是因为生成器已经保证了唯一性。然后,我可以使用自定义TIMESTAMP,避免创建回读。
  • 如果第一次插入失败,我不应该继续第二次插入。
  • 如果第二个插入失败,我应该回滚第一个插入。
  • 系统不应该处于任何一列中没有另一列的行中的状态。
  • 我愿意在回滚期间忽略错误,并将清理委派给外部(可能是手动)流程。

似乎很清楚如何继续,但我正在努力解释非条件更新的某些错误情况。所有现有的描述都假设您不关心最终结果,并且稍后会再次尝试写入。

UnavailableException:没有足够的节点用于法定人数,但当他们重新联机时,保存的提示将重新运行写入。这是否意味着最终状态将是写入成功?如果是这样,什么读一致性水平允许我看到它?如果没有,我怎么知道最终状态是什么?

CassandraWriteTimeoutException:有足够的节点用于法定人数,但有些节点没有及时回复。据我所知,这只是UnavailableException的一个更模糊的版本。它应该如何处理有什么不同吗?

我的很多困惑来自于相互矛盾的陈述here

  

协调员可以将结果强制置于更新前或更新后状态。

     

[...]

     

协调器在本地存储更新,并在恢复时将其重新发送到失败的副本,从而迫使它进入客户端最初想要的更新后状态

那么什么时候迫使它进入更新前状态?如何判断它是在更新后(因此我忽略它)还是预更新(因此我回滚第一个插入)?

有没有办法解决这个问题而不要求所有插入都是有条件的,从而增加了更多的性能损失并且失去了设置写时间的能力?

1 个答案:

答案 0 :(得分:0)

tl; William Price's answer

的博士

只有无条件插入才有任何疑问,因此切换操作顺序并假设任何异常都失败。 只要你永远不会发出一个可能失败的系统生成的id,它就永远不会被使用,所以相应的用户生成的值不是唯一的并不重要。

  1. 插入由系统生成的唯一值键入的记录,而不必担心唯一性。
  2. 如有任何错误,请删除一致性级别为ANY的记录,并使整个操作失败。
  3. 在给定用户生成的值作为键的情况下插入指向前一个ID的记录,条件是IF NOT EXISTS。
  4. 如前所述,确定它是否实际成功,如果不是,则执行步骤2中先前插入的相同回滚
  5. 实施定期的后台清理任务以查找并修复不一致。
  6. 所以不必担心解释含糊不清的异常。