1. ホーム
  2. Django

Djangoキャッシュの説明

2022-03-02 08:44:37

キャッシュ(Cache)は、パフォーマンスの高いウェブサイトを作り、ユーザー体験を向上させるために非常に重要ですが、私たちのようなPoundlandしか使えないコーダーにとって最も重要なことは、その使い方を学ぶことです。今日は、キャッシュ Cache のアプリケーションシナリオとその仕組みを見て、Django で Cache をセットアップしてそれらを使用する方法を詳しく説明します。

キャッシュCacheとは

キャッシュとは、データの読み取りを高速化できるメディアの総称であり、データの読み取りを高速化できる他の記憶方式も指す。一般的には一時的なデータを保存するために使用され、一般的な媒体は読み出しが非常に速いメモリである。一般的に、メモリやハードディスクなどから一度に読み出すよりも、データベースから必要なデータを複数回抽出する方がコストがかかると言われている。中規模から大規模のWebサイトでは、キャッシュを利用してデータベースへのアクセス回数を減らすことが、サイトのパフォーマンスを向上させる鍵のひとつとなります。

キャッシュを使用する理由 キャッシュ

Django では、ユーザのリクエストがビューに到達すると、ビューはまずデータベースからデータを取得し、動的レンダリングのためのテンプレートに入れ、レンダリング結果がユーザが見るページとなります。もしユーザがリクエストのたびにデータベースからデータをフェッチしてレンダリングしていたら、サーバにストレスがかかるだけでなく、クライアントからすぐにレスポンスが得られないので、パフォーマンスが大きく低下します。もしレンダリング結果をより高速なキャッシュに入れることができれば、リクエストが来るたびに、まずキャッシュに対応するリソースがあるかどうかをチェックし、もしあれば、直接キャッシュから取り出してレスポンスを返し、データのフェッチとレンダリングの時間を節約し、システムのパフォーマンスを大幅に改善できるだけでなく、ユーザーエクスペリエンスも改善することができます。

実際のブログの例を見てみましょう。トップページにアクセスするたびに、以下のようなビューがデータベースから投稿のリストを取得し、テンプレートにレンダリングしています。ほとんどの場合、私たちのブログはそれほど頻繁に更新されないので、投稿のリストは一定です。これでは、ユーザーが一定期間に何度もトップページにアクセスするたびに、データベースから同じデータを再読み込みしなければならず、大きな無駄が発生してしまいます。

from django.shortcuts import render

def index(request):
    # Read database etc and render to web page
    article_list = Article.objects.all()
    return render(request, 'index.html', {'article_list': article_list})


キャッシュ Cache を使うことで、この問題を解決することができます。ユーザーが初めてブログのホームページにアクセスしたとき、データベースから記事のリストを取り出し、キャッシュに保存します (セットアップによっては、一般的にメモリに保存されます)。ユーザがある単位時間内に再びホームページを訪れたとき、 Django はまずキャッシュが期限切れかどうかを調べ (この例では 15 分) 、次にキャッシュに記事リストリソースが存在するかどうかを調べ、存在すればキャッシュから直接データを読み込んで、テンプレートをレンダリングします。

from django.shortcuts import render
from django.views.decorators.cache import cache_page


@cache_page(60 * 15) # number of seconds, here means cache 15 minutes
def index(request):
    article_list = Article.objects.all()
    return render(request, 'index.html', {'article_list': article_list})

注意: Django でキャッシュを使用する前に、必要な設定を行う必要があります。

Cacheキャッシュの活用シーン

キャッシュは、主に高いページリアルタイムパフォーマンスを必要としないページで使用されます。キャッシュに保存されるデータは、通常、頻繁にアクセスされ、頻繁に変更されることはありません。いくつかのアプリケーションの例を見てみましょう。

  • ブログの記事。ユーザーが1日に1回記事を更新すると仮定して、1日後に更新されるブログの1日分のキャッシュを設定することができます。

  • ショッピングサイト。商品の説明情報はほとんど変化しないが、購入個数はユーザーに応じてリアルタイムに更新する必要がある。アイテム説明情報のみをキャッシュすることも可能です。

  • Webページのスニペットをキャッシュする。例えば、ページナビゲーションメニューとフッター(Footer)をキャッシュします。

Djangoのキャッシュ設定

Django で提供されているキャッシュの方法はいくつかあり、キャッシュを使うには、まず settings.py で設定し、それを適用する必要があります。キャッシング媒体によっては、異なるキャッシングバックエンド Backend を設定する必要があります。

Memcachedキャッシュ

Memcached はインメモリベースのキャッシュで、Django がネイティブにサポートする最速かつ最も効率的なキャッシュシステムです。ほとんどのシナリオでは、データがサーバサイドでキャッシュされる Memcached を使うことを推奨します。memcached プラグイン python-memcached と pylibmc を使用する前に pip 経由でインストールする必要があり、複数のサーバで同時に memcached をサポートすることができます。

pyhon-memcachedを使用するための設定です。

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

# unix soket
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'unix:/tmp/memcached.sock',
    }
}   

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
        # We can also weight the cache machines, the ones with higher weights take more requests, as follows
        'LOCATION': [
            ('172.19.26.240:11211',5),
            ('172.19.26.242:11211',1),
        ]
    }
 }

データベースキャッシング

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }

ファイルシステムキャッシュ

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',# this is the path to the folder
        #'LOCATION': 'c:\foo\bar',# example for windows
    }
}

ローカルメモリーキャッシュ

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
}

Djangoのコードでキャッシュを使用する方法

Cache を設定したら、コードで Cache を使用する方法が 3 つあります。

  • viewViewで使用する

  • ルーティングのURLConfで使用

  • テンプレートでの使用

viewViewでキャッシュを使用する

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)
def my_view(request):
    ...

ルーティングされたURLConfでキャッシュを使用する

これは私が好む方法で、論理的な部分を担当するビューを修正する必要がないのです。

from django.views.decorators.cache import cache_page

urlpatterns = [
    path('foo/<int:code>/', cache_page(60 * 15)(my_view)),
]

テンプレートでキャッシュを利用する

{% load cache %}
{% cache 500 sidebar request.user.username %}
    ... sidebar for logged in user ...
{% endcache %}

ほとんどのコーダにとって、django でキャッシュを使う方法だけ知っていればよく、選択したメディアへのデータの保存方法や、キャッシュが期限切れかどうかを django が判断する方法など、django バックエンドの動作の詳細については知る必要はないでしょう。

Djangoでキャッシュを使用するための高度なヒント

ここでは、Django でキャッシュを使うための高度なテクニックをいくつか取り上げます。

cache_controlの使用

一般的に、ユーザーは2種類のキャッシュに直面します。自分のブラウザのキャッシュ(プライベートキャッシュ)とプロバイダのキャッシュ(パブリックキャッシュ)です。パブリックキャッシュは複数のユーザーによって使用され、他のユーザーによって制御されます。そのため、銀行の口座番号がパブリックキャッシュに保存されるなど、遭遇したくない機密データに関する問題が発生する。したがって、ウェブアプリケーションは、どのデータがプライベートで、何がパブリックであるかを、何らかの方法でキャッシュに伝える必要があります。

解決策は、ページキャッシュがプライベートであるべきであることを示すことです。Django でこれを行うには、ビューモディファイア cache_control を使います。

from django.views.decorators.cache import cache_control


@cache_control(private=True)
def my_view(request):
# ...

このモディファイアは、バックグラウンドで適切な HTTP ヘッダを送信する役割を果たします。

キャッシュパラメータを制御する方法は、他にもたくさんあります。例えば、HTTP ではアプリケーションで以下のようなことが可能です。

  •     ページがキャッシュされる最大時間を定義します。

  •     キャッシュが常に新しいバージョンをチェックし、更新がないときのみキャッシュされたコンテンツを渡すかどうかを指定します。

Django では、これらのキャッシュパラメータは cache_control ビューモディファイア を使って指定できます。以下の例では、 cache_control は、アクセス毎にキャッシュを再検証し、最大 3600 秒間キャッシュされたバージョンを保存するように指示しています。

from django.views.decorators.cache import cache_control


@cache_control(must_revalidate=True, max_age=3600)
def my_view(request):
# ...

cache_control() では、任意の有効な Cache-Control HTTP ディレクティブが有効です。以下はその完全なリストです。

  • public=True

  • private=True

  • no_cache=True

  • no_transform=True

  • must_revalidate=True

  • proxy_revalidate=Trueを指定します。

  • max_age=num_seconds

  • s_maxage=num_seconds

vary_on_headersの使用

デフォルトでは、 Django のキャッシュシステムは、リクエストされたパス (例 blog/article/1) を使ってキャッシュキーを作成します。つまり、リクエストヘッダ中のクッキーや言語の違いを考慮するために Vary on headers 通知キャッシュ機構を使わない限り、同じパスをリクエストする異なるユーザは、クライアント側のユーザエージェント、クッキー、言語の設定に関係なく、同じキャッシュバージョンを取得することになります。

Django でこれを行うには、便利な vary_on_headers ビューデコレータを使用します。例えば、以下のコードは、キャッシュされたデータを読み込む際に User-Agent と Cookie の違いを考慮するよう Django に指示します。

from django.views.decorators.vary import vary_on_headers


@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
    ...

never_cacheでキャッシュを無効にする
ヘッダでキャッシュを完全に無効にしたい場合は、 django.views.decorators.cache.never_cache デコレータを使うことができます。ビューでキャッシュを使わない場合、サーバサイドは間違いなくキャッシュしませんが、 ブラウザのようなユーザのクライアントはまだいくつかのデータをキャッシュしているので、 never_cache を使ってクライアントサイドのキャッシュを無効にすることができます。

from django.views.decorators.cache import never_cache

@never_cache
def myview(request):
# ...

朝から頑張ってますので、気軽に声をかけてくださいね。もしこの記事が楽しくなければ、私のWeChat公開番号で気軽にフォローしてください。