美文网首页程序员讲点故事工具癖
Python Async! 二十行代码的改变,让qps吞吐量高7

Python Async! 二十行代码的改变,让qps吞吐量高7

作者: StoryRecorder | 来源:发表于2018-07-14 19:51 被阅读59次

    响应变化,是敏捷的美德。

    团队一直采用python-flask框架做web开发,最近业务扩大规模,需要能够承载峰值为10000的qps,团队准备用GO语言写API接口,在此之前,我使用python3.5的新语法async/await改写了API,对协程做了初步的探索。

    代码都比较简单,我直接放在下面,让大家对新老API有个直观的了解。

    FLASK框架的API(以下称老接口):

    from flask import Flask, request, jsonify
    from models import get_question_analysis
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET'])
    def index():
        return 'hello world'
    
    @app.route('/api', methods=['POST'])
    def api():
        data = request.get_json()
        question = data['question']
        question_analysis = get_question_analysis(question)
        return jsonify(question_analysis)
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=5000, debug=False)
    

    使用ASYNC语法,aiohttp框架下的API(以下称新接口):

    from aiohttp import web
    from models import get_question_analysis
    
    async def index(request):
        return web.Response(text='Hello World')
    
    async def api(request):
        data = await request.json()
        question = data['question']
        question_analysis = await get_question_analysis(question)
        return web.json_response(question_analysis)
    
    app = web.Application()
    app.add_routes([web.get('/', index),
                    web.post('/api', api)])
    
    if __name__ == '__main__':
        web.run_app(app, host='0.0.0.0', port=5000)
    

    针对两个接口,我用了两种方法做测试,过程如下:

    方法一:用本机(macOS)ab(apache benchmark)直接做性能测试

    测试方法:在命令行输入ab -c [concurrency] -n [total requests] T 'application/json' —p [filename] http://localhost:5000/api

    通过更改"每秒并发数"和"服务进程数",得知:

    • 12个进程,500并发,老接口的理论qps值为550,而新接口的理论qps值为4023,提高了7倍
    • 1个进程,100并发,老接口的理论qps值为88,而新接口的理论值为522,提高了6倍


      ab数据对比

    优点:

    • ab很简单,macOS与linux命令行原生自带,直接可用,数据清晰

    缺点:

    1. 本机测试无法准确给出单个request的响应时间,实际业务中timeout的情况无法准确分析;
    2. qps值为理论值,实际业务中程序调度,机器负荷的花费无法考虑

    方法二:用grafana.***.net做压力测试

    测试方法:(蔽司的一个压测工具)模拟线上请求对API打压

    数据分析:在打压API时,会返回每次请求的响应时间csv

    为了满足业务50%请求的平均响应时间都在10ms以内的要求,我分别对新老接口(12个进程/台)进行了压力测试:

    • 新接口


      请求时间(new)
    • 老接口({qps: 400, avg: 25}, {qps: 300, avg: 14} {qps: 200, avg: 13})
      请求时间(old)

    可以看到,在3500的并发下,新接口都能保持良好的性能,50%的请求都能在7ms内完成,并且响应时间的均值为8ms;另一方面,老接口的性能就难以保证,在400并发下,平均响应时长高达27ms。

    到现在,我们应该知道python async的性能是非常优秀的,在我看来,接口的性能仍然有提升的空间,希望以后能够有更多的时间来探索、测试和分享。

    相关文章

      网友评论

        本文标题:Python Async! 二十行代码的改变,让qps吞吐量高7

        本文链接:https://www.haomeiwen.com/subject/mvmypftx.html