【问题标题】:Handling uniqueness concurrently in event-based systems在基于事件的系统中同时处理唯一性
【发布时间】:2013-05-01 23:17:27
【问题描述】:

在我目前正在进行的项目中,我们面临着我们所说的挑战。挑战有成员参与者。成员是有权访问挑战的每个人(可以是单个用户或用户组),参与者会跟踪每个用户的参与统计信息。

每次添加新的挑战成员时,都会重新计算挑战参与者。这基于事件发生,因此挑战成员会触发created 事件,挑战参与者会监听该事件。

当同时创建两个挑战成员时会出现问题,这意味着该事件也被触发了两次,并且代码的两次执行同​​时运行。举例说明:

challenge.getMembers();
challenge.getParticipants();

// calculations

foreach member not in participants, create participant

如上所述,当上述代码同时运行时会出现问题,更具体地说,当第二次执行在第一次创建参与者条目之前到达getParticipants 时丢失了参与者条目。两次执行都看到一些参与者丢失,并创建它们。这意味着我们现在有一些用户的挑战参与者重复条目。

目前,我们对这个问题的解决方案是在挑战参与者的challenge_id, user_id 上有一个唯一索引。但是在违反约束时忽略错误确实感觉有点脏。这也使得检查其他 SQL 错误变得更加困难,因为所有错误都只是传递给回调,然后我们必须检查错误字符串的内容以查看它是否是我们喜欢的错误(违反唯一性),或者一个我们不喜欢的错误(例如语法错误),应该处理。

此代码将在多个服务器上运行,因此即使使用 mutice,我们也不能保证代码不会同时运行。我们也不介意它同时运行不同的挑战,只要它不会同时运行相同的挑战。有人对处理这种类型的并发合并有什么建议吗?

【问题讨论】:

  • 简单的解决方案(但可能效率不高)是在您的数据库中为每个挑战维护一个锁,或者为您的所有服务器都可访问的某种缓存/共享内存层。然而,更大的问题在于您的设计;为什么在添加新成员时创建所有参与者?为什么在添加成员时不将每个成员创建为参与者?此外,即使您认为这种情况不应该发生,您也应该对您的数据库有独特的约束。这是一个很好的后备方案,以防您的代码不如您想象的那么好。
  • 对于挑战、参与者和成员,您的架构是什么样的?

标签: javascript mysql node.js mutual-exclusion


【解决方案1】:

既然您说您不介意针对不同的挑战同时运行代码,您可以在挑战表中有一个包含状态的列。然后你会发出UPDATE challenges SET state = {locked} WHERE id = {id} AND state = {unlocked}。如果此查询成功并且受影响的行等于 1,那么您可以继续更新参与者并在之后解锁挑战。如果查询不影响任何行,则挑战可能正在由其他执行线程更新,因此您可能希望跳过此步骤或安排稍后重新运行。

如果你走这条路,那么你需要小心解锁你的挑战,并做一些事情来防止它们在更新过程中一个线程崩溃并且没有解锁它的挑战时被卡住。例如,您可以拥有state = {thread id},然后您可以检测哪些线程已死亡并解锁它们的挑战。

【讨论】:

    猜你喜欢
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多