Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Django + 非同期ワーカー コトハジメ

Django + 非同期ワーカー コトハジメ

更新:2013-10-23
バージョン:0.1.2
作者:@voluntas
URL:http://voluntas.github.io/

環境

Python:2.7.5
MySQL:5.6.14
redis:2.6.16

概要

C 拡張 API を使っている MySQL-Python は gevent のパッチが当てられないため使えないので PyMySQL を使用する

  • Django + Gunicorn + Gevent 使えるようにする
  • Django で MySQL-Python を使わず PyMySQL を使う
  • 全てを非同期で実行出来るように gevent のパッチを当てる
  • Celery の処理を Gevent を使って非同期にする
  • gunicorn + meinheld を使う

TODO

  • Redis との連携

PyMySQL + Django

インストール

gevent と PyMySQL は Git リポジトリから開発版をインストールする

celery / django-celery は後ほど登場します

$ pip install -r requirements.txt

requirements.txt:

Cython==0.19.1
Django==1.5.4
-e git+https://github.com/PyMySQL/PyMySQL.git#egg=PyMySQL
-e git+https://github.com/surfly/gevent.git#egg=gevent
-e git+https://github.com/mopemope/meinheld.git#egg=meinheld
gunicorn==18.0
uWSGI==1.9.18.1
redis==2.8.0
celery==3.0.23
django-celery==3.0.23

manage.py

snowflake は仮のアプリ名なので置き換える事

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "snowflake.settings")

    from gevent import monkey
    monkey.patch_all()

    import pymysql
    pymysql.install_as_MySQLdb()

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'snowflake',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

INSTALLED_APPS = (
    ...
    # 追加
    'gunicorn',
    ...
)

syncdb

MySQL-python は未インストール

$ python manage.py syncdb
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): no
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

起動

run_gunicorn

$ python manage.py run_gunicorn -w 1 -k gevent --worker-connections=4096 --backlog=1000
2013-09-22 13:35:14 [43326] [INFO] Starting gunicorn 18.0
2013-09-22 13:35:14 [43326] [INFO] Listening at: http://127.0.0.1:8000 (43326)
2013-09-22 13:35:14 [43326] [INFO] Using worker: gevent
2013-09-22 13:35:14 [43329] [INFO] Booting worker with pid: 43329

uWSGI

まだ未完成

$ uwsgi --gevent 100 --socket :3031 --module myapp

meinheld

まだ未完成

$ python manage.py run_gunicorn -w 2 --worker-connections=4096 --backlog=1000 --worker-class="egg:meinheld#gunicorn_worker"
2013-10-22 11:22:45 [22724] [INFO] Starting gunicorn 18.0
2013-10-22 11:22:45 [22724] [INFO] Listening at: http://127.0.0.1:8000 (22724)
2013-10-22 11:22:45 [22724] [INFO] Using worker: egg:meinheld#gunicorn_worker
2013-10-22 11:22:45 [22727] [INFO] Booting worker with pid: 22727
2013-10-22 11:22:45 [22728] [INFO] Booting worker with pid: 22728
2013-10-22 11:22:45 [22729] [INFO] Booting worker with pid: 22729
2013-10-22 11:22:45 [22730] [INFO] Booting worker with pid: 22730

Celery

broker には簡単に使えて安定している redis を使う

高負荷対策で使う場合は RabbitMQ を検討すると良い

redis のダウンロードから動作までは以下を参照

https://gist.github.com/voluntas/21759d5c45aacc0e6656#redis

設定

非同期タスクキューへの接続も Gevent を使ってみる

settings.py に Celery の設定を追加する

INSTALLED_APPS = (
    ...
    'gunicorn',
    # 追加
    'djcelery',
    ...
)

# celery

import djcelery
djcelery.setup_loader()

BROKER_URL = 'redis://127.0.0.1:6379/4'

起動

  • -Q は --queues
  • -P は --pool
  • -c は --concurrency
$ python manage.py celery worker -Q celery_gevent -P gevent -c 1024

 -------------- celery@192.0.2.1 v3.0.23 (Chiastic Slide)
---- **** -----
--- * ***  * -- Darwin-12.5.0-x86_64-i386-64bit
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> broker:      redis://127.0.0.1:6379/4
- ** ---------- .> app:         default:0x10ea3d510 (djcelery.loaders.DjangoLoader)
- ** ---------- .> concurrency: 1024 (gevent)
- *** --- * --- .> events:      OFF (enable -E to monitor this worker)
-- ******* ----
--- ***** ----- [queues]
 -------------- .> celery_gevent: exchange:celery_gevent(direct) binding:celery_gevent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment