Django/Mezzanine Database Cache の設定をしてみる


Mezzanine の Blog list ページが結構重いので、
Cache を使用して改善できないかと考えました。
潤沢にメモリーがあったりするわけではないので、そこまで改善は見込めなさそうですが、
database cache を使用して改善できないか試してみます。


0. 前提

以下の環境で実行しています。

  • OS
    CentOS release 6.9 (Final)

  • Python Version
    Python 2.7.8

  • Package (必要そうなものだけ抜粋)
    Django (1.10.6)
    Mezzanine (4.2.3)

  • DATABASE
    psql (8.4.20)


1. 参考


2. 実施したこと

2-0. cache Middleware の確認

"mezzanine.core.middleware.UpdateCacheMiddleware"と、 "mezzanine.core.middleware.FetchFromCacheMiddleware"が設定されていれば、
サイトごとのキャッシュ(URL単位でのキャッシュ)が使用できます。

Mezzanine のプロジェクト作成時に作られるsettinngs.py には、 デフォルトで記載されているので、特に設定は不要です。

  • MIDDLEWARE_CLASSES の設定抜粋
    MIDDLEWARE_CLASSES = (
        "mezzanine.core.middleware.UpdateCacheMiddleware",
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.contrib.auth.middleware.AuthenticationMiddleware",
        "django.middleware.common.CommonMiddleware",
        # ADD SessionAuthenticationMiddleware
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        "django.middleware.csrf.CsrfViewMiddleware",
        "django.contrib.messages.middleware.MessageMiddleware",
        # ADD XFrameOptionsMiddleware
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    
        "mezzanine.core.request.CurrentRequestMiddleware",
        "mezzanine.core.middleware.RedirectFallbackMiddleware",
        "mezzanine.core.middleware.TemplateForDeviceMiddleware",
        "mezzanine.core.middleware.TemplateForHostMiddleware",
        "mezzanine.core.middleware.AdminLoginInterfaceSelectorMiddleware",
        "mezzanine.core.middleware.SitePermissionMiddleware",
        # Uncomment the following if using any of the SSL settings:
        # DEL "mezzanine.core.middleware.SSLRedirectMiddleware",
        "mezzanine.pages.middleware.PageMiddleware",
        "mezzanine.core.middleware.FetchFromCacheMiddleware",
    )
    

2-1. cache 用の table を作成する

データベース Cache を使用する前に以下のコマンドを実行して、cache 用のテーブルを作成します。

python2.7 manage.py createcachetable blog_cache

戻りが何もないコマンド だったので、何が起こっているのかよくわかりませんでしたが、
python2.7 manage.py dbshell でテーブルを確認したところ指定したテーブルが作成されていました。
以下、作成されたテーブルの構成情報になります。

\d blog_cache
------------------------------------------------------
テーブル "public.blog_cache"
  カラム   |            型            |  修飾語  
-----------+--------------------------+----------
 cache_key | character varying(255)   | not null
 value     | text                     | not null
 expires   | timestamp with time zone | not null
インデックス:
    "blog_cache_pkey" PRIMARY KEY, btree (cache_key)
    "blog_cache_expires" btree (expires)
------------------------------------------------------

2-2. settings.py に CACHES 定義を追加

##############################
# Cache Middleware Settings
##############################
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 60 * 60 * 24 
CACHE_MIDDLEWARE_KEY_PREFIX = 'middleware'

# KEY_FUNCTION
from django.utils.encoding import smart_str
def make_key(key, key_prefix, version):
    return '_'.join([key_prefix, str(version), smart_str(key)])

##########################
# CACHE SETTINGS
##########################
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'blog_cache',
        'TIMEOUT': 60 * 60 * 24 ,
        'OPTIONS': {
                    'MAX_ENTRIES': 1000, 
                    'CULL_FREQUENCY': 2,
               },
        'KEY_PREFIX' : 'blog',
        'VERSION' : 1,
        'KEY_FUNCTION' : make_key
    }
}
  • ミドルウェア設定の説明 最初よくわかっていなかったですが、ミドルウェアによる Cache の有効期限の設定は、
    はこちらの値が効いてきます。TIMEOUT の設定が効くと思い込んでおり、
    動作を理解するのに小2時間程度かかってしまいました。

    • CACHE_MIDDLEWARE_ALIAS
      ミドルウェア側が使用するCache のエイリアス名です。デフォルトは ‘default’

    • CACHE_MIDDLEWARE_SECONDS
      ミドルウェアのCache の有効期限、60 * 60 * 24秒で、1日を設定しています。デフォルトは600秒です。

    • CACHE_MIDDLEWARE_KEY_PREFIX
      ミドルウェアが作成するCacheキーのprefix になります。
      KEY_PREFIX にさらに追加される形で付与されそうです。前なのか後なのかは、ちょっとわかりませんでした。

  • CACHES設定の説明

    • BACKEND
      DB キャッシュの場合は、django.core.cache.backends.db.DatabaseCache を設定します。
    • LOCATION
      キャッシュテーブル名を設定します。
    • TIMEOUT
      キャッシュを保持する秒数を、60 * 60 * 24秒で、1日を設定しています。
      ミドルウェアのCacheのみ今回は使っているのでこの値は使用されません。
      template レベル view レベルのCache などの場合にこの値は効いてくるのかと。
    • OPTIONS MAX_ENTRIES
      保持するキャッシュの数を設定します。
    • OPTIONS CULL_FREQUENCY
      キャッシュの保持数が閾値を超えた場合どのくらいのキャッシュ数を消すかを指定します。
      MAX_ENTRIES 1000 で、OPTIONS CULL_FREQUENCYが、2 なので、 超えた場合は、500 エントリが削除されます。
    • KEY_PREFIX
      キャッシュのキー値に付与するprefix名を指定
    • VERSION
      キャッシュのキー値に付与するversion番号を指定
    • KEY_FUNCTION
      キャッシュのキー値生成に使用する関数を指定

3. Mezzanine の拡張された Cache 設定

基本的に Django の Cache 設定に従って動作しますが、以下の点が異なるようです。

3.1 Cache Middleware の設定

  • CACHE_ANONYMOUS_ONLYFalse を設定しても無視され、認証ユーザーには、キャッシュされていない、生のコンテンツが表示される。

  • キャッシュのキーには、Site の ID と、アクセスしているデバイスの種類(mobileとか、Desktopなど)が含まれる。

  • キャッシュキーは Vary ヘッダーを考慮しないため、末認証ユーザーにはURLごとに同じページコンテンツを返す。

3.2 templatetag

末認証ユーザーに、ユーザーごとのコンテンツを返したい場合は、
template の対象箇所を nevercacheendnevercache タグで囲む。

3.3 MINT CACHE

CACHE_SET_DELAY_SECONDS という設定を追加することで、
キャッシュエントリの有効期限の値がキャッシュエントリ自体とともにキャッシュに保存される、
ミントキャッシングと呼ばれる手法を使用することができます。
使用される実際の有効期限は、指定された有効期限にCACHE_SET_DELAY_SECONDS設定値を加えた値が設定されます。
キャッシュミスが実際には起こらないこと、および(ほぼ)1つのクライアントだけがキャッシュエントリの作成を実行することを保証できます。

Mezzanine の設定を値についての感想。

  • 2.1 Cache Middleware の設定
    CMS用途で使うことを想定するとこの動作で問題がないように思います。

  • 2.2 templatetag
    これは、個人的な使用用途では設定する必要はないと、判断しました。

  • 2.3 MINT CACHE
    これは正直あまり理解できておりません。。
    設定なし(0秒)でとりあえず置いておくことにしました。


4. Cache設定後のパフォーマンス

Cache なしの場合、1.7秒表示でかかっていたのが、
0.5秒程度に改善されました。

以上です。

コメント