Gunicorn性能测试

栏目: Python · 发布时间: 5年前

内容简介:写了很多很多Flask的API, 但是一直偷懒, 没有使用Gunicorn来作为Web Server 来运行成。后来因为某个线上服务, 经常出现timeout的情况。 在已经采用了好一些措施的情况还是无法完全避免的情况下, 想到了Gunicorn。

Gunicorn性能测试

前言

写了很多很多Flask的API, 但是一直偷懒, 没有使用Gunicorn来作为Web Server 来运行成。

后来因为某个线上服务, 经常出现timeout的情况。 在已经采用了好一些措施的情况还是无法完全避免的情况下, 想到了Gunicorn。

下面是迁移之前进行的一些简单的性能测试。 真正迁移其实比下面的脚本要复杂一些。

Gunicorn安全与测试命令

安装Gunicorn

安装与运行很简单,直接pip命令即可:

pip install gunicorn # 安装Gunicorn
pip install gunicorn[gevent] # 安装 gevent组件, 尝试多核    
 

性能测试工具: wrk

Linux安装官网地址: https://github.com/wg/wrk/wiki/Installing-Wrk-on-Linux

对于Ubuntu / Debian :

sudo apt-get install build-essential libssl-dev git -y
git clone https://github.com/wg/wrk.git wrk
cd wrk
sudo make
# move the executable to somewhere in your PATH, ex:
sudo cp wrk /usr/local/bin
 

wrk 使用简单说明:

# 格式:
wrk -d20s -t10 -c200 [url]
 
# -d: duration 测试持续时间
# -t: threads 线程数
# -c: connection 连接数
 

测试的Flask 程序

这里为了简单, 主要测试 python 将一段string变成json的逻辑

数据来源: https://itunes.apple.com/search?term=apple

为了保持代码逻辑清晰, 将其中的json字符串“隐藏了”

# perf_test.py
 
import json
from flask import Flask, jsonify
 
app = Flask(__name__)
 
@app.route('/')
def index():
    return 'hello world'
 
@app.route('/performance_test_json')
def performance_test_json() :
    raw_json = """
    # please paste json content from: https://itunes.apple.com/search?term=apple 
    """.strip()
    raw_json = json.loads(raw_json )
    return jsonify( raw_json )
 
if __name__ == '__main__':
    app.debug = False
    app.run(port=5001)
 

注意: 前端使用nginx做了转发。nginx配置如下:

server
{
    listen 80;
    server_name my-test-domain.com;
    client_max_body_size 5M;
    location / {
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:5001;
    }
    access_log logs/my-test-domain.com.access.log;
}
 

这样,我们就可以通过nginx转发的域名来做性能测试了。

PS: nginx主要解决静态文件+慢客户端的问题, 在这里对性能测试的影响应该不大。

测试1: 使用Flask内置的server进行测试

测试命令:

# 启动flask的命令
python perf_test.py
 
# wrk命令
wrk -d20s -t10 -c200 http://my-test-domain.com/performance_test_json
 

测试结果:

Running 20s test @ http://my-test-domain.com/performance_test_json
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   794.04ms  601.06ms   1.98s    55.36%
    Req/Sec     5.17     11.44   202.00     97.43%
  472 requests in 20.04s, 4.46MB read
  Socket errors: connect 0, read 0, write 0, timeout 248
Requests/sec:     23.55
Transfer/sec:    227.83KB
 

测试小结:

需要注意的数字:

  1. 一共产生了472个requests
  2. 一共出现了248次timeout, 这个比例相当高了, 比例: 52.5%
  3. 平均访问延时: 794.04ms

测试2: 使用Gunicorn 单核

测试命令:

# 使用Gunicorn启动Flask
gunicorn -w 1 -b 127.0.0.1:5001 perf_test:app   # 注意:这里使用的是单核哦
 
# wrk命令
wrk -d20s -t10 -c200 http://my-test-domain.com/performance_test_json
 

测试结果:

Running 20s test @ http://my-test-domain.com/performance_test_json
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   765.60ms  589.04ms   1.99s    61.11%
    Req/Sec     5.14     11.79   202.00     96.52%
  475 requests in 20.04s, 4.49MB read
  Socket errors: connect 0, read 0, write 0, timeout 187
Requests/sec:     23.71
Transfer/sec:    229.41KB
 

测试小结:

timeout 比例: 187 / 475 = 39.3%

可以看到, 比例下降非常明显。 平均访问延时也从794 下降到 765ms, 提升 (794 – 765) / 794 = 3%

测试3: 使用Gunicorn 双核

毕竟我们的服务有两个核, 之前的测试也一直没有把单核占满!

测试命令:

# 使用Gunicorn启动Flask
gunicorn -w 2 -b 127.0.0.1:5001 perf_test:app   # 注意:这里使用的是【双核】哦
 
# wrk命令
wrk -d20s -t10 -c200 http://my-test-domain.com/performance_test_json
 

测试结果:

Running 20s test @ http://my-test-domain.com/performance_test_json
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   556.30ms  506.81ms   1.98s    66.58%
    Req/Sec     6.47     11.28   202.00     93.03%
  530 requests in 20.04s, 4.69MB read
  Socket errors: connect 0, read 0, write 0, timeout 132
Requests/sec:     26.45
Transfer/sec:    239.71KB
 

测试小结:

不出意外, 性能进一步提升, 而且很明显。

timeout比例: 132 / 530 = 24.9%

平均延时也下降到 556ms

测试3: 使用Gunicorn 单核 + Gevent

Gevent + Gunicorn 应该是一个很常见的组合。

什么是Gevent?

From : 廖雪峰的官方网站

Python通过 yield 提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。

gevent是第三方库,通过greenlet实现协程,其基本思想是:

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

直接使用Gevent其实还是要花一些时间, 不过让Gunicorn来包装使用, 就很简单了。具体请看下面的测试命令

测试命令:

# 使用Gunicorn启动Flask
pip install gunicorn[gevent] # 确保安装了gevent
gunicorn -w 1 -k gevent  -b 127.0.0.1:5001 perf_test:app    # 注意:这里使用的是单核哦
 
# wrk命令
wrk -d20s -t10 -c200 http://my-test-domain.com/performance_test_json
 

测试结果:

Running 20s test @ http://my-test-domain.com/performance_test_json
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   737.19ms  579.67ms   1.98s    59.03%
    Req/Sec     5.90     14.47   230.00     98.97%
  484 requests in 20.04s, 4.55MB read
  Socket errors: connect 0, read 0, write 0, timeout 174
Requests/sec:     24.15
Transfer/sec:    232.38KB
 

测试小结:

timeout 比例: 174 / 484 = 35.95% , 虽然不及双核的表现, 但是相比Gunicorn默认单核, 还是有所提升的

平均访问延时也从765 下降到 737ms。

测试4: Gunicorn + Gevent 双核

这个应该是最强搭配了

测试命令:

# 使用Gunicorn启动Flask
pip install gunicorn[gevent] # 确保安装了gevent
gunicorn -w 2 -k gevent  -b 127.0.0.1:5001 perf_test:app    # 注意:这里使用的是【双核】哦
 
# wrk命令
wrk -d20s -t10 -c200 http://my-test-domain.com/performance_test_json
 

测试结果:

Running 20s test @ http://my-test-domain.com/performance_test_json
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   591.00ms  543.56ms   1.97s    64.10%
    Req/Sec     6.79     13.67   181.00     98.77%
  537 requests in 20.06s, 4.79MB read
  Socket errors: connect 0, read 0, write 0, timeout 122
Requests/sec:     26.77
Transfer/sec:    244.58KB
 
 

测试小结:

  1. 相比测试3,使用原生双核, 很意外, 平均延时有所上升, 从556上升到现在591
  2. 但是总体的timeout还是有所下降, 从132 下降到122

整体测试小结

上面的测试结果小结如下:

  • Gunicorn 比原生的内置server 性能要快, 平均延时提升3%。 timeout的比例大大下降, 减少了约20%
  • Gunicorn双核的表现要比单核强不少, 平均延时又减少了 20% 这样, timeout的比例也减少了约 40%
  • Gevent 单核 比Gunicorn原生单核略强, 双核的表现可能跟测试用例有关, 表现并不明显

测试结果数据汇总

测试项目 平均延时(ms) Timeout数量 Timeout 比例
Flask内置Server 794 248 52.5%
Gunicorn 单核 765 187 39.3%
Gunicorn 双核 556 132 24.9%
Gunicorn + Gevent 单核 737 174 35.9%
Gunicorn + Gevent 双核 591 122 22.7%

测试后记:

因为之前我们的程序设计到登录, 而且登录的Session在进程内存之中, 没使用 Redis 来管理。 因此理论上来说只能单核进行。

所以最后采用的方案: Gunicorn + Gevent 单核

估计还会有下文: 如何迁移你的Flask程序 (因为当前的Flask的启动设定比较多, 直接使用Gunicorn启动甚至会发生无法访问的情况。。。)

本文原创,转载需要注明出处


以上所述就是小编给大家介绍的《Gunicorn性能测试》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

最高人民法院《关于行政诉讼证据若干问题的规定》释义与适用

最高人民法院《关于行政诉讼证据若干问题的规定》释义与适用

李国光 / 人民法院出版社 / 2002-9 / 30.0

为进一步深入贯彻实施《中华人民共和国行政诉讼法》,最高人民法院发布了《关于行政诉讼证据若干问题的规定》。本书即是对《行政证据规定》作出的充分的阐释。《行政证据规定》是我国第一部关于行政诉讼证据问题系统的司法解释,对我国行政审判的发展和行政诉讼制度的完善必将产生重要而深远的影响。本书对这一《行政证据规定》进行阐述,是为了让广大读者更具体深入的了解这一重要的规定。 本书均将《最高人民法院......一起来看看 《最高人民法院《关于行政诉讼证据若干问题的规定》释义与适用》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具