Cassandra

时间:2016-07-08 20:56:31

标签: apache-spark cassandra

我在Cassandra有一个表,它存储了csv文件的版本。它使用具有唯一ID的主键(版本(分区键))和行号(聚类键)。当我插入新版本时,我首先在我要插入的分区键上执行删除语句,以清除任何不完整的数据。然后插入数据。

现在问题就出现了。即使删除和后续插入在应用程序中彼此同步执行,似乎在Cassandra中仍然存在某种程度的并发性,因为当我之后阅读时,插入的行偶尔会丢失 - 类似于3次中的1次。以下是一些事实:

  • Cassandra 3.0
  • 一致性ALL(R + W)
  • 使用Java驱动程序删除
  • 使用Spark-Cassandra连接器插入
  • 节点数:2
  • 复制因子:2

我执行的删除语句如下所示:

“DELETE FROM myTable WHERE version ='id'”

如果我省略它,问题就会消失。如果我在删除和插入之间插入延迟,则问题会减少(缺少的行数减少)。最初我使用限制性较低的一致性级别,我确信这是问题,但它并没有影响问题。我的假设是,由于某种原因,删除语句是异步发送到副本的,尽管ALL的一致性水平,但我不明白为什么会出现这种情况或如何避免它。

2 个答案:

答案 0 :(得分:1)

默认情况下,所有突变都会获得该写入协调器的写入时间。来自文档

  

TIMESTAMP:设置操作的时间戳。 如果没有指定,   协调员将使用当前时间(以微秒为单位)   语句执行的开始作为时间戳。这通常是一个   合适的默认值。

http://cassandra.apache.org/doc/cql3/CQL.html

由于不同突变的协调员可能不同,协调员之间的时钟偏差最终会导致一台机器相对于另一台机器发生突变。

由于写入时间控制C *历史记录,这意味着您可以拥有一个同步插入和删除的驱动程序,但根据协调程序,删除可以在插入之前“发生”。

实施例

想象一下,两个节点A和B,B在A后面以5秒的时钟偏差运行。

在时间0:您将数据插入群集,并选择A作为协调员。突变到达A和A分配时间戳(0)

现在集群中有一条记录

INSERT VALUE AT TIME 0

两个节点都包含此消息,请求返回确认写入成功。

在时间2:您对先前插入的数据发出删除,并选择B作为协调员。 B指定的时间戳为(-3),因为它比A中的时间落后5秒钟。这意味着我们最终会得到一个像

这样的语句。
DELETE VALUE AT TIME -3

我们承认所有节点都已收到此记录。

现在全球一致的时间表是

DELETE VALUE AT TIME -3
INSERT VALUE AT TIME 0

由于插入发生在删除后,该值仍然存在。

答案 1 :(得分:0)

我遇到了类似的问题,我通过为INSERT和DELETE请求启用Light-Weight-Transaction来修复它(实际上对于所有查询,包括UPDATE)。它将确保通过一个“线程”序列化对此分区的所有查询,因此DELETE不会覆盖INSERT。例如(假设instance_id是主键):

INSERT INTO myTable (instance_id, instance_version, data) VALUES ('myinstance', 0, 'some-data') IF NOT EXISTS;
UPDATE myTable SET instance_version=1, data='some-updated-data' WHERE instance_id='myinstance' IF instance_version=0;
UPDATE myTable SET instance_version=2, data='again-some-updated-data' WHERE instance_id='myinstance' IF instance_version=1;
DELETE FROM myTable WHERE instance_id='myinstance' IF instance_version=2
//or:
DELETE FROM myTable WHERE instance_id='myinstance' IF EXISTS

IF子句为每一行启用light-wight-transactions,因此所有这些都是序列化的。警告:LWT比普通调用更昂贵,但有时需要它们,就像这个并发问题一样。