如何解决MongoDB中缺少事务的问题?

Nag*_*gyI 136 transactions mongodb

我知道这里有类似的问题,但如果我需要事务或使用原子操作两阶段提交,他们要么告诉我切换回常规RDBMS系统.第二种解决方案似乎是最佳选择.第三个我不想遵循,因为似乎很多事情都可能出错,我无法在各个方面进行测试.我很难重构我的项目来执行原子操作.我不知道这是否来自我有限的观点(到目前为止我只使用过SQL数据库),或者它是否真的无法完成.

我们想在我们公司试用MongoDB.我们选择了一个相对简单的项目 - 短信网关.它允许我们的软件向蜂窝网络发送SMS消息,并且网关执行肮脏的工作:实际上通过不同的通信协议与提供商进行通信.网关还管理消息的计费.申请服务的每个客户都必须购买一些积分.发送消息时,系统会自动降低用户的余额,如果余额不足,则拒绝访问.另外,由于我们是第三方SMS提供商的客户,我们也可能拥有自己的余额.我们也必须跟踪这些.

如果我减少了一些复杂性(外部计费,排队短信发送),我开始考虑如何用MongoDB存储所需的数据.来自SQL世界,我将为用户创建一个单独的表,另一个用于SMS消息,另一个用于存储有关用户余额的事务.假设我为MongoDB中的所有人创建了单独的集合.

想象一下SMS发送任务,在这个简化的系统中执行以下步骤:

  1. 检查用户是否有足够的余额; 如果没有足够的信用,请拒绝访问

  2. 使用详细信息和成本在SMS集合中发送和存储消息(在实时系统中,消息具有status属性,任务将接收它以进行传递,并根据SMS的当前状态设置SMS的价格)

  3. 通过发送消息的成本减少用户的余额

  4. 在事务集合中记录事务

那现在有什么问题?MongoDB只能在一个文档上进行原子更新.在之前的流程中,可能会发生某种错误,并且消息会存储在数据库中,但用户的余额未更新和/或未记录事务.

我提出了两个想法:

  • 为用户创建单个集合,并将余额作为字段,用户相关事务和消息存储为用户文档中的子文档.因为我们可以原子地更新文档,这实际上解决了事务问题.缺点:如果用户发送许多SMS消息,文档的大小可能会变大,并且可能达到4MB的文档限制.也许我可以在这种情况下创建历史文档,但我认为这不是一个好主意.另外,我不知道如果我将越来越多的数据推送到同一个大文档,系统会有多快.

  • 为用户创建一个集合,为事务创建一个集合.可以有两种交易:具有正余额变化的信用购买和具有负余额变化的消息.交易可能有一个子文件; 例如,在发送消息中,SMS的详细信息可以嵌入到事务中.缺点:我没有存储当前的用户余额,因此每次用户尝试发送消息时都要计算它,以判断消息是否可以通过.我担心随着存储事务数量的增加,这种计算会变慢.

我对选择哪种方法有点困惑.还有其他解决方案吗?我在网上找不到关于如何解决这些问题的最佳实践.我想许多试图熟悉NoSQL世界的程序员一开始就面临着类似的问题.

xam*_*mir 82

没有交易的生活

事务支持ACID属性,但是虽然没有事务MongoDB,但我们确实有原子操作.好吧,原子操作意味着当您处理单个文档时,该工作将在其他人看到该文档之前完成.他们会看到我们所做的所有改变,或者没有改变.使用原子操作,您通常可以完成使用关系数据库中的事务完成的相同操作.原因是,在关系数据库中,我们需要跨多个表进行更改.通常需要加入的表格,因此我们希望一次完成所有这些操作.要做到这一点,因为有多个表,我们必须开始一个事务并执行所有这些更新,然后结束事务.但是MongoDB,我们将要嵌入数据,因为我们将在文档中预先加入它们,而这些文档是具有层次结构的丰富文档.我们经常可以完成同样的事情.例如,在博客示例中,如果我们想确保以原子方式更新博客文章,我们可以这样做,因为我们可以立即更新整个博客文章.如果它是一堆关系表,我们可能必须打开一个事务,以便我们可以更新帖子集合和评论集合.

那么,我们可以采取哪些方法MongoDB来克服缺乏交易?

  • 重组 - 重构代码,以便我们在单个文档中工作并利用我们在该文档中提供的原子操作.如果我们这样做,那么通常我们都会设置好.
  • 在软件中实现 - 我们可以通过创建关键部分来实现软件锁定.我们可以使用查找和修改来构建测试,测试和设置.如果需要,我们可以建立信号量.从某种程度上说,这就是大世界的工作方式.如果我们考虑一下,如果一家银行需要将资金转移到另一家银行,那么他们就不会生活在同一个关系系统中.而且他们每个人都经常拥有自己的关系数据库.即使我们无法在这些数据库系统中开始事务和结束事务,也只能在一个银行内的一个系统内,他们就能够协调该操作.因此,软件无疑可以解决问题.
  • 容忍 - 最终的方法,通常适用于现代网络应用程序和其他接收大量数据的应用程序,只是容忍一点不一致.举个例子,如果我们在Facebook上谈论朋友提要,那么每个人是否同时看到你的墙更新并不重要.如果有人,如果一个人的几个人在几秒钟内击败并且他们赶上了.在许多系统设计中,一切都保持完全一致并且每个人都拥有完全一致且相同的数据库视图并不重要.所以我们可以简单地容忍一点点不一致,这有点暂时.

Update,findAndModify,$addToSet(更新内)$push(更新内)操作在单个文档中以原子方式操作.

  • 如果您有多个服务器,则必须使用外部分布式锁定服务,代码的关键部分将不起作用 (3认同)
  • 我喜欢这个答案的方式,而不是继续质疑我们是否应该回到关系数据库.谢谢@xameeramir! (2认同)

Gio*_*ner 24

检查出,由Tokutek.他们为Mongo开发了一个插件,不仅承诺交易,还承诺提升性能.


Gri*_*nik 19

从4.0开始,MongoDB将拥有多文档ACID事务.计划是首先启用副本集部署中的那些,然后是分片群集.MongoDB中的事务就像开发人员熟悉的关系数据库中的事务一样 - 它们将是多语句,具有类似的语义和语法(如start_transactioncommit_transaction).重要的是,对启用事务的MongoDB所做的更改不会影响不需要它们的工作负载的性能.

欲了解更多详情,请参见这里.

  • 交易来了!4.0 GA'ed。https://www.mongodb.com/blog/post/mongodb-multi-document-acid-transactions-general-availability (2认同)

小智 11

提出要点:如果必须使用事务完整性,则不要使用MongoDB,而只使用支持事务的系统中的组件.在组件之上构建一些东西是非常困难的,以便为非ACID兼容组件提供类似ACID的功能.根据个人用例,以某种方式将操作分为事务性和非事务性操作可能是有意义的...

  • NoSQL 解决方案很少单独使用。文档存储(mongo 和 couch)可能是此规则的唯一例外。 (2认同)

pin*_*33n 7

那现在有什么问题?MongoDB只能在一个文档上进行原子更新.在之前的流程中,可能会发生某种错误,并且消息会存储在数据库中,但用户的余额不会减少和/或事务未被记录.

这不是一个真正的问题.您提到的错误是逻辑(错误)或IO错误(网络,磁盘故障).这种错误会使无事务和事务存储处于不一致状态.例如,如果它已经发送了短信但是在发生存储消息错误时 - 它无法回滚短信发送,这意味着它不会被记录,用户余额也不会减少等.

这里真正的问题是用户可以利用竞争条件并发送比他的余额更多的消息.这也适用于RDBMS,除非您使用平衡字段锁定进行内部事务的SMS发送(这将是一个很大的瓶颈).因为MongoDB的一个可能的解决方案是findAndModify首先使用减少余额并检查它,如果它是否定的,则不允许发送和退还金额(原子增量).如果是肯定的,继续发送,如果它未能退还金额.还可以维护余额历史记录集合以帮助修复/验证余额字段.

  • 事实上,如果您不进行最终提交,事务存储将会回滚. (9认同)
  • 此外,您不发送短信,然后登录到数据库,这是完全错误的.首先将所有内容存储在DB中并进行最终提交,然后您可以发送消息.此时某些内容仍然可能失败,因此您需要一个cron作业来检查消息是否实际发送,如果没有尝试发送.也许专用的消息队列对此更好.但是整个事情归结为你是否可以以交易方式发送短信...... (9认同)

Kar*_*ath 6

该项目很简单,但您必须支持付款交易,这使整个事情变得困难.因此,例如,具有数百个集合(论坛,聊天,广告等)的复杂门户系统在某些方面更简单,因为如果您丢失了论坛或聊天条目,则没有人真正关心.另一方面,如果您失去了一个严重问题的支付交易.

所以,如果你真的想要MongoDB的试点项目,那么选择一个在方面很简单的项目.


khe*_*eya 6

由于正当理由,MongoDB中缺少事务.这是使MongoDB更快的事情之一.

在你的情况下,如果交易是必须的,mongo似乎不太适合.

可能是RDMBS + MongoDB,但这会增加复杂性并使管理和支持应用程序变得更加困难.

  • 交易怎么可能不是"必须".一旦你需要1个简单的情况你需要更新2个表mongo突然不再适合?这根本不会留下很多用例. (9认同)

Vai*_*hav 6

这可能是我发现的关于为mongodb实现交易功能的最佳博客.

同步标志:最好只从主文档复制数据

工作队列:非常通用,解决了95%的案例.无论如何,大多数系统都需要至少有一个作业队列!

两阶段提交:此技术确保每个实体始终具有达到一致状态所需的所有信息

日志调节:最强大的技术,非常适合金融系统

版本控制:提供隔离并支持复杂的结构

阅读本文以获取更多信息:https: //dzone.com/articles/how-implement-robust-and