热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MongoDB的upsert在并行程序中应该注意的问题

题图Oct.12th,2018最近使用python的多进程编程来解决一个MongoDB的数据库。这个程序中,每一个进程都要对数据库中的某些数据进行升级。假如目标数据不存在的话,则需
题图

Oct. 12th, 2018

最近使用python的多进程编程来解决一个MongoDB的数据库。这个程序中,每一个进程都要对数据库中的某些数据进行升级。假如目标数据不存在的话,则需要进行upsert。程序运行之后,速度的确比单进程快少量(在小数据集的情况下,大约快了三四倍),但是最终结果却与单进程产生的结果不符合。研究一番之后,把问题锁定在了多进程同时升级数据库时产生的upsert问题。这里探讨一个简化模型来阐明此问题并且论述处理方法。

简化模型

为了简化探讨,这里探讨一个投票程序。某城市人民选举该市市长。每个市民选择一个人为他/她投票。因为该选举为广泛选举,在选举之前并没有候选人集合,而是每个市民可以把票投给任何一个人。为简化问题,假设城市里没有人重名,因而每个人的名字可以作为其唯一代号使用。实际情况中,可以使用其余唯一表示,比方身份证号等等。

这里的数据集非常简单:

Collection: db.election{'name': 'Alice', 'votes': 10}{'name': 'Bob', 'votes': 21}...

作为一个计票的进程,主要任务就是拿过一张选票,查看其name属性,在数据库中给名字为name的文档的票数加1。注意,这里name不肯定已经存在于数据库中。假如此名字不存在,则应新建一条文档。因而,使用update_one时upsert属性应设为True

# name variable stores the candidate's name.db.election.update_one({'name': name}, \ {'$inc': {'votes': 1}}, upsert=True)

在只有一个进程运行的情况下,这段代码尽管速度并不快,但会给出正确的计票结果。假如我们使用多进程,创立几个worker,分别收集选票,给指定的被选人计票,会怎样样呢?

多进程下的写入矛盾

当简单地把上面的update_one交给几个进程来解决的时候,我们会发现运行结果出了这样的问题:每个被选人的票数似乎少了很多,而被选人的数量添加了。仔细检查会发现,其实是同一个候选人被创立了多个文档。为什么会导致这样的写入错误呢?不难想象到,这是多个进程同时试图升级一个文档的时候导致的。

需要注意的是,MongoDB本身是有文档级的写入锁的。也就是说,当一个进程开始修改一个文档时,该文档被锁定,其余文档不可以再对其进行写入甚至读取。这个写入锁的存在本身就是为了防止不同程序升级文档时产生的写入冲突。然而,update其实分为两步。首先是搜索文档位置,而后是文档升级。当两个程序同时试图升级一个不存在的文档的时候,假设程序A先发现文档不存在,而后程序B发现文档不存在。此时A还没来得及对文档进行写入,因而文档锁并没有挂起。或者者说,因为文档不存在,探讨文档锁也就失去了意义。这个时候,两个进程就会分别创立文档并给其votes加1。于是就出现了不必要的重复。

如何处理?

处理方法其实很简单:unique index。 上文提到,name属性是唯一的。假如我们给它加一个唯一索引,不即可以从根本上避免一个人有多个不同的文档了吗?这个时候,即便两个进程经过搜索都得到了某个文档不存在的结果,假设A先一步创立了该文档,那么当B创立文档时,因为含有相同name的文档已经被A进程抢先创立,MongoDB就会拒绝B进程创立。pymongo对此类错误应该是有应对机制的,这是B进程会稍等片刻,重新尝试升级文档。这个时候,A进程已经完成计票并且释放了写入锁,文档被成功创立,而进程B再尝试时,也会检索到这个被新创立的文档,直接在上面把票数加1,而不是创立新文档。这样一个小的时间差,就处理了写入矛盾。

同时,我们还得到了额外的奖励:当name上创立了unique index之后,找到特定候选人的速度就会快很多。这个优势在计票初期,候选人数量不多时并没有显示,但当后期候选人数变多时,一方面再有新的候选人被加入的概率会变得很小(该被加的差不多都被加进来了),因而修改索引的几率越来越少;另一方面,在候选人基数变得很大的时候,相比于没有索引的情况,有唯一索引的情况下程序的速度优势会越发显著。这两个方面综合在一起,结果就是,增加唯一索引之后程序在后期速度优势会越来越显著。在我自己的程序中,运行初期多线程比单线程只快了三四倍,但在数据量较大时,多线程(加上唯一索引)会比单线程快10到20倍。这多处来的速度,就是唯一索引导致的。


推荐阅读
  • MongoDB的核心特性与架构解析
    本文深入探讨了MongoDB的核心特性,包括其强大的查询语言、灵活的文档模型以及高效的索引机制。此外,还详细介绍了MongoDB的体系结构,解释了其文档、集合和数据库的层次关系,并对比了MongoDB与传统关系型数据库(如MySQL)的逻辑结构。 ... [详细]
  • Python包管理工具pip的使用指南
    本文详细介绍了如何使用pip进行Python包的安装、管理和常见问题的解决方法,特别针对国内用户提供了优化建议。 ... [详细]
  • PostgreSQL 最新动态 —— 2022年4月6日
    了解 PostgreSQL 社区的最新进展和技术分享 ... [详细]
  • Python + Pytest 接口自动化测试中 Token 关联登录的实现方法
    本文将深入探讨 Python 和 Pytest 在接口自动化测试中如何实现 Token 关联登录,内容详尽、逻辑清晰,旨在帮助读者掌握这一关键技能。 ... [详细]
  • 优化Flask应用的并发处理:解决Mysql连接过多问题
    本文探讨了在Flask应用中通过优化后端架构来应对高并发请求,特别是针对Mysql 'too many connections' 错误的解决方案。我们将介绍如何利用Redis缓存、Gunicorn多进程和Celery异步任务队列来提升系统的性能和稳定性。 ... [详细]
  • 配置PHPStudy环境并使用DVWA进行Web安全测试
    本文详细介绍了如何在PHPStudy环境下配置DVWA( Damn Vulnerable Web Application ),并利用该平台进行SQL注入和XSS攻击的练习。通过此过程,读者可以熟悉常见的Web漏洞及其利用方法。 ... [详细]
  • Python3 中使用 lxml 模块解析 XPath 数据详解
    XPath 是一种用于在 XML 文档中查找信息的路径语言,同样适用于 HTML 文件的搜索。本文将详细介绍如何利用 Python 的 lxml 模块通过 XPath 技术高效地解析和抓取网页数据。 ... [详细]
  • Spring Cloud因其强大的功能和灵活性,被誉为开发分布式系统的‘一站式’解决方案。它不仅简化了分布式系统中的常见模式实现,还被广泛应用于企业级生产环境中。本书内容详实,覆盖了从微服务基础到Spring Cloud的高级应用,适合各层次的开发者。 ... [详细]
  • 58同城的Elasticsearch应用与平台构建实践
    本文由58同城高级架构师于伯伟分享,由陈树昌编辑整理,内容源自DataFunTalk。文章探讨了Elasticsearch作为分布式搜索和分析引擎的应用,特别是在58同城的实施案例,包括集群优化、典型应用实例及自动化平台建设等方面。 ... [详细]
  • 探讨在PHP开发中,如何选择使用Cookie或数据库来优化网站性能,特别是在处理用户保存的搜索结果时。 ... [详细]
  • SDN网络拓扑发现机制解析
    本文深入探讨了SDN(软件定义网络)中拓扑发现的原理与实现方法,重点介绍了LLDP协议在OpenFlow环境中的应用,并讨论了非OpenFlow设备存在时的链路发现策略。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
  • 本章详细介绍SP框架中的数据操作方法,包括数据查找、记录查询、新增、删除、更新、计数及字段增减等核心功能。通过具体示例和详细解析,帮助开发者更好地理解和使用这些方法。 ... [详细]
  • Python自动化测试入门:Selenium环境搭建
    本文详细介绍如何在Python环境中安装和配置Selenium,包括开发工具PyCharm的安装、Python环境的设置以及Selenium包的安装方法。此外,还提供了编写和运行第一个自动化测试脚本的步骤。 ... [详细]
  • 本文详细介绍了Java中实现异步调用的多种方式,包括线程创建、Future接口、CompletableFuture类以及Spring框架的@Async注解。通过代码示例和深入解析,帮助读者理解并掌握这些技术。 ... [详细]
author-avatar
爱恨情仇4131_120
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有