Concurrency Cassandra,并发写入的模式和流程设计

Concurrency Cassandra,并发写入的模式和流程设计,concurrency,cassandra,schema,Concurrency,Cassandra,Schema,这是一个冗长的问题。它是关于卡桑德拉模式设计的。我来这里是为了从你们尊敬的专家那里得到我正在研究的一个用例的信息。欢迎所有意见、建议和批评。我的问题来了 我们想收集用户对我们即将发表的一些论文的评论。对于每一篇论文,我们寻求3个评论。但我们会向3*2=6个用户发出评论邀请。所有6个用户都可以向我们的系统提交他们的评论,但只计算前3个;前三名评论员将获得工作奖励 在我们的Cassandra数据库中,有三个表:用户、论文和评论。用户表和纸质表很简单:每个用户对应于用户表中具有唯一用户ID的一行;同样

这是一个冗长的问题。它是关于卡桑德拉模式设计的。我来这里是为了从你们尊敬的专家那里得到我正在研究的一个用例的信息。欢迎所有意见、建议和批评。我的问题来了

我们想收集用户对我们即将发表的一些论文的评论。对于每一篇论文,我们寻求3个评论。但我们会向3*2=6个用户发出评论邀请。所有6个用户都可以向我们的系统提交他们的评论,但只计算前3个;前三名评论员将获得工作奖励

在我们的Cassandra数据库中,有三个表:用户、论文和评论。用户表和纸质表很简单:每个用户对应于用户表中具有唯一用户ID的一行;同样,每张纸张在纸张表中都有一个唯一的纸张ID

查看表如下所示

CREATE TABLE REVIEW(
    PAPER_ID uuid,
    USER_ID uuid,
    REVIEW_CONTENT text,
    PRIMARY KEY(PAPER_ID, USER_ID)
    );
----------------------------------------------------
PAPER_ID      |  USER_ID        |  REVIEW_CONTENT  |
----------------------------------------------------
 P1           |  U1             |      null        |
----------------------------------------------------
 P1           |  U2             |      null        |
----------------------------------------------------
 P1           |  U3             |      null        |
----------------------------------------------------
 P1           |  U4             |      null        |
----------------------------------------------------
 P1           |  U5             |      null        |
----------------------------------------------------
 P1           |  U6             | This paper   ... |
 ---------------------------------------------------
 ...          |  ...            | ...              |
我们使用PAPER_ID作为评审表的分区键,以便给定论文的所有评审都存储在单个Cassandra行中。对于我们拥有的每一篇论文,我们会挑选6个用户,在评论表中插入6个条目,并向这些用户发送6个邀请。因此,对于论文“P1”,评审表中有6个条目如下所示

CREATE TABLE REVIEW(
    PAPER_ID uuid,
    USER_ID uuid,
    REVIEW_CONTENT text,
    PRIMARY KEY(PAPER_ID, USER_ID)
    );
----------------------------------------------------
PAPER_ID      |  USER_ID        |  REVIEW_CONTENT  |
----------------------------------------------------
 P1           |  U1             |      null        |
----------------------------------------------------
 P1           |  U2             |      null        |
----------------------------------------------------
 P1           |  U3             |      null        |
----------------------------------------------------
 P1           |  U4             |      null        |
----------------------------------------------------
 P1           |  U5             |      null        |
----------------------------------------------------
 P1           |  U6             | This paper   ... |
 ---------------------------------------------------
 ...          |  ...            | ...              |
用户使用http通过web浏览器提交评论。在后端,我们使用以下流程来处理提交的评论(以论文“P1”为例):

  • 使用分区键“P1”从检查表中取出所有6个条目
  • 在REVIEW_CONTENT列中找出这6个条目中有多少条具有非空值(非空值表示相应的用户已经提交了他的审阅。例如,在上表中,用户“U6”已经提交了审阅,而其他5条尚未提交)
  • 如果这个数字>=3,我们已经有足够的评论了,返回给当前的评论人,并显示一条消息,如“谢谢,我们已经有足够的评论了。”
  • 如果此数字小于2,则将当前审核保存到审核表中的相应条目中,返回给审核人,并显示“您的审核已被接受”这样的消息(例如,如果当前审核人为“U1”,则用当前审核内容填写“P1,U1”条目的审核内容列。)
  • 如果这个数字=2,这是最复杂的情况,因为当前提交的是我们将接受的最后一份。在这种情况下,我们首先将当前审核保存到审核表中,然后找到提交审核的所有三个用户(包括当前用户)的ID,将他们的ID记录到事务表中,以便稍后向他们支付奖励 但这一过程并不奏效。问题是它不能正确处理并发提交。考虑下面的情况:两个用户已经提交了他们的评论,同时3个其他用户通过上面显示的三个并发过程提交他们的评论。在步骤5中,三个提交人中的每一个都会认为自己是第三个也是最后一个提交人,并在事务表中插入新记录。这导致了重复计算:单个用户可能会因为提交的同一审查而获得不止一次的奖励

    这个过程的另一个问题是,它可能永远不会达到步骤5。假设审查表中没有提交,4个用户同时提交审查。他们都在第4步保存了评论。在此之后,以后的提交人将始终被拒绝,因为已经有4个接受的审查。但由于我们从未达到第5步,因此不会将任何ID记录到事务表中,用户也不会获得任何奖励


    所以我的问题来了:我应该如何使用Cassandra作为后端数据库来处理我的用例?卡桑德拉会帮忙吗?如果是,怎么做?我还没有考虑过如何使用计数器,但这个博客()警告说Cassandra计数器不安全(引用“因此,在网络分区期间,Cassandra计数器将在很大范围内超过或低于计数。”)Cassandra的比较和设置(CAS)功能会有帮助吗?如果是,怎么做?保存博客再次警告说,“卡桑德拉轻量级事务甚至不接近正确”。

    < P>而不是在评论表中创建空条目,我会考虑将其保留为空,并仅在提交评论时填写它。要处理并发性,请添加timeuuid字段作为排序键:

    CREATE TABLE review(
      paper_id uuid,
      submission_time timeuuid,
      user_id uuid,
      content text,
      PRIMARY KEY (paper_id, submission_time)
    );
    
    当用户提交时,将条目添加到表中。然后在写入成功后,查询表(仅在paper_id上),并确定用户的id是否是前三个id之一。相应地响应用户。由于您只需要一小部分审阅者,因此获取所有审阅的额外开销应该是最小的(特别是因为您不需要在查询中包含内容列)


    如果您需要跟踪谁在审阅论文,请在论文表中添加一组用户ID,并在其中写入六个用户ID。

    我喜欢您的解决方案。似乎Cassandra的一个通用设计原则是,总是在表后面追加内容,尽量不更新它。一个简短的问题:如果一个审阅者X成功提交了他的审阅,但当下一个审阅者Y获取所有审阅时,由于网络延迟,X新提交的审阅不包括在内,会发生什么情况?我想这可能会发生。ConsistencyLevel.ALL会有帮助吗?因为您的用例需要这种级别的一致性,我建议您在仲裁时进行书写和阅读。假设您有3个或更多副本(标准),这将为您提供完美的一致性,而不会有所有副本的脆弱性。生成时间戳的位置也有影响。在这种情况下,最好使用CQL的函数。考虑到这两个因素(以及NTP),我认为您应该非常接近保证的一致性水平。