最近在使用 Tornado 开发 API,数据库选择了 MongoDB,因为想使用 Geo 搜索的特性。Python 可供选择的 MongoDB Drivers 可以在官网查找

在这些 Drivers 中,GitHub 上 Star 数最多的有 3 个:

Motor 和 MongoEngine 都是基于 PyMongo,Motor 的最新版是基于 PyMongo 2.8,Motor 的优势就在于异步,而 PyMongo 在 2.2 以后的版本,就开始支持 gevent。

MongoEngine 借鉴了 Django 的 ORM,提供了一个 ORM-like layer,官方称作 Document-Object Mapper,可以像使用 Django 的 ORM 一样,简单的操作和处理数据。

面对这么多选择,就想探究这些选择都有哪些特点,性能如何,所以有了这篇文章。你可以在这里找到所有的测试代码和测试数据

https://github.com/restran/tornado-mongodb-performance-test

HTTP 性能测试工具

HTTP 性能测试工具可以选择:

这里的测试使用 ab,安装方法

sudo apt-get install apache2-utils

测试配置

测试的配置如下

  • Tornado 程序位于一台 Ubuntu 14.04 x86_64 的虚拟机,2 GB 内存,2 核心 CPU,2.59 GHz。
  • MongoDB 3.06 x86_64 Windows 版,在一台 Windows 2008 R2 的虚拟机,4 GB 内存,2 核心 CPU,2.39 GHz。
  • MongoDB 数据库中已经预先插入 100W 条数据,以下所有的实验都是测试从数据库中读数据的性能。
  • Tornado 使用最新的 4.2.1 版。

数据库中的数据是这个样子的

{
"_id": {
"$oid": "5630cd05f7732b28a81f57fa"
},
"title": "Post title",
"created": {
"$date": "2015-10-28T21:26:29.271+0000"
}
}

Tornado 中查询数据的 Handler 是这个样子的,以 PyMongo 3.0 为例。

class QueryHandler(APIHandler):
def get(self):
cursor = self.database.post.find(limit=30)
json_data = []
for t in cursor:
j = {
'_id': text_type(t['_id']),
'title': t['title'],
'created': t['created'].strftime('%Y-%m-%d %H:%M:%S')
if t['created'] else None
}
json_data.append(j) self.success(json_data)

测试说明

在实际测试的时候,发现在 PyMongo 2.8 的环境下,PyMongo 2.8 和 MongoEngine 性能都很差,因此设置了两组测试。

测试 1

总共 10000 个请求,每次并发 100 个(同时发送 100 个),使用如下命令

ab -n 10000 -c 100 http://127.0.0.1:8500/api/posts/query/

实验对象:

  • Motor(Mortor 最新版是基于 PyMongo 2.8)
  • PyMongo 3.0
  • PyMongo 3.0 + gevent(PyMongo 支持 gevent)
  • MongoEngine + PyMongo 3.0

PyMongo 开启 gevent 的方法,可以参考

https://api.mongodb.org/python/current/examples/gevent.html

测试 2

总共 100 个请求,每次并发 10 个(同时发送 10 个),使用如下命令

ab -n 100 -c 10 http://127.0.0.1:8500/api/posts/query/

实验对象:

  • PyMongo 2.8
  • PyMongo 2.8 + gevent
  • MongoEngine + PyMongo 2.8

Virtualenv

由于要使用不同版本的 PyMongo,因此使用了 Virtualenv 来创建不同的环境。

Windows 环境下的 virtualenv,命令会有些不一样,这里的命令适用于 Linux。

安装

sudo pip install virtualenv

创建一个虚拟的 Python 环境

virtualenv env_name

创建测试需要的两个环境

virtualenv pymongo2.8
virtualenv pymongo3.0

激活虚拟环境,安装相应的包

cd pymongo2.8
source bin/activate
pip install pymongo==2.8.0 tornado mongoengine motor gevent

对虚拟环境 pymongo3.0 执行相应的操作

cd pymongo3.0
source bin/activate
pip install pymongo==3.0.6 tornado mongoengine gevent

用虚拟环境中的 Python 启动 Tornado 程序

/path/to/pymongo2.8/bin/python pymongo2.8_app.py

测试结果

先给出两组测试结果的数据:完成所有请求的耗时,吞吐量(每秒处理的请求数)

从测试的结果来看,Motor 的性能确实很好,gevent 几乎没有性能提升,PyMongo 2.8 的性能很差,MongoEngine 是在 PyMongo 的基础上有封装了一层,但是两者性能相差不大。

Tornado 的单线程的,同步的数据库 Driver 会将 Tornado 阻塞住,导致无法处理其他的请求。

最后给出一组数据,百分比请求的最大响应时间。下面这张图,左边坐标的单位是毫秒。例如 Motor 有 50% 的请求是在 376 毫秒内完成的。

PyMongo 2.8,PyMongo 2.8 + gevent,MongoEngine + PyMongo 2.8 三条线重叠在了一起,它们之间的性能相当。

Tornado 中 PyMongo Motor MongoEngine 的性能测试的更多相关文章

  1. 在 tornado 中异步无阻塞的执行耗时任务

    在 tornado 中异步无阻塞的执行耗时任务 在 linux 上 tornado 是基于 epoll 的事件驱动框架,在网络事件上是无阻塞的.但是因为 tornado 自身是单线程的,所以如果我们在 ...

  2. Tornado 中的 get() 或 post() 方法

    ---恢复内容开始--- Tornado 中的 get() 或 post() 方法 请求处理程序和请求参数 Tornado 的 Web 程序会将 URL 或者 URL 范式映射到 tornado.we ...

  3. tornado中使用torndb,连接数过高的问题

    问题背景 最近新的产品开发中,使用了到了Tornado和mysql数据库.但在基本框架完成之后,我在开发时候发现了一个很奇怪的现象,我在测试时,发现数据库返回不了结果,于是我在mysql中输入show ...

  4. 在tornado中使用celery实现异步任务处理之中的一个

    一.简单介绍 tornado-celery是用于Tornado web框架的非堵塞 celeryclient. 通过tornado-celery能够将耗时任务增加到任务队列中处理, 在celery中创 ...

  5. 深入tornado中的协程

    tornado使用了单进程(当然也可以多进程) + 协程 + I/O多路复用的机制,解决了C10K中因为过多的线程(进程)的上下文切换 而导致的cpu资源的浪费. tornado中的I/O多路复用前面 ...

  6. 深入tornado中的TCPServer

    1 梳理: 应用层的下一层是传输层,而http协议一般是使用tcp的,所以实现tcp的重要性就不言而喻. 由于tornado中实现了ioloop这个反应器以及iostream这个对连接的异步读写,所以 ...

  7. 深入tornado中的http1connection

    前言 tornado中http1connection文件的作用极其重要,他实现了http1.x协议. 本模块基于gen模块和iostream模块实现异步的处理请求或者响应. 阅读本文需要一些基础的ht ...

  8. 基于python3.x,使用Tornado中的torndb模块操作数据库

    目前Tornado中的torndb模块是不支持python3.x,所以需要修改部分torndb源码即可正常使用 1.开发环境介绍 操作系统:win8(64位),python版本:python3.6(3 ...

  9. Python设计模式中单例模式的实现及在Tornado中的应用

    单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def new(cls, *args): if not isinstan ...

随机推荐

  1. Arpa’s obvious problem and Mehrdad’s terrible solution 思维

    There are some beautiful girls in Arpa’s land as mentioned before. Once Arpa came up with an obvious ...

  2. 有向图与无向图的合并操作区别D(递归与并查集)

    有向图的合并,典型问题:通知小弟(信息只能单向传播)https://www.nowcoder.com/acm/contest/76/E 无向图的合并,典型问题:修道路问题 由于无向图只要二者有联系即可 ...

  3. poj1797 最短路

    虽然不是求最短路,但是仍然是最短路题目,题意是要求1到N点的一条路径,由于每一段路都是双向的并且有承受能力,求一条路最小承受能力最大,其实就是之前POJ2253的翻版,一个求最大值最小,一个求最小值最 ...

  4. MHA之Binlog Dump (GTID)僵尸进程清理

      master存活的状态下切换 masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_mas ...

  5. JS 中 this 的用法

    this是JavaScript语言中的一个关键字 他是函数运行时,在函数体内部自动生成的一个对象, 只能在函数体内部使用. 在不同function中, this有不同的值. 1. 纯粹的函数调用. f ...

  6. drbd脑裂问题处理

    http://blog.csdn.net/heianemo/article/details/8439813 split brain实际上是指在某种情况下,造成drbd的两个节点断开了连接,都以prim ...

  7. php单例模式实现对象只被创建一次 mysql单例操作类

    这是我在php面试题中遇到的一道试题,单例模式按字面来看就是某一个类只有一个实例,这样做的好处还是很大的,比如说数据库的连接,我们只需要实例化一次,不需要每次都去new了,这样极大的降低了资源的耗费. ...

  8. R(5): sql 数据处理

    sqldf程序包是R语言中实用的数据管理辅助工具,但最新版本的包在处理中文时出现乱码,待解决 Usage:  sqldf(x, stringsAsFactors = FALSE,  row.names ...

  9. 【Spring学习笔记-3.1】让bean获取spring容器上下文(applicationContext.xml)

    *.hl_mark_KMSmartTagPinkImg{background-color:#ffaaff;}*.hl_mark_KMSmartTagBlueImg{background-color:# ...

  10. Spring IOC - 控制反转(依赖注入) - 懒加载机制

    懒加载机制 Spring默认会在容器初始化的过程中,解析xml,并将单例的bean创建并保存到map中,这样的机制在bean比较少的时间问题不大,但一旦bean非常多时,Spring需要在启动的过程中 ...