Tornado和Mongodb的阻塞与异步考虑是什么?
我正在使用 Tornado 网络服务器和 MongoDB(通过 pymongo 驱动)一起运行。我想做一些架构上的决策,以最大化性能。
我有几个关于使用 Tornado 和 pymongo 时,应用程序的阻塞/非阻塞和异步方面的小问题:
问题 1:连接池
看起来 pymongo.mongo_client.MongoClient
对象会自动实现一个连接池。连接池的目的就是让我可以从不同的线程同时访问 MongoDB 吗?如果只用一个线程运行一个 MongoClient 实例,那真的没有“池”吗?因为那时候只会有一个连接是打开的,对吧?
问题 2:多线程 Mongo 调用
提到:
目前没有很好的方法将 PyMongo 与 Tornado 或 Twisted 一起使用。PyMongo 提供内置的连接池,所以通过编写共享 MongoClient 的多线程代码,可以实现这些框架的一些好处。
所以我假设我只需要将一个 MongoClient
的引用传递给每个线程?还是说还有其他的考虑?当每个线程产生结果时,触发回调的最佳方法是什么?我是否应该有一个线程在运行,负责监视一个队列(Python 的 Queue.Queue
),来处理每个结果,然后在 Tornado 中调用剩下的 RequestHandler
对象的 finish()
?(当然需要使用 tornado.web.asynchronous
装饰器)
问题 3:多个实例
最后,我是不是在自找麻烦?我是否应该直接运行一个单线程的 Tornado 实例,然后每个核心启动 3-4 个实例?(上面的常见问题似乎暗示了这一点)
毕竟,Python 中的 GIL 不会导致实际上是不同的进程吗?还是说 Tornado 的“非阻塞”特性还有其他性能上的考虑(好处或坏处)?(我知道在这里提到的,这是在 I/O 方面是非阻塞的:Tornado 真的是非阻塞的吗?)
(附加说明:我知道 asyncmongo,地址是:https://github.com/bitly/asyncmongo,但我想直接使用 pymongo,而不想引入这个额外的依赖。)
3 个回答
你知道motor吗?这是一个为Python和Tornado设计的异步MongoDB驱动程序。你可以在这里了解更多:http://emptysquare.net/blog/introducing-motor-an-asynchronous-mongodb-driver-for-python-and-tornado/。这个项目是由Jesse Davis写的,他也是pymongo的共同作者。
虽然这个问题已经有点时间了,但我觉得之前的回答并没有完全解决用户提出的所有疑问。
如果我只用一个MongoClient实例在单线程中运行,真的就没有“连接池”吗?因为此时只会有一个连接打开,对吗?
这个说法是对的,如果你的脚本没有使用多线程。不过,如果你的脚本是多线程的,那么在某个时刻就会有多个连接打开。
最后,我是不是在自找麻烦?我是不是应该简单点,只用一个线程的Tornado实例,然后每个核心启动3到4个实例?
你并没有自找麻烦!创建多个线程比创建多个进程要占用更少的资源。
难道Python中的GIL不会导致实际上是不同的进程吗?
GIL只会阻止多个线程同时访问解释器,并不会阻止多个线程同时进行输入输出操作。实际上,这正是使用asyncio的motor实现异步的方式。
它使用一个线程池执行器,为每个查询创建一个新线程,并在线程完成时返回结果。
我理解,网络服务器有两个概念:
- 基于线程的(比如 Apache)
- 事件驱动的(比如 Tornado)
在 Python 中有个叫 GIL 的东西,它对线程的支持不太好,而事件驱动的模型只用一个线程,所以建议使用事件驱动的方式。
Pymongo 会阻塞 Tornado,所以这里有一些建议:
- 使用 Pymongo:可以用它,并通过创建索引来加快数据库的调用速度,但要注意;索引在处理大量值的操作时效果不好,比如
gte
。 - 使用 AsyncMongo,这个似乎有更新,但并不是所有 MongoDB 的功能都有。
- 使用 Mongotor,这个可以看作是 AsyncMongo 的升级版,它有 ODM(对象文档映射),包含了你需要的 MongoDB 所有功能(聚合、复制集等),唯一缺少的功能是 GridFS。
- 使用 Motor,这是一个与 Tornado 完美配合的解决方案,支持 GridFS,并且是官方的 MongoDB 异步驱动,使用了一个叫 Greenlet 的技巧,所以唯一的缺点是不能与 PyPy 一起使用。
现在,如果你决定使用其他解决方案而不是 Tornado,如果你用 Gevent,那么可以使用 Pymongo,因为 据说:
PyMongo 完全支持的唯一异步框架是 Gevent。
附注:抱歉如果偏离主题,但这句话:
目前没有很好的方法将 PyMongo 与 Tornado 一起使用
应该从文档中删除,因为 Mongotor 和 Motor 的配合效果非常好(特别是 Motor)。