如何在NoSQL中进行原子性、多记录和相互依赖的操作?

3
我最初熟悉的是关系型数据存储。我现在正在研究NoSQL并尝试了解其用例。以下是最近一直困扰着我的问题。
如何使用典型的NoSQL产品执行以下操作?
- 读取多个输入 - 为它们计算新值(每个输出都依赖于所有输入) - 将值写回
过去处理其他问题的示例是,您有一个带有各种用户帐户的Web游戏。用户可以互相发起攻击,攻击公式是复杂的黑盒游戏逻辑,根据两个输入和随机性确定相互结果。您需要强制执行攻击以原子方式发生,并且输入反映了序列化后的攻击序列中的一致时间点,输出也是如此。
重要的是:
- 所有输出以某种我们无法分解的复杂方式依赖于所有输入(即我们不能将其转换为标准的银行账户到事务分类帐示例,我们不能仅使用先前记录日志等)。 - 换句话说,我们不是在做P1 + = $10,P2- = $10这样的操作。 - 更像是我们正在(基本上是一些复杂/不可约的东西)进行[P1,P2] =(sha1(P1 + P2),sha1(P1-P2))的操作,其中我们希望获得P1和P2的值的一致快照[并不是说该行是实际游戏的好示例]。 - 输入将是小记录子集的任意选择,因此我们不能只使用复合记录。 - 外部观察者在所有操作之前或之后看到统一/一致的状态,但不在其间。
我们遇到了这个问题。我们实际上正在使用关系型数据库,但我们没有像应该那样使用其事务功能。结果,在线玩家互相攻击时往往会生成错误的结果,并为攻击者生成虚假资源。
在关系模型中,我会使用事务来完成这项工作。想想看,这可能是事务的标准示例。
如何在NoSQL中实现这一点?
以下是我在SO和其他地方看到的答案,我认为它们不适用于此特定实例:
- 忽略竞态条件的可能性 - 重新设计游戏,使其不成问题 - 使用数据存储实现2PC、面包店算法等 - 使用外部锁定服务
如果您认为它们中的任何一个或全部都是好的解决方案,请告诉我如何以及为什么。
我希望能够获得有关如何在实践中实现此类内容的指南。
谢谢!

3
由于NoSQL涵盖了许多不同的产品/技术,因此我认为答案将取决于您想要使用哪种NoSQL解决方案。 我不认为会有一个适用于所有现有NoSQL解决方案的最佳答案。 您有特定的NoSQL解决方案吗? - Laurent Parenteau
我看了几个,意识到它们彼此非常不同。但我注意到一个共同点是,似乎没有一个提供像这样的操作的通用支持。如果需要具体示例,让我们问一下:在MongoDB中如何做到这一点?或者,在CouchDB中如何做到这一点? - Ming
1
一些NoSQL解决方案(如GT.M)提供事务处理。因此,您使用事务的“关系模型”解决方案将在那里起作用。现在您特别询问MongoDB或CouchDB,让我们看看这些解决方案的专家有什么要说的。 - Laurent Parenteau
1个回答

2

关于这个主题,你需要了解有关MongoDB的两件事:

  • 原子性的单位是单个文档。
  • 没有事务,但可以模拟它们。

记住,这种事情不是MongoDB的强项,而且你自己也指出了,它本质上就是一个事务。

然而,如果你要尝试对其进行建模,可以先创建一个攻击集合,其中文档如下:

{
  attacker: {user_document},
  attackee: {user_document},
  in_progress:  boolean (true or false),
  outcomes: [array of results based on calculation]
}

为启动攻击,您需要使用findAndModify并使用包含两个用户ID的查询文档执行upsert来查询攻击集合。如果已存在攻击,则不会创建新攻击。如果不存在攻击,则会插入文档并将in_progress设置为true以开始攻击。请在其中放置所有必要的用户详细信息。
接下来,进行黑盒计算并将结果序列推送到outcomes数组中,这些结果需要对两个用户文档进行一系列更新,并将in_progress设置为false。
完成后,逐个将outcomes应用于用户集合。
如果没有更多的outcome存在,则删除attack文档,以便可以开始新的攻击。
不确定是否符合您的要求,但希望这可以帮助您考虑如何实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接