Twitter 転生した記念に Qiita 始めてみます。
タイトルのとおりですが、Flask を uWSGI @ HTTP で動かすと、ファイル投稿時に綺麗に 1 秒遅延する現象を確認しましたので、再現手順を紹介します。
これは curl
の仕様で Expect: 100-continue
ヘッダを付けてリクエストを発行するようになっていて、サーバにファイルを投稿していいかどうかお伺いを立てるために 1 秒待つということのようです。1
$ curl -v -s -XPOST -F file=@LICENSE localhost:5002
* Rebuilt URL to: localhost:5002/
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 5002 (#0)
> POST / HTTP/1.1
> Host: localhost:5002
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 1271
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------ebc5516179fb0a6c
>
* Done waiting for 100-continue
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 20
<
* Connection #0 to host localhost left intact
Took: 0:00:01.011157
これは HTTP/1.1 に準拠したものであるとのことです。2
uWSGI は Expect: 100-continue
のハンドリングに対応しており、 ini ファイルに以下の行を追加すると良いそうです。 1
http-manage-expect = 1
実験設定
上記リポジトリの通り、
- Flask を単独で起動した場合
- Flask を HTTP 設定の uWSGI を介して起動した場合
- Flask を uwsgi プロトコル設定の uWSGI を介して起動した場合
に関して実験を行っています。
1. Flask を単独で起動した場合
単に
$ flask run --host=0.0.0.0
で起動した場合です。
2. Flask を HTTP 設定の uWSGI を介して起動した場合
uWSGI を
http = 0.0.0.0:80
を含む設定で起動した場合です。
3. Flask を uwsgi プロトコル設定の uWSGI を介して起動した場合
uWSGI を
socket = /socket/uwsgi.sock
を含む設定で起動した場合です。
バージョン
Flask==1.1.1
uwsgi==2.0.18
実験結果
それぞれ curl
を使ってファイルを POST したときのレスポンス時間は以下のとおりです。
ここで、確認されている限りファイルは何でも良いので、 リポジトリの LICENSE
ファイルを使っています。
レスポンス時間 | |
---|---|
1. Flask 単独 | 0.067 |
2. Flask w/ uWSGI @ HTTP | 1.063 |
3. Flask w/ uWSGI @ uwsgi | 0.062 |
Flask を uWSGI @ HTTP で起動した場合のみ、レスポンス時間がちょうど 1 秒遅くなっていることが見て取れます。
今回は試行回数一回のデータを掲載していますが、何度やっても概ねこのレスポンスタイムになります。
※ 冒頭で説明したとおり、ここで 1 秒待っている主体は curl
であって、 Flask
や uWSGI
ではありません。
おわりに
Flask 単独だとこの現象は発生しないので、おそらく uWSGI が原因なんじゃないかという事で適当に issue を投げましたが、ひょっとしたら Flask のせいかもしれないし、合わせ技一本で発生しているのかもしれないし、よく分からないです。
詳しい方がいらっしゃいましたらぜひともご教示ください。
uWSGI のコントリビュータに教えてもらいました。1
とても勉強になりました。