多线程下pymongo连接数过多的问题处理
背景
项目中有个应用,用到了多线程,线程中会有对MongoDB的操作。一般涉及到这种场景,都会小心MongoDB的连接的数量控制。
实现这个应用的时候必然已经考虑这点了,但实际碰到的情况是:多线程的程序运行起来,MongoDB连接数比预期多。
涉及的环境:
- Linux
- Python 2.6.5
- MongoDB 2.0.0
- MongoDB的驱动是pymongo。本文涉及的版本有4个:1.1.1、2.0.1、2.1.1,以及最新的2.2rc1。
过程
简化的代码
先用一段简化的代码来说明下这个问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#-*- encoding:UTF-8 -*- import threading import time import pymongo single_conn = pymongo.Connection('mongodb://127.0.0.1', max_pool_size=1) class SimpleExampleThread(threading.Thread): def run(self): print single_conn['fvck'].damnit.count(), self.getName() time.sleep(10) for i in range(100): SimpleExampleThread().start() |
代码的大致意思是创建1个MongoDB连接,然后生成100个线程,在线程中会有对MongoDB的操作
具体使用方式如下:
- 编辑上述代码,保存为test_pymongo.py
- 启动MongoDB,确保可以用127.0.0.1访问
- 运行MongoDB自带的命令行工具mongostat,关注conn这一列,这个时候应该数量是1
- 执行测试程序,python test_pymongo.py
- 观察mongostat的conn这一列,猜是多少?2?这是预想的,实际竟然是101
- 确认pymongo版本是2.0.1
怀疑pymongo版本太旧
- 升级到最新的正式版本2.1.1
- sudo pip install pymongo==2.1.1 --upgrade
- 执行测试程序结果一样,已然有连接数过多的问题
确认自己程序
- 确认没问题。上面程序只是个实际程序的简化的代码。
意外确认问题
- 这个这个时候一般会去查看下pymongo的源代码,分析下实现原理
- 偷个懒。刚好停下来没事,随便瞎逛了下MongoDB的缺陷跟踪系统。想可能是不是pymongo的缺陷,刚好搜到了这个缺陷, https://jira.mongodb.org/browse/PYTHON-287
- 这个issues大致意思是每个线程还是会创建一个MongoDB的连接,希望能支持线程间共享1个MongoDB连接
- pymongo预计解决的版本是2.2,一看,竟然刚好是发现改问题的当天发布该版本。果然,当天发布了2.2rc1这个版本
更新到2.2rc1
- 因为不是正式版本,所以单独下载安装
1 2 3 4 5 |
wget https://github.com/mongodb/mongo-python-driver/tarball/2.2rc1 tar xzvf 2.2rc1 cd mongodb-mongo-python-driver-4c7edfc/ sudo python setup.py install python test_pymongo.py |
- 但失败了,和2.0.1和2.1.1的表现一样
RTFM
- 查看文档: http://api.mongodb.org/python/2.2rc1/examples/requests.html
- 发现是程序写法不对,修改的代码如下:
123456789101112131415161718#-*- encoding:UTF-8 -*-import datetimeimport threadingimport timeimport pymongoconn = pymongo.Connection('mongodb://127.0.0.1', auto_start_request=False)class MyThread(threading.Thread):def run(self):print conn['fvck'].damnit.count(), datetime.datetime.now(), self.getName()time.sleep(10)with conn.start_request():for i in range(100):MyThread().start()
- 运行程序,连接数符合预期数量是2
- 关键参数是:auto_start_request=False,这个参数看源码历史,貌似从pymongo1.1.1开始移除了,在2.2rc1这个版本又恢复了,但应该有新的用处了吧。
最后
- 问题至此,从项目角度,算是告一段落,如果从纯技术研究角度,还可以继续深入
- 比如:至于pymongo如何处理连接数,谁有兴趣,可以深入下pymongo的源码,貌似可以从这3个py入手,估计可以另起一篇文章来讲解:
- pymongo/connection.py
- pymongo/database.py
- pymongo/pool.py
5条评论
3.0之后的版本 去掉了 只说 增加了一个connect参数。。。也马勒隔壁没说干嘛。。 true和false都没用 连接数开多少线程就涨多少了 导致经常跑着跑着服务器10056 10060 10055之类的错误
怒赞”RTFM”
连接数还是102。
不错。碰上同样问题。
不错,重要的是遇到问题的排查思路