简介

  • Gunicorn, 一个支持WSGI协议的web服务器
  • Flask, 一个轻量级的python web框架

Gunicorn目前自带支持几种工作方式:

  • sync (默认值)
  • eventlet
  • gevent
  • tornado

测试环境准备

  1. python 2.7+
  2. redis-server 2.8.4
  3. 压力测试工具ab
  4. 代码及相关python包准备 创建虚一个新的虚拟环境并安装需要的包

    :::bash
    $ mkvirtualenv test
    $ workon test
    
    $ cat requirements.txt
    gunicorn==19.3.0
    flask==0.10.1
    flask-redis==0.1.0
    gevent==1.0.2
    tornado==4.2
    eventlet==0.17.4
    
    $ pip install -r requirements.txt
    

    测试程序app.py

    :::python
    from flask import Flask
    from flask_redis import FlaskRedis
    
    REDIS_URL = "redis://:password-string@localhost:6379/0"
    app = Flask(__name__)
    app.config.from_object(__name__)
    
    redis = FlaskRedis(app, True)
    
    @app.route("/")
    def index():
        redis.incr("hit", 1)
        return redis.get("hit")
    
    if __name__ == '__main__':
        app.run()
    

开始测试

  1. 使用ab工具,并行500个客户端, 发送50000次请求

    $ ab -c 500 -t 30 -r "http://127.0.0.1:8000/"
    
  2. 分别使用四种方式启动使用服务, 并开启4个worker

    $ gunicorn -w 4 app:app --error-logfile - --worker-class sync
    $ gunicorn -w 4 app:app --error-logfile - --worker-class gevent
    $ gunicorn -w 4 app:app --error-logfile - --worker-class tornado
    $ gunicorn -w 4 app:app --error-logfile - --worker-class eventlet
    
  3. 结果比较

Worker class Time taken for tests Complete requests Failed requests Requests per second 用户平均请求等待时间 服务器平均处理时间 最小连接时间 平均连接时间 50%的连接时间 最大连接时间
sync 37.363 s 49928 793 1336.29 374.169 ms 0.748 ms 5 ms 75 ms 17 ms 31746 ms
tornado 13.995 50000 543 3572.64 139.953 ms 0.280 ms 6 ms 110 ms 24 ms 13837 ms
eventlet 8.156 50000 0 6130.74 81.556 0.163 ms 2 ms 80 ms 62 ms 3153 ms
gevent 7.647 s 50000 0 6538.23 76.473 ms 0.153 ms 1 ms 74 ms 52 ms 1122 ms

从测试结果来看,默认自带sync效率很低,并且在测试时发现,采用sync方式在高并发时 会出现woker重启的情况, 如下:

[2015-06-25 11:31:06 +0000] [27040] [CRITICAL] WORKER TIMEOUT (pid:27064)
[2015-06-25 11:31:06 +0000] [27040] [CRITICAL] WORKER TIMEOUT (pid:27051)
[2015-06-25 11:31:06 +0000] [27040] [CRITICAL] WORKER TIMEOUT (pid:27045)
[2015-06-25 11:31:06 +0000] [27040] [CRITICAL] WORKER TIMEOUT (pid:27046)
[2015-06-25 11:31:06 +0000] [27064] [INFO] Worker exiting (pid: 27064)
[2015-06-25 11:31:06 +0000] [27051] [INFO] Worker exiting (pid: 27051)
[2015-06-25 11:31:06 +0000] [27045] [INFO] Worker exiting (pid: 27045)
[2015-06-25 11:31:06 +0000] [27046] [INFO] Worker exiting (pid: 27046)
[2015-06-25 11:31:06 +0000] [27263] [INFO] Booting worker with pid: 27263
[2015-06-25 11:31:06 +0000] [27264] [INFO] Booting worker with pid: 27264
[2015-06-25 11:31:06 +0000] [27277] [INFO] Booting worker with pid: 27277
[2015-06-25 11:31:06 +0000] [27280] [INFO] Booting worker with pid: 27280

eventlet 和gevent两种方式效果最好,数据基本差不多.