CLOVER🍀

That was when it all began.

Gunicornを試してみる

これは、なにをしたくて書いたもの?

前に、uWSGIについてエントリを書きました。

uWSGIを試してみる - CLOVER🍀

今回は、同じくWSGIサーバーであるGunicornを試してみたいと思います。

Gunicorn - Python WSGI HTTP Server for UNIX

Gunicorn

Gunicornは、UNIX向けのPython WSGI HTTPサーバーです。

Gunicorn - WSGI server — Gunicorn 19.9.0 documentation

名前から想像できるかもしれませんが、RubyのUnicornから移植された、Preforkワーカーモデルのサーバーです。

いろいろなWebフレームワークと互換性があり、シンプルな実装のためリソース消費も少ないのが特徴だそうです。

確かに、uWSGIと比べるとドキュメントの量もぐっと少なくなります。

Python 2.6以上、Python 3.2以上に対応しているようです。

今回は、uWSGIで作成したソースコードを使って、Gunicorn上で動かすお題でやってみようと思います。

環境

今回の環境は、こちら。

$ python3 -V
Python 3.6.7

Gunicornをインストールする

まずは、Gunicornをインストールします。

Installation — Gunicorn 19.9.0 documentation

とりあえず、仮想環境を作成して

$ python3 -m venv venv
$ . venv/bin/activate

Gunicornをインストール。

$ pip3 install gunicorn

バージョン。

$ pip3 freeze
gunicorn==19.9.0

uWSGIの時に作った、簡単なWSGIアプリケーション。
simple-wsgi-app.py

def application(env, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [b'Hello WSGI!!']

こちらを、Gunicornで動かしてみます。

Running Gunicorn — Gunicorn 19.9.0 documentation

以下のような指定になるようです。

$ gunicorn simple-wsgi-app:application

構文的には以下で、「APP_MODULE」は「$(MODULE_NAME):$(VARIABLE_NAME)」で表現されます。

$ gunicorn [OPTIONS] APP_MODULE

「MODULE_NAME」がファイル名(.py除く)で、「VARIABLE_NAME」がWSGIで呼び出し可能なポイントの名前ですね。

デフォルトで8000ポートでリッスンしますが、ポート(バインドアドレス)を指定する場合は以下のようになります。

$ gunicorn -b :8000 simple-wsgi-app:application

設定項目は、こちら。

Settings — Gunicorn 19.9.0 documentation

確認。

$ curl -i localhost:8000
HTTP/1.1 200 OK
Server: gunicorn/19.9.0
Date: Sat, 13 Apr 2019 16:13:23 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain

Hello WSGI!!

ここで、uWSGIの時と同じように、Gunicornが利用するプロセス数、スレッド数を増やしてみましょう。

まず、デフォルトの状態だと以下のようになっています。

$ ps aux -L | grep gunicorn | grep -v grep
xxxxx  5473  5473  0.1    1  0.1  69352 22468 pts/4    S+   01:13   0:00 /path/to/venv/bin/gunicorn simple-wsgi-app:application
xxxxx  5477  5477  0.0    1  0.1  78064 19868 pts/4    S+   01:13   0:00 /path/to/venv/bin/python3 /path/to/venv/bin/gunicorn simple-wsgi-app:application

デフォルトで、ワーカー数(プロセス数)が1、スレッド数が1だからです。

Worker Processes

起動時の表示は、こんな感じでした。

[2019-04-14 01:13:10 +0900] [5473] [INFO] Using worker: sync
[2019-04-14 01:13:10 +0900] [5477] [INFO] Booting worker with pid: 5477

ワーカー数を4、スレッド数を2にしてみましょう。

$ gunicorn --workers 4 --threads 2 simple-wsgi-app:application

起動時の表示が、このようになります。

[2019-04-14 01:17:07 +0900] [5647] [INFO] Using worker: threads
[2019-04-14 01:17:07 +0900] [5650] [INFO] Booting worker with pid: 5650
[2019-04-14 01:17:07 +0900] [5651] [INFO] Booting worker with pid: 5651
[2019-04-14 01:17:07 +0900] [5652] [INFO] Booting worker with pid: 5652
[2019-04-14 01:17:07 +0900] [5653] [INFO] Booting worker with pid: 5653

この時点だと、プロセス数が増えただけですね。

$ ps aux -L | grep gunicorn | grep -v grep
xxxxx  5647  5647  0.1    1  0.1  74956 24004 pts/4    S+   01:17   0:00 /path/to/venv/bin/python3 /path/to/venv/bin/gunicorn --workers 4 --threads 2 simple-wsgi-app:application
xxxxx  5650  5650  0.0    1  0.1  83544 21180 pts/4    S+   01:17   0:00 /path/to/venv/bin/python3 /path/to/venv/bin/gunicorn --workers 4 --threads 2 simple-wsgi-app:application
xxxxx  5651  5651  0.0    1  0.1  83548 21052 pts/4    S+   01:17   0:00 /path/to/venv/bin/python3 /path/to/venv/bin/gunicorn --workers 4 --threads 2 simple-wsgi-app:application
xxxxx  5652  5652  0.0    1  0.1  83548 21052 pts/4    S+   01:17   0:00 /path/to/venv/bin/python3 /path/to/venv/bin/gunicorn --workers 4 --threads 2 simple-wsgi-app:application
xxxxx  5653  5653  0.0    1  0.1  83552 21052 pts/4    S+   01:17   0:00 /path/to/venv/bin/python3 /path/to/venv/bin/gunicorn --workers 4 --threads 2 simple-wsgi-app:application

スレッドが増えることは、どうやったら確認できるんでしょうね。負荷をかけたらいいのかな?

Djangoで作ったアプリケーションをGunicornで動かしてみる。

続いては、Djangoで作ったアプリケーションを動かしてみます。

Djangoで作ったアプリケーションのデプロイ方法は、ドキュメントに記載があります。

Integration

アプリケーションは、uWSGIのエントリで作成したものを使用します。

uWSGIを試してみる - CLOVER🍀

$ pip3 install Django


$ pip3 freeze
Django==2.2
...


$ django-admin startproject mysite
$ cd mysite
$ django-admin startapp myapp
$ cd mysite

URL設定とViewのコードだけ、再度記載しておきます。
myapp/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name = 'index'),
]

myapp/views.py

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    return HttpResponse('Hello Django!!')

プロジェクトディレクトリ配下にwsgi.pyがあるので、以下のように指定します。

$ gunicorn mysite.wsgi

この場合、ディレクトリのセパレーターが「.」に…?

これで、Djangoアプリケーションが起動します。

確認。

$ curl -i localhost:8000/myapp/
HTTP/1.1 200 OK
Server: gunicorn/19.9.0
Date: Sat, 13 Apr 2019 16:24:42 GMT
Connection: close
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 14

Hello Django!!

動きましたね。とりあえず、uWSGIと同じところまでは確認できましたよ、と。