thirose’s blog

openstackやpythonなどなど

flask+gunicornでgeventを使い、非同期処理にする

flask+gunicornなバックエンドでworker-classがデフォルトのsyncで同期処理をしていたのを非同期処理ができるように設定を変更しました。 同期処理の何が問題かというと、backendの処理に時間がかかる and プロセス数以上にリクエストがきてしまった場合、process数より多かった分のリクエストが待ち状態になりtimeoutになることがあります。
このような問題を解決すべくgeventを使い非同期で処理できるようにする方法をまとめました。

そもそもgunicornのワーカークラスには - sync - gevent - eventlet - tornado - gthread

と5つ存在していて今回はgeventを選択しました。geventはgreenletをベースとした非同期ワーカーです。

pip install gevent

でインストールでき,
起動時に-k WORKER_NAMEまたは--worker-class WORKER_NAMEのどちらかのオプションで指定すれば起動できます。 コードに対しての変更は特に必要ないです。

以下のように処理されます。 f:id:hirosetakahito:20181108175031p:plain

今回検証に使った簡易的なサーバとスクリプト

request script

import json
import requests


def register_name(self):
    url = 'http://127.0.0.1:5000/'
    res = requests.post(url)
    return res 


if __name__ == '__main__':
    result = register_name('test01')

proxy server

from flask import Flask
import requests

@app.route('/')
def register():
    url = 'https://127.0.0.1:5001'
    request.post(url)
    return "Created", 201 

if __name__ == '__main__':
    app.run(processes=5, port=5000)

backend server

from flask import Flask
app = Flask(__name__)

@app.route('/')
def wait_time():
    time.sleep(60)
    return "Created", 201

if __name__ == '__main__':
    app.run(port=5001, processes=10)

変更後の注意

非同期にすることで裁く量が増える場合があるので、MySQLなど別のところで問題が発生する可能性があります。 そのため、事前にconnection数など確認しておくと良いかもしれません。