自動化無しに生活無し

WEB開発関係を中心に備忘録をまとめています

DjangoのセッションをRedisで管理する

thumbnail

DjangoのセッションをRedisで管理するメリット

  • DB(ディスク)ではなくRedis(RAM)になるので、セッション管理が高速化される
  • 複数のアプリでセッション情報を共有できる
  • マルチノード構成を使って、負荷分散・可用性を高めることができる
  • TTLでセッションの削除を自動化できる。(DBの場合、能動的に削除しない限りセッション情報がそのまま残る)
  • Django-Channelsなどの非同期セッションと相性が良い(DBの場合、同期的なORMしかできないためボトルネックが生まれる)

django-redis のインストール

pip install django-redis 
Copy

settings.py の設定

# Redisをセッションエンジンとして設定
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

# Redisのキャッシュ設定
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",  # RedisのURL(適宜変更)
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "SOCKET_TIMEOUT": 5,  # 接続タイムアウト(秒)
        }
    }
}

# セッションの有効期限設定
SESSION_COOKIE_AGE = 86400  # 1日(秒)
SESSION_SAVE_EVERY_REQUEST = False  # セッションを毎回保存しない
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # ブラウザを閉じてもセッションを維持
Copy

まず、

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
Copy

とすることで、djangoのセッション管理をキャッシュで行うようにすることができる。

キャッシュの設定。django内にあるデフォルトのRedisバックエンドではなく、先程インストールしたdjango_redisを使う。

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",  # RedisのURL(適宜変更)
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "SOCKET_TIMEOUT": 5,  # 接続タイムアウト(秒)
        }
    }
}
Copy

Redisが何らかの影響で応答不能になった場合、5秒でタイムアウトする。

この設定をするだけで、セッション情報はすべてRedisで管理されるようになる。

これで高速な認証が実現され、WebSocketの連携時にもボトルネックが発生しない。

管理サイトにログインをした後、Redis内に保存されているセッションを取り出すには?

127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> KEYS *
1) ":1:django.contrib.sessions.cachemmoh6r4amm0gm7fn3l3sovyh48f8o9t8"
127.0.0.1:6379[1]> TYPE ":1:django.contrib.sessions.cachemmoh6r4amm0gm7fn3l3sovyh48f8o9t8"
string
127.0.0.1:6379[1]> GET ":1:django.contrib.sessions.cachemmoh6r4amm0gm7fn3l3sovyh48f8o9t8"
"\x80\x04\x95\xaf\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\r_auth_user_id\x94\x8c\x011\x94\x8c\x12_auth_user_backend\x94\x8c)django.contrib.auth.backends.ModelBackend\x94\x8c\x0f_auth_user_hash\x94\x8c@3b52c847036e247aec08277f3c96801f08729b54fa138dfeaa22c9b99d8e0053\x94u."
Copy

まず、SELECT 1コマンドでRedis DBを指定する。

続いて、KEYS *で保存されているすべてのKeyを取り出す。(※本番環境では大量のキーが保存されているため、KEYS * では負荷がかかる。SCAN 0 MATCH * COUNT 100などのSCANコマンドを使う。)

表示されるキーのデータ型を確認する。

TYPE ":1:django.contrib.sessions.cachemmoh6r4amm0gm7fn3l3sovyh48f8o9t8"
Copy

string型なので、ここは普通にGETコマンドでキーを指定して取得できる。

GET ":1:django.contrib.sessions.cachemmoh6r4amm0gm7fn3l3sovyh48f8o9t8"
Copy

なお、ここで表示されるセッションはBase64でエンコードされている、デコード用のコードは以下。

import base64
import pickle

# Redisから取得したデータ(バイナリ)
data = b"\x80\x04\x95\xaf\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\r_auth_user_id\x94\x8c\x011\x94\x8c\x12_auth_user_backend\x94\x8c)django.contrib.auth.backends.ModelBackend\x94\x8c\x0f_auth_user_hash\x94\x8c@3b52c847036e247aec08277f3c96801f08729b54fa138dfeaa22c9b99d8e0053\x94u."

# pickleでデコード
session_data = pickle.loads(data)

# デコードされたセッションデータを表示
print(session_data)
Copy

インタラクティブシェルで実行するとこうなる。

>>> import base64
>>> import pickle
>>> 
>>> # Redisから取得したデータ(バイナリ)
>>> data = b"\x80\x04\x95\xaf\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\r_auth_user_id\x94\x8c\x011\x94\x8c\x12_auth_user_backend\x94\x8c)django.contrib.auth.backends.ModelBackend\x94\x8c\x0f_auth_user_hash\x94\x8c@3b52c847036e247aec08277f3c96801f08729b54fa138dfeaa22c9b99d8e0053\x94u."
>>> 
>>> # pickleでデコード
>>> session_data = pickle.loads(data)
>>> 
>>> # デコードされたセッションデータを表示
>>> print(session_data)
{'_auth_user_id': '1', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', '_auth_user_hash': '3b52c847036e247aec08277f3c96801f08729b54fa138dfeaa22c9b99d8e0053'}
Copy
スポンサーリンク