documentDb存储过程可以并行运行并更新同一个对象吗? documentDb会按顺序处理它们吗?
请考虑以下情况。
我有一个应用程序,当我完成任务时,我有10000个硬币可以给我的用户。我有以下对象
{
remainingPoints: 10000
}
我有一个存储过程从该对象中减去10个点并将它们添加到用户的点。
现在让我们说10个用户同时完成任务,我同时调用存储过程10次,DocDb会按顺序执行吗?或者我必须按顺序执行存储过程吗?
答案 0 :(得分:3)
当我第一次使用DocumentDB时,我遇到了类似的问题,并在此处和来自DocumentDB产品经理的电子邮件中得到了很好的答案。引用:
存储过程...获取数据库的独立快照以获取事务支持。快照反映了sproc开始执行时的世界当前状态(没有陈旧数据)(强烈一致)。
警告 - 由于存储过程在快照上运行,如果在执行期间新的写入来自外部世界,您仍然可以在sproc中获得过时的读取。
此外,存储过程将始终读取他们自己的写入。
Sprocs是DocumentDB的多文档事务处理机制。当sproc成功完成执行时,将提交Sproc写入。如果抛出异常,则在sproc中完成的所有工作都会回滚。
因此,如果两个sprocs同时运行,他们就不会看到彼此的写入。
如果两个sprocs碰巧写入同一个文档(替换) - 那么第二个sprocs会因尝试提交写入时etag不匹配而失败。
从那以后,我继续我的设计,确保在我的写作中使用ETag,正如@Julian建议的那样。我还会自动重试最多3次sproc执行,以处理因并行操作而导致其失败的情况。在实践中,我从未超过3次重试(除非我的sproc有错误),我很少进行单次重试。
我从我观察到的行为中假设它将每个新的sproc执行发送到不同的副本,直到它用完副本然后将它们排队等待顺序执行,因此它是并行和串行执行的混合。
我通过实验学到的另一个技巧是,当你在一个负载很重的系统上时,你最好不要在客户端而不是在sproc中进行纯读取操作(没有写入和没有重要的聚合)。我认为优势是因为DocumentDB可以并行地满足不同副本的不同读取。我使用expandScript
的documentdb-utils功能模块化了我的sproc代码,以确保我使用完全相同的代码进行写入验证,文档内一致性以及客户端和服务器端的派生字段,这可以使用node.js.即使您主要是.NET,也可以使用expandScripts
以模块化DRY方式构建您的sprocs。您仍然需要在构建过程中运行node.js来预处理您的sprocs或使用Edge.NET(在.NET中运行的节点)来动态执行此操作。
答案 1 :(得分:0)
这取决于您为收藏选择的一致性。但是这个想法是DocumentDb使用etag处理并发并在文档版本的快照上执行存储过程,并且只有在执行成功时才提交结果。
请参阅:https://azure.microsoft.com/en-us/documentation/articles/documentdb-faq/#develop
此主题也可能有所帮助:Atomically increment an integer in a document in Azure DocumentDB