Flask と Redis でセッションをサーバーサイドに移す

Flask のデフォルトセッションは Cookie に保存されるが、サイズ制限やセキュリティ上の理由でサーバーサイドに保存したい場合がある。Flask-Session と Redis を使えば、セッションをサーバーサイドに移せる。

Flask-Session のセットアップ

pip install flask-session redis
from flask import Flask, session
from flask_session import Session

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:6379')
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True

Session(app)

設定オプション

SESSION_TYPEストレージの種類(redis, filesystem, memcached など)
SESSION_REDISRedis 接続オブジェクト
SESSION_PERMANENT永続セッションにするか
SESSION_USE_SIGNERセッション ID を署名するか
SESSION_KEY_PREFIXRedis キーのプレフィックス

使い方は同じ

サーバーサイドセッションでも、使い方はデフォルトと同じである。

@app.route('/login')
def login():
    session['user_id'] = 123
    session['cart'] = {'items': [], 'total': 0}  # 大きなデータも保存可能
    return 'Logged in'

@app.route('/cart')
def cart():
    return session.get('cart', {})

Cookie との違い

Cookie セッションデータが Cookie に保存される(約4KB制限)
サーバーサイドセッションCookie にはセッション ID のみ、データは Redis に保存

サーバーサイドセッションではデータサイズの制限が緩和される。

Redis に保存されるデータ

Redis では以下のような形式でセッションが保存される。

redis-cli
> KEYS session:*
1) "session:abcd1234..."
> GET session:abcd1234...
# pickle でシリアライズされたセッションデータ

セッションの有効期限

from datetime import timedelta

app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)

@app.route('/login')
def login():
    session.permanent = True  # これで有効期限が適用される
    session['user_id'] = 123
    return 'Logged in'

Redis の接続設定

本番環境では接続プールを使う。

import redis

redis_client = redis.Redis(
    host='localhost',
    port=6379,
    db=0,
    decode_responses=False,  # Flask-Session は bytes を期待
    socket_timeout=5,
    connection_pool=redis.ConnectionPool(max_connections=10)
)

app.config['SESSION_REDIS'] = redis_client

スケールアウト対応

Redis をセッションストアにすることで、複数の Flask インスタンス間でセッションを共有できる。ロードバランサー配下で複数サーバーを動かす場合に必須である。

┌─────────┐
           │  Nginx  │
           └────┬────┘
        ┌───────┼───────┐
        ▼       ▼       ▼
    Flask 1  Flask 2  Flask 3
        └───────┼───────┘
                ▼
            ┌───────┐
            │ Redis │
            └───────┘

どの Flask インスタンスにリクエストが来ても、同じセッションにアクセスできる。