開発

Djangoのセッション設定:保存先5種の選び分けとRedis構成の判断

Djangoのセッション設定:保存先5種の選び分けとRedis構成の判断

Djangoのセッションは、設定を書かなくても動きます。Djangoとは?Python製Webフレームワークの特徴・MVT・始め方を入門解説で触れているとおり、標準構成の時点でセッション機構が組み込まれているためです。問題が出るのは、アクセス増でデータベースが重くなったとき、サーバーを2台に増やしたとき、キャッシュを入れた直後にログインが切れたときの3場面です。ここではSESSION_ENGINEで選べる5種類の保存先を、正常時の速さではなく障害時の挙動から比べます。

まとめ:保存先の選択で決まるのは速さより障害時の挙動

  • SESSION_ENGINEの既定は db で、セッションを1つ読むたびにデータベースへクエリが飛びます。まず疑うのはこの既定値です。
  • cache は速い代わりに、追い出しやRedisの再起動でログイン状態が消えます。消えて困る業務なら選びません。
  • cached_db はライトスルーで、データベースとキャッシュの両方へ書きます。キャッシュが落ちてもセッションは生き残ります。
  • signed_cookies はサーバー側に何も持たない代わりに、4096バイトの壁とログアウトで失効できない性質を抱えます。
  • RedisのLOCATIONへリストを渡すと読み取りがレプリカへ散り、書き込み直後の読み取りが噛み合いません。
  • db系を選んだら clearsessions を日次で回します。Djangoは期限切れセッションを自動では消しません。

SESSION_ENGINEで選べる5つの保存先と既定のdbバックエンドの実体

セッション保存先5種のモジュールパスと既定値を最初に押さえる

Djangoのセッション保存先は SESSION_ENGINE という設定1つで切り替わります。global_settings.py の実測値では既定が django.contrib.sessions.backends.db なので、ここを書き換えていないプロジェクトは全てデータベース保存です。選べるのは db・cache・cached_db・file・signed_cookies の5種類で、モジュールパスはいずれも django.contrib.sessions.backends の下に並びます。同時に押さえる既定値は、SESSION_COOKIE_AGE が 60 * 60 * 24 * 7 * 2 = 1,209,600秒(2週間)、SESSION_COOKIE_NAME が sessionid、SESSION_COOKIE_HTTPONLY が True、SESSION_COOKIE_SAMESITE が Lax、そして SESSION_COOKIE_SECURE が False という並びです。最後の1つには注意が要ります。HTTPS運用へ切り替えてもTrueにしない限りSecure属性は付かないため、設定ファイル側での明示が残る作業になります。

バックエンド 保存場所 主な制約
db(既定) データベース 読むたびにクエリが飛ぶ
cache キャッシュのみ 追い出しでログアウト
cached_db 両方に書く 書き込み先が2か所になる
file サーバーのファイル 複数台で共有できない
signed_cookies クライアント側 4096バイトと失効不能

dbバックエンドが毎リクエストで発行するクエリとテーブル膨張

dbバックエンドの前提は、INSTALLED_APPS に django.contrib.sessions があり、migrate で django_session テーブルが作られていることです。動作は素朴で、セッションキーで1行を引き、書き換えたときだけ更新をかけます。負荷として現れるのは、ログイン状態を見るページが1リクエストごとに必ず1回のSELECTを発行する点です。

もう1つの落とし穴が行数の膨張です。Djangoは期限切れセッションを自動では削除しません。公式ドキュメントも掃除は利用者側の仕事だとし、clearsessions コマンドに任せる設計です。回していないプロジェクトでは2週間の既定期限を過ぎた行が残り続け、数百万行に達してから気づく形になります。

fileとlocmemを本番構成から外す判断とその根拠になる制約

file バックエンドはサーバーのファイルシステムへセッションを書きます。SESSION_FILE_PATH の既定は None で、指定しなければOSの一時ディレクトリが使われる形です。1台構成の検証環境では手軽ですが、2台に増やした瞬間にサーバーごとにセッションが分かれ、振り分け先が変わるたびにログアウトします。共有ストレージへ逃がす手もあるものの、ロックとI/Oの問題を持ち込むため選ぶ理由は薄いでしょう。

cacheバックエンドを選ぶ場合も、キャッシュ側の実装で可否が変わる点に注意が必要です。公式ドキュメントはセッション用途を Memcached と Redis に限定し、ローカルメモリキャッシュ(locmem)についてはデータを十分な時間保持せず、かつマルチプロセス安全ではないと書いています。gunicornでワーカーを複数立てる構成ではプロセスごとにキャッシュが分かれるため、locmemは検証用と割り切る判断が要ります。

cache・cached_db・signed_cookiesを障害時の挙動から選び分ける

cacheは追い出しでログアウトが起きる前提のうえで採用する構成

cacheバックエンドはセッションをキャッシュにだけ置きます。データベースを一切触らないので速く、django_sessionの掃除も不要になります。引き換えに失うのは永続性です。Redisのメモリが上限に達して追い出しが始まったとき、あるいはプロセスが再起動してデータが残っていなかったとき、該当セッションは復元できずログイン画面へ戻ります。

この性質が許されるのは、ログアウトされてもユーザーが困らない範囲に限られます。閲覧が主体のサイト、社内向けの参照系ツール、ログインが軽い認証で済むサービスなら候補になるでしょう。カートの中身が消える障害はキャッシュの追い出しという運用側の事象から起きるため、アプリのテストでは検出できない点が判断を難しくします。

cached_dbのライトスルー書き込みとキャッシュ失敗時のログ出力

cached_db はキャッシュとデータベースの両方を使う構成です。公式ドキュメントの記述では、書き込みはデータベースとキャッシュの両方へ、その順序で適用されるライトスルー方式になります。読み取りはキャッシュを見て、そこから消えていればデータベースへ落ちる動きです。結果として、追い出しが起きてもログイン状態は維持され、通常時の読み取りはキャッシュの速度で返る配分になります。

Django 5.1では、この構成のキャッシュ書き込みが失敗したときの扱いが明示されました。例外を処理してsessionsロガーへトレースバック付きで記録し、成功しているデータベース書き込みを失敗させないという挙動です。つまりRedisが落ちてもリクエストはエラーになりません。ただしこの状態は黙って進むため、sessionsロガーの出力を監視に載せていないと、キャッシュが死んだままデータベースだけで捌く重い状態に気づけません。

signed_cookiesの4096バイト制限とログアウトで失効しない性質

signed_cookies はセッションデータ自体をCookieへ入れ、SECRET_KEY で署名します。サーバー側に保存領域を持たないため、複数台構成でも共有の仕組みが不要です。ただし署名は暗号化ではありません。公式ドキュメントも、データがクライアントから読める点と、新鮮さの保証がない点を明記しています。ユーザーに見せたくない値を入れる設計は成立しません。

容量も壁です。Djangoはデータを圧縮しますが、それでもCookieの一般的な上限である4096バイトを超え得ると書かれています。サーバー側に状態が無いということは、ログアウト操作でそのCookieを無効化できないという意味でもあり、失効させたい要件があるならこの方式は候補から外れます。即時失効が要るかどうかで方式が分かれる話はセッション管理とは?セッションIDの発行から失効までの実装と保存先選定を解説の側で整理しました。

Redisをセッションの保存先にするときの接続設定と冗長化の判断

LOCATIONにリストを渡したときの書き込み先と読み取り先の分岐

Djangoには4.0以降 django.core.cache.backends.redis.RedisCache が組み込まれており、Redisを使うだけならサードパーティ製パッケージは要りません。CACHESのLOCATIONにはURLを1つ書くほか、セミコロン区切り・カンマ区切り・リストで複数サーバーを渡せます。公式ドキュメントによれば、複数を渡したときは書き込みが先頭のサーバーへ、読み取りは残りのレプリカからランダムに選ばれます。

この分担はページキャッシュには噛み合いますが、セッションでは危険側に振れます。ログイン直後の書き込みは先頭へ入り、次のリクエストの読み取りはレプリカへ飛ぶ可能性があるためです。レプリケーションが追いついていなければセッションは見つからず、ログイン直後にログイン画面へ戻る症状として現れます。冗長化を目的にレプリカを並べたい場合は、LOCATIONへ複数を並べるのではなく、フェイルオーバーをRedis側の仕組みに寄せ、Django側は単一のエンドポイントだけを知る構成にします。

OPTIONSのdb指定とプールクラス・hiredisの導入判断の基準

OPTIONSでは接続の細部を指定できます。Redisは既定で16個の論理データベースを持つため、db に番号を渡せばセッション用の領域を分けられる形です。接続の作り方を変えたい場合は pool_class を指定し、既定の redis.ConnectionPool からブロッキング型のプールへ切り替える選択肢もあります。ワーカー数と最大接続数の兼ね合いで接続が枯れる構成では、この指定が効きます。

必須のクライアントライブラリは redis-py で、hiredis-py は推奨扱いです。パース処理がC実装に置き換わるため、小さな読み取りを大量に出す用途では入れておく判断で足ります。認証情報はURLへユーザー名とパスワードを含める形式です。設定ファイルへ直接書かず環境変数から読む運用にすれば、別実装へ差し替えるときも影響は接続文字列だけに収まります。互換実装の選択肢についてはValkeyとは?Redisとの違い・導入方法・データ型を2026年最新版で解説を参照してください。

マネージドRedisを選ぶ場合のフェイルオーバー中の書き込み扱い

自前でRedisを立てずマネージドサービスへ寄せる場合、Django側の設定は接続先が変わるだけで済みます。判断が要るのは、フェイルオーバー中の数十秒をアプリがどう扱うかという点です。可用性の要件が高いほど、cached_dbで書き込みを二重化する形が現実的になります。階層と料金からマネージド側を選ぶ話はAzure Cache for Redisとは?仕組み・5つの階層と料金・Azure Managed Redisへの移行と採用判断を実装者目線で解説で整理しています。

キャッシュフレームワークと同居させたときセッションが消える経路

SESSION_CACHE_ALIASを別aliasへ分けるかどうかの判断基準

SESSION_CACHE_ALIAS の既定は default です。つまりcacheまたはcached_dbを選んだ時点で、セッションはページキャッシュと同じ領域に載ります。消えても再生成できるデータと、消えるとユーザーがログアウトするデータが同じ論理データベースに混ざる状態です。

分ける判断は、キャッシュの運用に触る頻度で決めます。デプロイのたびにキャッシュを消す運用、あるいはメモリ上限に張り付いて追い出しが常時走っている状態なら、CACHESへ別のaliasを定義し、SESSION_CACHE_ALIASでそちらを指す構成が妥当です。論理データベースの番号を分ければインスタンスは1つで足りますし、上限や追い出し方針をセッション側だけ別に決められます。

cache.clear()と追い出し方針でセッションが全消しになる経路

領域を共有したまま事故が起きる経路は2つあります。1つはアプリ側またはデプロイスクリプトからの cache.clear() です。ページキャッシュを捨てるつもりの操作が、同じ領域のセッションまで消し、全ユーザーが同時にログアウトします。見え方が「デプロイ直後にログインが切れた」となるため、原因の特定に時間がかかります。

もう1つはRedisの追い出し方針です。メモリ上限に達したときにキー全体を対象とする方針を採っていると、セッションもページキャッシュと同じ確率で追い出されます。セッションを別の論理データベースへ分けて追い出しを避ける設定にするか、cached_dbにしてデータベース側へ控えを持たせるかの二択です。cacheバックエンドで運用するなら、追い出しが起きた時点でログアウトが発生する仕様だと受け入れる形になります。

複数台構成でログインが切れる原因とスティッキーセッションの要否

サーバー側で保存しても接続の固定が要る場合と要らない場合の線引き

アプリケーションサーバーを複数台に並べたとき、db・cache・cached_db のいずれかを使っていれば、どの台からでも同じセッションを読めます。この条件下では、ロードバランサ側で振り分け先を固定する仕組みは不要です。逆に固定が必要になるのは、fileバックエンドのままの構成、locmemキャッシュを使っている構成、そしてワーカーのメモリに独自の状態を持たせてしまっている構成です。

固定を外せると、1台を落としてデプロイする作業やオートスケールでの台数変動がセッションに影響しなくなります。gunicornとnginxを前提にした配置の判断はDjangoのデプロイ手順:gunicorn+nginx構成と本番設定・配置先の選び方で扱っています。セッションの保存先を外部へ出す作業は、台数を動かせる構成にするための前提工程です。

有効期限の二重設計とSESSION_SAVE_EVERY_REQUESTの書き込み増

有効期限は2つの設定で決まります。SESSION_COOKIE_AGE の既定は2週間、SESSION_EXPIRE_AT_BROWSER_CLOSE の既定は False なので、標準構成ではブラウザを閉じても2週間ログイン状態が続く形です。業務システムでこの長さを許すかは要件側の判断になります。短くするなら期限切れ後の画面遷移まで決めておかないと、保存前のフォームが消える不満に変わります。

操作を続けている間だけ期限を延ばしたいなら SESSION_SAVE_EVERY_REQUEST を True にします。ただし既定が False であるのは理由あってのことです。Trueにするとセッションを書き換えていないリクエストでも保存処理が走るため、dbバックエンドでは全リクエストがUPDATEを発行する構成に変わります。この設定を入れるならcached_dbかcacheへ寄せ、書き込みをキャッシュ側で吸収する形にするのが妥当です。

clearsessionsを回さないとdjango_sessionが残り続ける

db または cached_db を選んだ場合、期限切れの行を消す仕組みは自分で用意します。Djangoが提供するのは clearsessions という管理コマンドで、公式ドキュメントは日次のcronなど定期実行を推奨しています。cacheバックエンドだけの構成ならキャッシュ側の期限で自然に消えるため、この作業は不要です。

放置したときの影響は、テーブルサイズとバックアップ時間、そしてインデックスの膨張として出ます。行数が積み上がってから一括削除すると、削除自体がロックと複製遅延の原因になるため、運用の初期に仕込むのが最も安く済みます。コンテナ構成ではジョブとして分離しておくと、台数を増やしても二重実行になりません。

4構成の採用条件と見送る場面・SECRET_KEY差し替え時の全失効

アクセス規模と要件から引く4構成の使い分けと見送る場面の判断条件

判断は速さより要件から引きます。既定の db は、同時アクセスが小規模から中規模で、データベースにまだ余力がある案件なら変える理由がありません。ログイン後の画面が重く、セッション参照がデータベース接続を占め始めた段階で cached_db へ移します。ここが多くの案件の着地点で、キャッシュ障害への耐性と読み取りの速さが両立します。

cache 単体を選ぶのは、ログアウトが業務影響にならないと言い切れる場合に限ります。判断の材料は、セッションに入力途中のデータを預けているか、決済や申込の途中状態を持つかの2点です。どちらかに該当するなら選びません。signed_cookies は、サーバー側の保存領域を持てない特殊な構成に限った選択肢です。ログアウトで失効させられない性質があるため、認証を伴う業務システムでは見送る判断になります。ログイン処理そのものの設計はDjangoのログイン機能:標準authの範囲とカスタムユーザー・allauthを参照してください。会員基盤ごと設計から任せたい場合は会員管理システム開発でご相談を受け付けています。

SECRET_KEYを差し替えると全セッションが切れる仕組みと手順

保存先の話とは別に、鍵の扱いで全セッションが切れる経路があります。これはsigned_cookies限定の話ではありません。SECRET_KEY は既定の get_session_auth_hash を通じて、dbバックエンドのセッションにも効いています。公式ドキュメントは、あるキーが SECRET_KEY にも SECRET_KEY_FALLBACKS にも含まれなくなった時点で、全セッション・CookieStorageのメッセージ・パスワードリセットのトークン・署名がすべて無効化されると明記しています。

したがって鍵の入れ替えは、新しい値を SECRET_KEY に置き、古い値を SECRET_KEY_FALLBACKS の先頭へ移す手順で行います。既定は空リストなので、この設定を知らないと入れ替えと同時に全ユーザーがログアウトします。古い値を落とすのは、セッションとリセットトークンの期限が切れきってからです。なお非同期ビューからセッションを触る場合は、Django 5.1で入った a 接頭辞のメソッド(aget・akeys・acycle_key など)を使います。

よくある質問

DjangoのセッションはSESSION_ENGINEを設定しないと使えませんか?

設定しなくても動きます。既定値が db なので、INSTALLED_APPS に sessions アプリが入って migrate が済んでいれば、データベース保存のセッションとして機能します。書き換えるのは、負荷を減らしたいときと保存先を外部へ出したいときです。

セッションをRedisに置くにはdjango-redisが必要ですか?

不要です。Django 4.0以降は組み込みのRedisキャッシュバックエンドがあり、CACHESでそれを指定して SESSION_ENGINE を cache か cached_db にすれば足ります。必要なのは redis-py の導入だけで、hiredis-py は速度面の推奨扱いです。

ログイン直後にログイン画面へ戻される原因は何が多いですか?

複数台構成でセッションが共有されていない場合と、RedisのLOCATIONへ複数サーバーを並べて読み取りがレプリカへ散っている場合が典型です。前者はfileバックエンドやlocmemキャッシュの残存、後者はレプリケーションの遅延が原因です。

セッションのタイムアウトを短くする設定はどれですか?

SESSION_COOKIE_AGE を秒数で指定します。既定は1,209,600秒(2週間)です。ブラウザを閉じたら切りたい場合は SESSION_EXPIRE_AT_BROWSER_CLOSE を True にします。操作中だけ延長したいときは SESSION_SAVE_EVERY_REQUEST を併用しますが、書き込み回数が増える点に注意してください。

django_sessionテーブルが巨大になったらどうすればよいですか?

clearsessions コマンドを定期実行に組み込みます。Djangoは期限切れセッションを自動削除しないため、放置すると行が残り続けます。既に膨張している場合は、期間を区切って分割削除する進め方が安全です。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.09 テックブログ IDCFクラウド(IDCフロンティア)不正アクセス・ランサムウェア:影響先・復旧・データは戻るか
  2. 2025.11.04 テックブログ Runpodとは?料金・使い方・支払い方法とGPUクラウドの選び方【2026年10月】
  3. 2026.01.09 コラム 違背実験とは?読み方・意味と具体例、ガーフィンケル原典の数値とエスノメソドロジー
  4. 2026.10.09 テックブログ ニッスイのサイバー攻撃で日水物流の入出荷停止|委託先クラウド障害に荷主が備える手順

RELATED POSTS 関連記事

目次