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
如何使用cassandra更新处理竞争条件?_Cassandra_Race Condition_Cassandra 2.0 - Fatal编程技术网

如何使用cassandra更新处理竞争条件?

如何使用cassandra更新处理竞争条件?,cassandra,race-condition,cassandra-2.0,Cassandra,Race Condition,Cassandra 2.0,我在学卡桑德拉。我正在为特定用例建模cassandra表。下面描述的用例- 用户可以写一篇文章。 其他用户可以回复帖子。 用户还可以“向上投票”或“向下投票”帖子。 用户按日期、向上投票或向下投票对帖子进行排序 这是我的表格定义- CREATE TABLE post.comments_by_post ( postid text, parentpostid text, createdon bigint, username text, userid text, displayname text, u

我在学卡桑德拉。我正在为特定用例建模cassandra表。下面描述的用例-

用户可以写一篇文章。 其他用户可以回复帖子。 用户还可以“向上投票”或“向下投票”帖子。 用户按日期、向上投票或向下投票对帖子进行排序

这是我的表格定义-

CREATE TABLE post.comments_by_post (
postid text,
parentpostid text,
createdon bigint,
username text,
userid text,
displayname text,
upvotes int,
downvotes int,
comment text,
PRIMARY KEY ((postid, parentpostid), createdon)
) WITH CLUSTERING ORDER BY (createdon DESC);
要增加“upvote”,我有一个更新查询-

UPDATE post.comments_by_post SET upvotes = incrementedValue where postid=1 and parentpostid = 2 ;
递增值是在上一个值中加1计算得出的

incrementedValue=previousValue+1

我的问题是,如果我必须根据表中的前一个值计算增量,它将导致竞争条件和数据损坏

我们有更好的办法吗


我知道cassandra有计数器列定义类型,可以用于此类增量值,但它需要额外的表。计数器列不能与不是主键一部分的普通列一起使用。

发生并发更新时,您将丢失一些更新。
例如,用户A读取当前值,比如10。同时,另一个用户B也读取当前值,他将得到10。然后用户使用新值11发出更新请求。然后,用户B也将使用新值11发出更新请求。因此,您丢失了用户A更新

柜台是您的最佳选择。

计数器是一个特殊的列,用于存储增量更改的数字。Cassandra计数器在Cassandra 2.1中重新设计,以缓解一些困难。阅读以了解计数器中所做的改进

您可以创建如下计数器表:

CREATE TABLE vote_counter (
   postid text,
   parentpostid text,
   upvotes counter,
   downvotes counter,
   PRIMARY KEY((postid,parentpostid))
)
UPDATE vote_counter SET upvotes = upvotes + 1 WHERE postid = ? AND parentpostid = ?
UPDATE vote_counter SET upvotes = upvotes - 1 WHERE postid = ? AND parentpostid = ?
UPDATE vote_counter SET downvotes = downvotes + 1 WHERE postid = ? AND parentpostid = ?
UPDATE vote_counter SET downvotes = downvotes - 1 WHERE postid = ? AND parentpostid = ?
现在您可以像这样进行查询:

CREATE TABLE vote_counter (
   postid text,
   parentpostid text,
   upvotes counter,
   downvotes counter,
   PRIMARY KEY((postid,parentpostid))
)
UPDATE vote_counter SET upvotes = upvotes + 1 WHERE postid = ? AND parentpostid = ?
UPDATE vote_counter SET upvotes = upvotes - 1 WHERE postid = ? AND parentpostid = ?
UPDATE vote_counter SET downvotes = downvotes + 1 WHERE postid = ? AND parentpostid = ?
UPDATE vote_counter SET downvotes = downvotes - 1 WHERE postid = ? AND parentpostid = ?
根据您的描述:

…用户按日期或向上投票或向下投票对帖子进行排序

您的目标是三个用例,但是表定义只解决第一个用例(按日期)。为了解决另外两个问题,您需要创建两个表,分别使用
upvoces
downvoces
字段作为集群键,并努力保持所有三个表的同步:

CREATE TABLE post.comments_by_post (
    postid text,
    parentpostid text,
    createdon bigint,
    username text,
    userid text,
    displayname text,
    upvotes int,
    downvotes int,
    comment text,
    PRIMARY KEY ((postid, parentpostid), upvotes) 
) WITH CLUSTERING ORDER BY (createdon DESC);
如果升级C*并使用3.0,则可以节省大量工作并创建一个新的应用程序

回到您的并发性问题,在分布式环境中计算是非常困难的。根据您的要求,我建议您两种可能的解决方案

1) 你不需要精确(你可以容忍计数过多/不足)。在这种情况下,我建议您使用一个新的Cassandra计数器表来存储您的计数器。这种方法的主要缺点是您实际上失去了(从应用程序的角度)按顺序获取结果的能力,因此您需要在应用程序级别应用排序。您还可以保存上述其他两个表,因为计数器保留在另一个表中


2) 你需要精确。在这种情况下,您需要序列化对每个post计数器的访问。您可以通过保留一个将要更新或最近已更新的post计数器的小缓存来实现这一点,并在每次需要更新时在应用程序级别获取每个项的锁。64k个员额就足够了。现在您知道,对于每个帖子,您都会按顺序执行更新。这不会出错,因为您不应用全局锁,只应用本地锁。您仍然需要使用C*2.0的三个表,或者使用C*3.0的一个+物化视图。

下表和二级索引将允许您在没有计数器表和任何锁的情况下实现计数:

CREATE TABLE votes_by_comment (
   postid text,
   parentpostid text,
   userid text,
   vote text, //can be 'up' or 'down'
PRIMARY KEY (( postid, parentpostid ), userid))

CREATE INDEX ON votes_by_comment (vote);
当用户进行“向上投票”时:

INSERT INTO votes_by_comment (postid, parentpostid, userid, vote) VALUES ('comment1', 'post1', 'user1', 'up');
当用户进行“否决投票”时:

INSERT INTO votes_by_comment (postid, parentpostid, userid, vote) VALUES ('comment1', 'post1', 'user1', 'down');
userid
as集群列将允许它避免竞争条件并限制一个用户的多次投票

计算选票:

SELECT count(*) from votes_by_comment WHERE postid='comment1' AND parentpostid='post1' and vote='up';
二级索引将允许它执行按
投票
值选择,因为二级索引选择将在分区键内执行,所以它将具有良好的性能


但是这种方法不允许您在Cassandra端实现投票排序,它应该在应用程序端实现。

谢谢Ashraful。创建另一个表将打破数据建模的规则。与读取数据的单个查询类似,插入记录将解决所有与竞争条件有关的问题。