Flask+PyPy 大規模Web向けBlueprintで速度ベンチマーク取ってみた

  • 22
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

前回の記事でDjangoとFlaskとPyramidを比較して、Flaskいいなーとなったので早速試してみました。

FlaskというPython Webフレームワークにて大規模向けと言われているBlueprintチュートリアルに沿って構築した機能をベンチマークして比較しています。Blueprintとは複数の小さなアプリ毎(機能毎)にViewを切り分けるFlaskの機能です。

構築後Apache Benchを利用して、PyPy3 2.4とPython3.5を比較した ベンチマーク を取得しています。

ディレクトリ構成

デフォルトの単一Viewと異なりviewsディレクトリを設置して、その中に機能毎のviewを設置していきます。今回はrootreport 機能を追加してみました。

■ ディレクトリ構成
スクリーンショット 2015-12-11 16.36.56.png

テンプレートの抽象化

HTMLのHEADやBODYタグといった共通部分をmaster.html 切り分けて分離します。

master.html
<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset="utf-8" />
  <title>{% block title %}{% endblock %} - Hello Flask!</title>
  <link type="text/css" rel="stylesheet"
       href="{{ url_for('static',
                        filename='hello.css')}}" />
</head>
<body>

{% block body %}{% endblock %}

</body>
</html>
index.html
{% extends "master.html" %}

{% block title %}index{% endblock %}

{% block body %}
<h1>this is index page</h1><br />

<h3>report</h3>
<a href="{{ url_for('report.index') }}">report - index</a><br />
<a href="{{ url_for('report.report_list') }}">report - list</a><br />
{% endblock %}

■ index.htmlの描写結果
スクリーンショット 2015-12-11 16.41.33.png

URLの抽象化とトップページの定義

Flaskサーバはpython main.py コマンドで起動します。main.py に機能毎のURLを紐付けます。

main.py
# -*- coding: utf-8 -*-
from flask import Flask
from views import root, report


app = Flask(__name__)
# 機能毎のURLを定義
app.register_blueprint(root.app, url_prefix="/")
app.register_blueprint(report.app, url_prefix="/report")


if __name__ == '__main__':
    app.run(debug=True)

root機能の定義

サイトトップページを定義します。

root.py
# -*- coding: utf-8 -*-
from flask import render_template, Blueprint

# 第一引数の名称が、テンプレのurl_for内で呼び出すときの名称と紐づく
app = Blueprint("index",
                __name__,
                url_prefix='/<user_url_slug>')

# テンプレート内で呼び出すときは url_for('index.index')
@app.route("/")
def index():
    return render_template('root/index.html')

report機能の定義

report.py
# -*- coding: utf-8 -*-
from flask import Module, render_template, Blueprint

app = Blueprint('report',
                __name__,
                url_prefix='/<user_url_slug>')


# テンプレート内で呼び出すときは url_for('report.index')
@app.route('/', methods=['GET'], strict_slashes=False)
def index():
    return 'report index'


# テンプレート内で呼び出すときは url_for('report.report_list')
@app.route('/report_list', methods=['GET'], strict_slashes=False)
def report_list():
    return 'report - list'

PyPy3 2.4とPython3.5でベンチマーク

debug=Falseと設定して、Apache Benchコマンドで並列度100で10,000回requestしてみました。Python3.5の方が26%高速に動作しました。サーバ起動はpython main.py コマンドで行ったのでシングルプロセスでのベンチマークです。予想ではPyPyが圧倒的速度でぶっちぎると思っていたのですが蓋を開けてみたらPython3.5の方が早いという不思議な結果に終わりました。flaskはFlask==0.10.1です。次はDBアクセス有りで調査してみたいと思います。

スクリーンショット 2015-12-11 17.20.24.png

PyPy3ベンチ結果
>>>ab -n 10000 -c 100 http://localhost:5000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        Werkzeug/0.11.2
Server Hostname:        localhost
Server Port:            5000

Document Path:          /
Document Length:        398 bytes

Concurrency Level:      100
Time taken for tests:   20.783 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      5530000 bytes
HTML transferred:       3980000 bytes
Requests per second:    481.16 [#/sec] (mean)
Time per request:       207.829 [ms] (mean)
Time per request:       2.078 [ms] (mean, across all concurrent requests)
Transfer rate:          259.85 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   2.6      1      74
Processing:     3  205  53.6    199     762
Waiting:        3  205  53.1    199     760
Total:         24  206  53.0    199     763

Percentage of the requests served within a certain time (ms)
  50%    199
  66%    204
  75%    211
  80%    214
  90%    225
  95%    236
  98%    295
  99%    571
 100%    763 (longest request)

++++++++++++++++++++++++++
>>> python --version
Python 3.2.5 (b2091e973da6, Oct 19 2014, 18:30:58)
[PyPy 2.4.0 with GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.51)]
Python3.5ベンチ結果
>>>ab -n 10000 -c 100 http://localhost:5000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        Werkzeug/0.11.2
Server Hostname:        localhost
Server Port:            5000

Document Path:          /
Document Length:        398 bytes

Concurrency Level:      100
Time taken for tests:   16.380 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      5530000 bytes
HTML transferred:       3980000 bytes
Requests per second:    610.52 [#/sec] (mean)
Time per request:       163.795 [ms] (mean)
Time per request:       1.638 [ms] (mean, across all concurrent requests)
Transfer rate:          329.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   5.8      0     195
Processing:     3  161  44.7    148     475
Waiting:        3  161  44.5    148     475
Total:         59  162  43.9    148     476

Percentage of the requests served within a certain time (ms)
  50%    148
  66%    151
  75%    154
  80%    156
  90%    239
  95%    276
  98%    299
  99%    322
 100%    476 (longest request)

++++++++++++++++++++++++++4
>>> python --version
Python 3.5.0

並列度1なら平均応答速度1.8 - 2.5msで応答しました。いまのところFlaskすごく早い( ・ㅂ・)و