Tornado和Mongodb的阻塞与异步考虑是什么?

4 投票
3 回答
4615 浏览
提问于 2025-04-17 18:45

我正在使用 Tornado 网络服务器和 MongoDB(通过 pymongo 驱动)一起运行。我想做一些架构上的决策,以最大化性能。

我有几个关于使用 Tornado 和 pymongo 时,应用程序的阻塞/非阻塞和异步方面的小问题:

问题 1:连接池

看起来 pymongo.mongo_client.MongoClient 对象会自动实现一个连接池。连接池的目的就是让我可以从不同的线程同时访问 MongoDB 吗?如果只用一个线程运行一个 MongoClient 实例,那真的没有“池”吗?因为那时候只会有一个连接是打开的,对吧?

问题 2:多线程 Mongo 调用

http://api.mongodb.org/python/current/faq.html#does-pymongo-support-asynchronous-frameworks-like-gevent-tornado-or-twisted

提到:

目前没有很好的方法将 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 个回答

0

你知道motor吗?这是一个为Python和Tornado设计的异步MongoDB驱动程序。你可以在这里了解更多:http://emptysquare.net/blog/introducing-motor-an-asynchronous-mongodb-driver-for-python-and-tornado/。这个项目是由Jesse Davis写的,他也是pymongo的共同作者。

1

虽然这个问题已经有点时间了,但我觉得之前的回答并没有完全解决用户提出的所有疑问。

如果我只用一个MongoClient实例在单线程中运行,真的就没有“连接池”吗?因为此时只会有一个连接打开,对吗?

这个说法是对的,如果你的脚本没有使用多线程。不过,如果你的脚本是多线程的,那么在某个时刻就会有多个连接打开。

最后,我是不是在自找麻烦?我是不是应该简单点,只用一个线程的Tornado实例,然后每个核心启动3到4个实例?

你并没有自找麻烦!创建多个线程比创建多个进程要占用更少的资源。

难道Python中的GIL不会导致实际上是不同的进程吗?

GIL只会阻止多个线程同时访问解释器,并不会阻止多个线程同时进行输入输出操作。实际上,这正是使用asyncio的motor实现异步的方式。

它使用一个线程池执行器,为每个查询创建一个新线程,并在线程完成时返回结果。

3

我理解,网络服务器有两个概念:

  1. 基于线程的(比如 Apache)
  2. 事件驱动的(比如 Tornado)

在 Python 中有个叫 GIL 的东西,它对线程的支持不太好,而事件驱动的模型只用一个线程,所以建议使用事件驱动的方式。

Pymongo 会阻塞 Tornado,所以这里有一些建议:

  1. 使用 Pymongo:可以用它,并通过创建索引来加快数据库的调用速度,但要注意;索引在处理大量值的操作时效果不好,比如 gte
  2. 使用 AsyncMongo,这个似乎有更新,但并不是所有 MongoDB 的功能都有。
  3. 使用 Mongotor,这个可以看作是 AsyncMongo 的升级版,它有 ODM(对象文档映射),包含了你需要的 MongoDB 所有功能(聚合、复制集等),唯一缺少的功能是 GridFS。
  4. 使用 Motor,这是一个与 Tornado 完美配合的解决方案,支持 GridFS,并且是官方的 MongoDB 异步驱动,使用了一个叫 Greenlet 的技巧,所以唯一的缺点是不能与 PyPy 一起使用。

现在,如果你决定使用其他解决方案而不是 Tornado,如果你用 Gevent,那么可以使用 Pymongo,因为 据说

PyMongo 完全支持的唯一异步框架是 Gevent。

附注:抱歉如果偏离主题,但这句话:

目前没有很好的方法将 PyMongo 与 Tornado 一起使用

应该从文档中删除,因为 Mongotor 和 Motor 的配合效果非常好(特别是 Motor)。

撰写回答