Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark Cassandra中的分区删除/插入并发问题_Apache Spark_Cassandra - Fatal编程技术网

Apache spark Cassandra中的分区删除/插入并发问题

Apache spark Cassandra中的分区删除/插入并发问题,apache-spark,cassandra,Apache Spark,Cassandra,我在Cassandra中有一个存储csv文件版本的表。它使用一个主键,该主键具有唯一的版本id(分区键)和行号(集群键)。当我插入一个新版本时,我首先对我要插入的分区键执行delete语句,以清除任何不完整的数据。然后插入数据 现在问题来了。即使删除和后续插入在应用程序中同步执行,但Cassandra中似乎仍然存在某种程度的并发性,因为当我随后读取时,插入中的行偶尔会丢失—大约是3次中的1次。以下是一些事实: 卡桑德拉3.0 一致性全部(R+W) 使用Java驱动程序删除 使用火花卡桑德拉接头

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

现在问题来了。即使删除和后续插入在应用程序中同步执行,但Cassandra中似乎仍然存在某种程度的并发性,因为当我随后读取时,插入中的行偶尔会丢失—大约是3次中的1次。以下是一些事实:

  • 卡桑德拉3.0
  • 一致性全部(R+W)
  • 使用Java驱动程序删除
  • 使用火花卡桑德拉接头插入
  • 节点数:2
  • 复制因子:2
我执行的delete语句如下所示:

“从版本为'id'的myTable中删除”


如果我省略它,问题就消失了。如果我在delete和insert之间插入一个延迟,问题就会减少(缺少的行更少)。起初,我使用了一个限制较少的一致性级别,我确信这就是问题所在,但这并没有影响问题。我的假设是,出于某种原因,不管ALL的一致性级别如何,delete语句都会异步发送到副本,但我不明白为什么会出现这种情况,也不知道如何避免这种情况。

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

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

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

由于写入时间控制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

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

我遇到了类似的问题,我通过为插入和删除请求(实际上包括更新的所有查询)启用轻量级事务解决了这个问题。它将确保对该分区的所有查询都通过一个“线程”序列化,因此删除wan不会覆盖INSERT。例如(假设实例_id是主键):


IF子句为每一行启用轻量级事务,因此所有这些事务都被序列化。警告:LWT比普通调用更昂贵,但有时需要它们,例如在这种并发问题的情况下。

一般来说,C*是最终一致的数据库。这意味着很多不同的事情,但你不能依赖操作命令。切勿尝试在一行中执行某些相关操作。最好重新设计您的模式并改变您的方法。如果您发布您的数据模型并解释您希望实现的目标,我们可能会在这方面帮助您。据我所知,在您的情况下,最好在客户端检索数据后过滤旧版本。我的期望是,最终的一致性程度将受到我选择的一致性级别的限制。现在,为了简单起见,我们在原型中使用ALL,因为它不是瓶颈。如果我不能依赖于以最保守的一致性级别顺序完成的操作序列,那么我可以将一致性级别用于什么?ALL保证所有节点都对查询有一致意见(因此,在单个查询之后,所有节点都将具有相同版本的受影响行)但不能保证任何关于查询顺序的事情。我严格建议您重新设计您的方法,停止将C*视为关系数据库。这是行不通的。根据文档,ALL将保证它写入所有节点上的提交日志,这将保证给定相关时间戳的顺序(尽管Russell在下面关于这些时间戳的分配有一个很好的观点,但这可以在查询中解决)。是的,但你不能保证加工订单。。。无论如何,执行所有一致性的写入都是一个坏主意,除非您的写入量非常小。您可以通过重新设计您的方法来解决问题并提高效率。但让我惊讶的是,鉴于删除是以一致性方式执行的,我希望它在返回调用方之前确认对所有副本的删除。出现此问题是否是因为它在返回之前不在内部执行DELETE,而只使用时间戳记录它,然后在下一个insert语句中出现顺序错误?我相信插入是成批进行的,因此如果每个批都有自己的时间戳,这将与我的观察结果很匹配。我可以看到,您支持在基于rdd的连接器API上设置写入时间,但该功能似乎已从基于数据帧的API中消失。这有什么原因吗
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