Cassandra 修补列表时出现意外结果

Cassandra patching a List with unexpected result

我在 C* 中修补 LIST 时进行了观察,如果对此有合理的解释(忽略用例是否实际有效),希望有人能给我提示。

假设一个简单的 table 只有一个主键和一列列表类型。

CREATE TABLE ks.tbl(col_primary varchar,varchar_list list<varchar>,PRIMARY KEY(col_primary)) ;

向 table 添加一行,其中包含 table 中一些条目的列表。

INSERT INTO ks.tbl (col_primary,varchar_list) VALUES ('0815',['OlencUIkqqlVOFPiwsoEJM','JamilUOHIOXTWuGp','AbdulvZaeQDJOdu','GoldaGugnVNnbdSBpRpd','BrennaVvYuDyERsKvVW','FletcherpkkCYpEBket','DaytonglCSvswZQTEj','EdTUkTShUerYcfiSvCIH','LandenLTThnmlAAULJwdNwAma','IsabellelrDcMFHsyBGT','ArielOhIcLglehg','BellrtifChchjMZ','EmelieDdlViBlHUPQbxyUC']);

最后用以下条目更新行。

UPDATE ks.tbl SET varchar_list[1]=null,varchar_list[0]='MEGGCJOFic',varchar_list=varchar_list+['nwbaGsGbcd'] WHERE col_primary='0815' IF EXISTS;

列表的预期输出是(大部分时间实际上是)

['MEGGCJOFic', 'AbdulvZaeQDJOdu', 'GoldaGugnVNnbdSBpRpd', 'BrennaVvYuDyERsKvVW', 'FletcherpkkCYpEBket', 'DaytonglCSvswZQTEj', 'EdTUkTShUerYcfiSvCIH', 'LandenLTThnmlAAULJwdNwAma', 'IsabellelrDcMFHsyBGT', 'ArielOhIcLglehg', 'BellrtifChchjMZ', 'EmelieDdlViBlHUPQbxyUC', 'nwbaGsGbcd']

现在将其应用于具有两个数据中心(美国、欧盟)并使用 LOCAL_ONE 一致性级别并使用一个数据中心进行更新而另一个数据中心读取返回的令人惊讶的结果的设置:

 ['MEGGCJOFic', 'nwbaGsGbcd']

这正是发生变化的两个元素。一段时间后,列表自行解析并返回预期的内容。

但是怎么可能进入到上述那种中间状态呢?顺便说一句,同样的事情发生了。如果使用 MAPS 而不是 LIST。我确实知道数据在 C* 中是如何物理布局的,但是一个集群怎么可能只包含更新而不包含原始数据?

它阐述了 Cassandra (C*) 的实际工作原理及其内部架构。如果您更多地使用 C*,随着时间的推移,您将对它及其行为有更多的了解。有很多要解释的地方,但我会提到一些具体的要点,并尽量让你明白。

C* 如何存储数据

How is data updated

CAP 定理

Cassandra and CAP

Cassandra is typically classified as an AP system, meaning that availability and partition tolerance are generally considered to be more important than consistency in Cassandra. But Cassandra can be tuned with replication factor and consistency level to also meet Consistency.

C* 最终一致性:

Eventual consistency is a consistency model used in distributed computing to achieve high availability that informally guarantees that, if no new updates are made to a given data item, eventually all accesses to that item will return the last updated value.

C* 一致性级别:

RF -> 将保留多少份数据(行)。 (有多少服务器或节点将保持不变row/data)。

CL -> 确认需要多少个节点才能让客户端 know/inform write/read 操作成功。这意味着至少有 CL 提到的节点数(例如:如果 CL 为 2,则至少有 2 个节点)必须 acknowledge/ensure 它们已成功写入数据或从这些副本读取数据(等到所有必需的复制 return 结果到协调节点)并合并结果(如果不同节点对相同数据有不同的更新,则保留最新数据)并成功 return 结果到客户端。

由于您的 CL 是 LOCAL_ONE,只有来自本地 DC 的一个节点必须被确认,该副本可以保存回溯或旧数据,但最终它最终会得到更新。您可以使用 LOCAL_QUORUM 来获得一致的数据。对于集合,数据存储略有不同。

Using the Collections

These update operations are implemented internally without any read-before-write. Appending and prepending a new element to the list writes only the new element.

总结与可能性

C* 是一个 row-oriented 数据库。它存储映射到相应键的多行数据(列)。 C* 不会先读后写,因此数据库中可能存在同一行的多个版本。在请求读取时,协调器会合并它的不同版本,比较时间戳和 returning 最新版本。这取决于 CL 需要确认多少节点并将 returned 结果发送给协调器。如果您使用 CL(写入 CL + 读取 CL > RF),您将获得最新结果。

例如:假设您有一个列表 [1,2,3]。现在想追加[4]。您的预期结果是 [1,2,3,4]。当您使用 LOCAL_ONE 并且协调器节点命中仅具有此新更新的副本时,因此 returning 此结果。

如果在写操作后立即读取,也会得到不一致的结果。下次阅读时,您将获得 updated/latest 合并行。

在分布式系统中,这些是常见的场景,对于 RDMS 架构来说是非常不寻常的。

一些链接:

也可以看到C*读写路径

The write path to compaction
How is data read?

Understanding How CQL3 Maps to Cassandra's Internal Data Structure