我知道这里也有类似的问题,但是如果我需要事务或使用原子操作或两阶段提交,它们要么告诉我切换回常规RDBMS系统。第二种解决方案似乎是最佳选择。第三,我不想跟进,因为看来很多事情可能出错,而且我无法在各个方面进行测试。我很难重构项目以执行原子操作。我不知道这是否来自我有限的观点(到目前为止,我仅使用SQL数据库),还是实际上无法完成。
我们想在我们公司试行MongoDB。我们选择了一个相对简单的项目-SMS网关。它使我们的软件可以将SMS消息发送到蜂窝网络,而网关则可以完成肮脏的工作:实际上是通过不同的通信协议与提供商进行通信。网关还管理消息的计费。每个申请该服务的客户都必须购买一些积分。发送消息时,系统自动减少用户的余额,如果余额不足,则拒绝访问。另外,由于我们是第三方SMS提供商的客户,因此我们也可能拥有自己的余额。我们也必须跟踪这些。
我开始考虑如果我降低了一些复杂性(外部账单,排队的SMS发送),如何使用MongoDB存储所需的数据。来自SQL世界,我将为用户创建一个单独的表,为用户创建另一个表,用于存储SMS消息,以及一个用于存储有关用户余额的事务的表。假设我为MongoDB中的所有数据库创建了单独的集合。
设想一下此简化系统中的SMS发送任务,其步骤如下:
检查用户是否有足够的余额;如果信用额不足,请拒绝访问
将消息以及详细信息和成本发送并存储在SMS集合中(在实时系统中,消息将具有
status
属性,任务将提取该消息进行传递,并根据其当前状态设置SMS的价格)通过发送邮件的费用减少用户的余额
将交易记录在交易集合中
现在有什么问题吗?MongoDB只能对一个文档进行原子更新。在上一个流程中,可能会发生某种错误,消息已存储在数据库中,但用户的余额未更新和/或未记录交易。
我提出了两个想法:
为用户创建一个集合,并将余额存储为字段,将与用户相关的交易和消息存储为用户文档中的子文档。因为我们可以原子地更新文档,所以实际上解决了交易问题。缺点:如果用户发送许多SMS消息,则文档的大小可能会变大,并且可能会达到4MB的文档限制。也许我可以在这种情况下创建历史记录文档,但是我认为这不是一个好主意。另外,我不知道如果将越来越多的数据推送到同一个大文档中,系统将有多快。
为用户创建一个集合,为事务创建一个。可以有两种交易:余额更改为正的信用购买和余额更改为负的发送的消息。交易中可能有一个子文档;例如,在发送的消息中,可以将SMS的详细信息嵌入交易中。缺点:我不存储当前用户余额,因此每次用户尝试发送消息时都必须进行计算,以判断消息是否可以通过。恐怕随着存储的事务数量的增加,此计算可能会变慢。
我对选择哪种方法有些困惑。还有其他解决方案吗?在网上找不到关于如何解决此类问题的最佳实践。我猜想许多试图熟悉NoSQL世界的程序员在一开始就面临类似的问题。