cassandra lwt写入产生不正确的数据

cvxl0en2  于 2021-06-13  发布在  Cassandra
关注(0)|答案(1)|浏览(350)

我们有一个3节点的cassandra集群(单个dc)和一个表,这些表可以被运行在不同节点上的应用程序访问(读/写)。
在重载情况下,当应用程序的两个示例都试图更新相同的用户条目(例如add attribute)时,我们从 app1 (正在运行) node1 成功-即。 ResultSet#wasApplied 退货 true ). 但是,什么时候 app2 (开 node2 读取数据之前,它正在获取过时的数据 app1 更新了它)。
我想知道为什么会发生这种情况,因为具有串行一致性的ltw应该可以防止这种类型的不一致。非常感谢您的帮助!
提前谢谢!
示例:(基于应用程序日志)
最初,用户具有 A 有价值的 1 两者 app1 以及 app2 正在添加新属性; app1 添加 B:2 以及 app2 添加
C:3 app1 将正确的数据读入内存,添加新属性 B 并成功地给Cassandra写信。日志显示最终的属性列表 A:1 以及 B:2 元组。 app2 读取数据,但只看到 A:1 (从 app1 以及 app2 只有2ms;因此可能以任何顺序发生)。
一次 app2 的写入已完成,结束状态只有 A:1 以及 C:2 ,这是不正确的。
更多信息
对表执行读写操作的(准备好的语句)具有以下特征:
write是lwt(如果存在userid,则为on)
在一致性级别为local\u quorum的情况下执行对表的写入
表上的读取以本地\u serial的一致性级别执行
这张table看起来像:

CREATE TABLE my_table(userid ascii, username ascii, attributes map);

更新属性Map时,应用程序内的逻辑是:

User user = dao.getUser(userid);
user.addNewAttribute("key", "value");
dao.update(user);
lnxxn5zx

lnxxn5zx1#

因为读/写操作发生在两个不同的节点上,所以我们没有在应用程序级别同步操作。 app2 他在做那件事 read 之前 app1 开始写了。因此, app1 获取过时数据(不是过时数据)。这个 update 操作设置整个Map,而不是在Map中添加/删除元素。
我们已经改变了逻辑,所以add/remove操作现在分别执行add(和remove)而不是“read and then set”。
新的prepared语句类似于:

QueryBuilder.update("my_table")
            .onlyIf(QueryBuilder.eq("username", QueryBuilder.bindMarker()))
            .with(QueryBuilder.putAll("attributes", QueryBuilder.bindMarker()))
            .and(QueryBuilder.set("lastUpdatedOn", QueryBuilder.bindMarker()))
            .where(QueryBuilder.eq("userid", QueryBuilder.bindMarker()));

在使用 set

相关问题