SlideShare a Scribd company logo
Djangoアプリケーション 
パフォーマンスチューニング 
@hirokiky
話すこと 
Djangoアプリケーション高速化 
パフォーマンス測定ツール
話さないこと 
ミドルウェアパラメータ調整 
検証用データの作成方法 
なんか魔法みたいに速くなる技
自己紹介 
@hirokiky 
Python Django 好き 
ギョームで100万ユーザーくらいのサイト 
Django本体への貢献
Github 
https://github.com/hirokiky/
Djangoアプリ高速化 
SQLを吐きまくるコードは誰だ 
インデックス 
キャッシュキャッシュキャッシュ 
アプリケーション外
SQLを吐きまくるコードは誰だ 
● django-debug-toolbar 
dbログ出力
django-debug-toolbar 
デモ 
https://pypi.python.org/pypi/django-debug-toolbar
django-debug-toolbar
dbログ出力
dbログ出力設定例 
LOGGING['loggers']['django.db.backends'] = { 
'level': 'DEBUG', 
'handlers': ['console'] 
} 
'console'ハンドラーは標準出力に表示する想定
SQLを吐きまくるコードを倒す 
● .select_related/.prefetch_related 
.bulk_create / .update 
.count / .exists
.select_related (demo) 
● FK先のデータも一緒に取ってくる 
内部的にはJOINなどが走る
.prefetch_related (demo) 
● FK元のデータも一緒に取ってくる 
複数クエリを実行しPython側で結合
.bulk_create (demo) 
● 複数のオブジェクトを一度に作成
.update
.exist - countダメ
その他 
● .only / .defer 
.values / .values_list 
アプリケーションが複雑化しやすい....
QuerySetはlazy 
>>> articles = Article.objects.all() 
>>> articles = articles.filter(title__startswith='title') 
>>> print(articles) 
>>> 
>>> q = articles.filter(author_id=1) 
>>> print(q) 
ここでクエリ実行 
https://docs.djangoproject.com/en/1.7/topics/db/queries/#querysets-are-lazy
ここまでのまとめ 
● ORMが実行するSQLを知ろう 
ORMの特性を意識しよう 
他にも: https://docs.djangoproject.com/en/1.7/topics/db/optimization/
インデックス 
● 適切なインデックスを使おう 
結局相手にしてるのはRDB
インデックス 
1) 吐かれてるSQLをみて適応してく 
2) インデックスがかかるクエリに変更
吐かれるクエリは? 
検証環境などにデータたっぷりいれて 
画面をポチポチします 
JetProfilerなどがツールも優秀です
JetProfiler for MySQL 
http://www.jetprofiler.com/tour/
インデックスの貼り方 
ここでは話しません
インデックスがかかるクエリにする 
.extra: クエリの一部分を生SQLで書く 
.raw: クエリを生SQLで書く 
複雑化しやすいのでキャッシュとの兼ね合いです
ここまでのまとめ 
● クエリを眺めてインデックス適応 
好みのクエリを走るようにする 
あとそもそもテーブルの設計ちゃんとしましょう
キャッシュキャッシュキャッシュ 
キャッシュの種類と使いどころ 
Redisでのキャッシュ
キャッシュの種類 
レスポンスキャッシュ 
ビューキャッシュ 
テンプレートキャッシュ 
オブジェクトキャッシュ 
効果的 
https://docs.djangoproject.com/en/1.7/topics/cache/
テンプレートキャッシュ 
{% load cache %} 
{% cache 500 sidebar %} 
.. sidebar .. 
{% endcache %} 
https://docs.djangoproject.com/en/1.7/topics/cache/
キャッシュの使いどころ 
ユーザーに依存する表示は基本キャッシュ無理 
画面設計段階でどこキャッシュできるか考える
Redisでキャッシュ 
Redisならではの型を有効利用: 
* Set型でユニークユーザーの管理 
* SortedSet型でランキング 
http://redis.io/
まとめ 
ユーザーに近いほどキャッシュは有効 
あまり複雑化しないように設計
アプリケーション外 
セッションバックエンド変更 
静的ファイル圧縮 
DBのPrimary/Replica構成
セッションバックエンド変更 
Cacheバックエンド 
Redisのバックエンド
Redisバックエンド 
$ pip install django-redis-sessions 
SESSION_ENGINE = 'redis_sessions.session' 
https://pypi.python.org/pypi/django-redis-sessions
静的ファイル圧縮 
django-compressor か django-asset
django-compressor 
{% load compress %} 
{% compress css %} 
<link rel="stylesheet" href="/static/css/one.css" type="text/css"> 
<style type="text/css">p { border:5px solid green;}</style> 
<link rel="stylesheet" href="/static/css/two.css" type="text/css"> 
{% endcompress %} 
http://django-compressor.readthedocs.org/en/latest/
DBのMaster/Slave 
django-replicatedが便利 
レプリ遅延にも賢く対応
django-replicated 
$ pip install django-replicated 
DATABASES = {'default': {...}, 
'slave1': {...}} 
DATABASE_SLAVES = ['slave1'] 
DATABASE_ROUTERS = ['django_replicated.ReplicationRouter'] 
更新が master, 参照が slave になります 
https://github.com/yandex/django_replicated
レプリ遅延対策 
MIDDLEWARE_CLASSES = [ 
... 
'django_replicated.middleware.ReplicationMiddleware', 
] 
GET, HEADで slave, それ以外で master 
https://github.com/yandex/django_replicated
レプリ遅延対策 2 
from django_replicated.decorators import use_master, use_slave 
@use_master 
def my_view(request, ...): 
# GETで更新&参照するViewなんだぜ。。。 
Viewに強制指定 
https://github.com/yandex/django_replicated
まとめ 
ORMの使い方は基本としてマスター 
インデックス+キャッシュのバランス 
まんべんなくやっとくのが吉です
Funkloadでパフォーマンス測定 
負荷試験ツール (Pythonで書く) 
セッション付きのシナリオ 
静的ファイルの自動取得などリッチ 
https://funkload.nuxeo.org/
Funkload (テストシナリオ) 
1) 一覧画面 
2) 詳細画面 
3) 編集画面 
4) 更新 
5) 詳細画面
Funkload (demo) 
$ fl-run-test test_Wiki.py 
$ fl-run-bench test_Wiki TestWiki.test_update
Funkload 一覧画面
Funkload 詳細画面
Funkload 編集画面
Funkload 更新
Funkload 詳細画面
Funkload レポートビルド 
$ fl-run-test test_Wiki.py 
$ fl-run-bench test_Wiki TestWiki.test_update
レポートその他 
2レポート間の差分レポート 
複数レポートでのトレンドレポート
耐えるべき負荷は? 
アクティブユーザー10万人、1日100万PV 
ピーク時でその3倍として秒間34PV 
人間1人5秒/1ページとして同時接続数170 
このあたり模索中で良い方法などあれば教えてください
ここまでのまとめ 
FunkloadはPythonで書ける 
シナリオでかけるので信頼できる
全体まとめ 
ORMの扱いなどは当たり前にやっておく 
面倒、複雑なものは測定しつつ必要な分やる
感想 
カッコいいこと言っても結局 
設計とミドルウェアが重要 
どううまく使うかを考えましょう
出会い系 
オフィスアワー(会議室4/5)に13:15〜 
Sprint(3日目)
@hirokiky

More Related Content

Pycon2014 django performance