Edited at

Djangoのキャッシュ機能を使って画面表示をもっと高速化する Memcached編


はじめに

Djangoのキャッシュ機能を使って、画面表示の高速化にトライしてみました。

今回、キャッシュを保存する先はMemcahcedとしています。

その他の保存先としてファイルや、データベースを使うこともできます。

データベースをキャッシュとする方法や、キャッシュ設定前後の処理時間の比較は、前回の記事「Djangoのキャッシュ機能を使って画面表示を高速化する データベース編」を見てください。


この記事の構成


  1. Djangoの開発サーバーでMemcachedを使う方法について解説します

  2. MemcachedによりDjangoの動きがどのように変わったかを見てみます

ここで説明するのはあくまで開発サーバーでMemcachedを使う方法ですので、本番環境で使う場合にはsettings.pyの設定を適宜変更する必要があります。

本番環境の一例としてHeroku環境のDjangoでMemcachedを使う方法については以下を参照ください。


環境


  • macOS High Sierra 10.13.6

  • Python 3.7.0

  • Django 2.1

  • python-memcached 1.59


1. Djangoの開発サーバーでMemcachedを使う方法


1.1. Memcachedをインストールする

$brew install memcached


1.2. Memcachedを起動する

$ brew services start memcached


1.3. python-memcachedをインストールする

pythonでmemcashedを使う為に、python-memcachedをインストールします。

(myvenv) $ pip install python-memcached


1.4. settings.pyにキャッシュの設定を行う

settings.pyに以下を追加します。


settings.py

CACHES = {

'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}

BACKENDの部分がキャッシュの保存先の種類を示していて、Memcachedを使う場合はmemcached.MemcachedCacheと指定します。

LOCATIONの部分は、Memcahcedが稼動するサーバーとポート番号を指定します。

Djangoの開発サーバーのIPアドレスが127.0.0.1なのであれば、127.0.0.1:11211と指定します。

11211は、Memcachedのデフォルトのポート番号です。


1.5. キャッシュする対象を指定する

今回はアクセスの多い特定のURLのページだけをキャッシュすることにしました。そのような場合は、urls.pyでキャッシュする対象を指定します。

もともとのurls.pyが以下のような内容だった場合・・・


urls.py(修正前)

from django.urls import path

from . import views

urlpatterns = [
path('', views.ArticleListView.as_view(), name='article_list'),
# 略
]


以下のようにcache_page関数を使います。秒数の部分は60 * 15と記述することで15分であることをわかりやすくしています。


urls.py(修正後)

from django.urls import path

from django.views.decorators.cache import cache_page # ここを追加
from . import views

urlpatterns = [
# cache_page(秒数)(ビュー)を追加する
path('', cache_page(60 * 15)(views.ArticleListView.as_view()), name='article_list'),
# 略
]



2. キャッシュによりDjangoの動きがどのように変わったかを見てみる

キャッシュ設定前後で何が変わったのかをdjango-debug-toolbarの機能を使って見てみることにします。

django-debug-toolbarの設定方法は以下を参考にさせていただきました。

Djangoメモ(14) : Django Debug Toolbarでデバッグ情報を表示


2.1. キャッシュ設定無し(Memcachedを停止)

$ brew services stop memcached

スクリーンショット 2018-12-14 13.47.08.png

画面は自作のDjangoアプリです。

右端の黒いツールバー部分がdjango-debug-toolbarによって表示されている情報です。

「時刻」に表示されているのがCPUの処理時間だと思われます。約163ミリ秒かかっています。

なお、SQLは3本発行されてます。

ちなみに処理時間の内訳は以下のようになっています。

スクリーンショット 2018-12-14 13.52.32.png


2.2. キャッシュ設定あり(memcached起動中)の時の初回のアクセス

前回の記事ではキャッシュの保存先をデータベースとしましたが、その場合、初回アクセス時に関してはキャッシュテーブルへの書き込みが発生する都合上、逆に処理時間が増えてしまうという弊害がありました。


処理時間が約335ミリ秒(+154ミリ秒)に増えてしまいました。

また、SQLの発行本数も14本(+9本)に増えています。

SQLの本数が増えたのはキャッシュ用のテーブルへの読み書きを行ったためのようです。

キャッシュの有無を調べるSQL、(キャッシュが無いので)ページの情報をキャッシュへ書き込むSQLが発行されていました。


Memcachedの場合はどうなるのでしょうか?

Memcachedを起動した上で、画面にアクセスします。

$ brew services start memcached

スクリーンショット 2018-12-14 14.00.13.png

Memcached停止中での画面アクセスと比較して、処理時間は約164ミリ秒(+1ミリ秒)とほぼ変化はありません。

また、SQLの発行本数についても3本のままで、増加はありません。


2.3. キャッシュ設定ありの時の2回目のアクセス

スクリーンショット 2018-12-14 14.15.21.png

処理時間が約9ミリ秒と大幅に減りました(-154ミリ秒)。

また、SQLの発行本数は0本(-3本)となりました。


まとめ


Memcachedの場合

条件
CPU処理時間(ms)
SQL本数

キャッシュ設定無し
163
3

キャッシュ設定あり・初回アクセス
164
3

キャッシュ設定あり・2回目のアクセス
10
0

たったの1回ずつしかアクセスしていないので厳密な検証ではありませんが、初回のアクセスにおいてもキャッシュ設定無しの時より画面表示に時間がかかってしまうようなことは無く、2回目以降のアクセスは大幅に時間が短くなることが期待できるようです。


ちなみにデータベースの場合

同一のDjangoアプリケーションで、キャッシュの保存先をデータベースとした場合の処理時間も記載しておきます。

この結果を見ると、キャッシュの保存先はデータベースよりもMemcachedとした方が良さそうですね。

条件
CPU処理時間(ms)
SQL本数

キャッシュ設定無し
163
3

キャッシュ設定あり・初回アクセス
326
12

キャッシュ設定あり・2回目のアクセス
22
2


参考