内容简介:写了很多很多Flask的API, 但是一直偷懒, 没有使用Gunicorn来作为Web Server 来运行成。后来因为某个线上服务, 经常出现timeout的情况。 在已经采用了好一些措施的情况还是无法完全避免的情况下, 想到了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
测试小结:
需要注意的数字:
- 一共产生了472个requests
- 一共出现了248次timeout, 这个比例相当高了, 比例: 52.5%
- 平均访问延时: 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
测试小结:
- 相比测试3,使用原生双核, 很意外, 平均延时有所上升, 从556上升到现在591
- 但是总体的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性能测试》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 微服务测试之性能测试
- Go 单元测试和性能测试
- 性能测试vs压力测试vs负载测试
- SpringBoot | 第十三章:测试相关(单元测试、性能测试)
- Golang 性能测试 (2) 性能分析
- 随行付微服务测试之性能测试 原 荐
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。