AWSとRedisを使ったセッション管理~Flaskアプリケーションへの適用例~

AWS

redis-handson1
ブログ運営者
さいとう

閲覧いただきありがとうございます!"さいとう"と申します。わたしは異業種・未経験からIT業界に転職し、現在インフラエンジニアとしてクラウド環境の設計や構築・運用の支援を行っています。

私はPythonで書かれたWebフレームワークのFlaskを使い、Webアプリを作成しています。最近、ログイン機能を実装した際に、ログイン状態を維持できない問題に直面しました。この問題を解決するためには、ログインのセッションデータを外部ストアに保存する必要がありました。外部ストアにセッションデータを保存する方法として、Redis、Memcached、データベースなどが考えられます。私はAWSの学習を進める中で、Redisというインメモリデータストアの存在を知り、興味を持っていました。そこで、今回の課題解決の一環として、Redisを使ってセッションデータを管理する方法を試してみることにしました。


この記事では、「Amazon EC2を利用してRedisを簡単にセットアップする方法」と、「Flaskで作成したアプリのログインセッションデータをRedisに保存する方法」を紹介します。


具体的には、EC2インスタンス上にRedisをインストールし、Flaskアプリケーションと連携させる手順を詳しく解説します。これにより、セッション管理の信頼性を向上させ、ユーザー体験を改善することができます。Redisは、高速なデータアクセスと優れたパフォーマンスを提供するため、多くのWebアプリケーションで利用されています。この記事を通じて、Redisの基本的な使い方と、その実践的な活用方法を学び、Flaskアプリケーションのセッション管理に役立てていただければ幸いです。


Redisを使ってみよう

Redisとは

redis-handson2

Redis(Remote Dictionary Server)は、高速なインメモリデータストアです。通常はキーと値として保存・使用されますが、リスト、セット、ハッシュ、ソート済みセット、ビットマップなど、さまざまなデータ型をサポートしています。一般的には、キャッシュ、セッションストア、パブ/サブメッセージング、リアルタイムのアナリティクスなど、多くの用途で利用されます。

Redisのメリット

  • 高速: Redisはインメモリデータストアであるため、非常に高速な読み書きが可能です。
  • 複数のデータ型: キー-値ペアだけでなく、リスト、セット、ソート済みセット、ハッシュなど、多くの複雑なデータ型をサポートしています。
  • 持続性: 必要に応じて、メモリ上のデータをディスクに保存する設定も可能です。
  • 広範な言語サポート: 多くのプログラミング言語で利用できるクライアントライブラリがあります。



Redisのデメリット

  • メモリ使用量: すべてのデータは主にメモリに格納されるため、大量のデータを扱う場合はコストがかかる可能性があります。
  • 持続性の制限: 完全なACIDトランザクションをサポートしていないため、RDBMSに比べて持続性が低い場合があります。
  • クラスタリングの複雑さ: Redisのクラスタリングは比較的新しく、設定が複雑である可能性があります。
  • 単一スレッドモデル: Redisは単一スレッドで動作するので、多核プロセッサの能力をフルに活用することはできません。



AWSのページにRedisについて詳しく載っています。詳しく知りたい方はぜひ。

■前提条件

今回の記事ではRedisについて知るために、ハンズオンを3つ用意しました。ハンズオンの前提条件は以下の通りです。

  • 環境: AWS
  • 使用AWSリソース: Amazon EC2, Amazon VPC
  • セキュリティグループルール: ローカル環境からアクセスするため、自身のIPを許可(MyIP)
  • OS: AmazonLinux2023
  • 接続: 任意。Session Managerを利用する場合、適切なIAMポリシーを付与してください。
  • ユーザー: ec2-user
  • パブリックv4: あり

※ハンズオンではPythonやhtmlのソースコードが出てきますが、あくまでRedisの紹介ですのでコード説明は省きます。

ハンズオン1:Redisを使ってみる

ハンズオン1では、Amazon EC2にRedisをインストールして、[redis-cli]を使い、キーと値を保存・参照してみます。


↓EC2インスタンスに接続し、以下のコマンドを実行します。

sudo dnf install -y redis6
redis-handson3

redis-handson4

インストールが完了したら、起動します。以下のコマンドを順に実行してください。

sudo systemctl start redis6
sudo systemctl enable redis6
systemctl status redis6

 
【実行結果】

[ec2-user@ip-10-0-1-41 ~]$ systemctl status redis6
● redis6.service - Redis persistent key-value database
     Loaded: loaded (/usr/lib/systemd/system/redis6.service; enabled; preset: disable>
    Drop-In: /etc/systemd/system/redis6.service.d
             └─limit.conf
     Active: active (running) since Sun 2023-09-10 00:40:50 UTC; 55s ago
   Main PID: 25082 (redis6-server)     Status: "Ready to accept connections"
      Tasks: 5 (limit: 9349)
     Memory: 2.1M
        CPU: 36ms
     CGroup: /system.slice/redis6.service
             └─25082 "/usr/bin/redis6-server 127.0.0.1:6379"

Sep 10 00:40:50 ip-10-0-1-41.ap-southeast-1.compute.internal systemd[1]: Starting red>
Sep 10 00:40:50 ip-10-0-1-41.ap-southeast-1.compute.internal systemd[1]: Started redi>lines 1-15/15 (END)


[actiove(running)]になっていたら、起動しています。


↓それではRedisを使ってみましょう。Redisサーバを操作する方法はいくつかありますが、まずは"redis6-cli"ツールを使ってみます。以下のコマンドを実行してください。

redis6-cli
redis-handson5


↓キーと値を保存します。

SET mykey "Hello, Redis!"
redis-handson6


↓保存した値を取り出します。

GET mykey
redis-handson7



キーと値の保存・参照の仕方はシンプルでわかりやすいですね。


ハンズオン1は以上です。

ハンズオン2:PythonでRedisを使ってみる

ハンズオン2はPythonでRedisを操作するコードを使って、Redisにキーと値を保存し、指定したキーの値を表示してみます。


↓"Python"をインストールします。環境によってはすでにインストール済みかもしれません。

sudo dnf install -y python3-pip python3-devel
redis-handson8


↓PythonでRedisを扱うためのパッケージをインストールします。

pip install redis
redis-handson9



redis-handson10


↓インストールが完了したら、Pythonファイルを保存するディレクトリを作成します。

mkdir test_redis/
redis-handson11


↓ディレクトリを作成したら、実行ファイルを作成します。コマンドとソースコードは以下を利用してください。

sudo vim test_redis/test_redis.py

 
【ソースコード(test_redis.py)】

import redis

# Redisに接続
r = redis.Redis(host='localhost', port=6379, db=0)

# データのセット
r.set('my_key', 'Hello from Python!')

# データの取得
value = r.get('my_key')
print(value.decode('utf-8'))


redis-handson12



redis-handson13


↓ソースコードを入力したら、[Esc]キーを押し、以下のコマンドで保存してエディターを終了します。

:wq
redis-handson14


↓ディレクトリを移動し、pyファイルを実行しましょう。

cd test_redis/
python3 test_redis.py
redis-handson15



redis-handson16


キー"my_key"を指定して、値"Hello from Python!"が返ってきました。

ハンズオン2は以上です。

ハンズオン3:Redis×Flaskを使ってみる

さいごに、WebフレームワークのFlaskを利用して、redisにセッションデータを保存してみます。Flaskについては後日記事を公開します。


ハンズオン2の続きから始めますので、カレントディレクトリに注意してください。


↓必要なパッケージをインストールします。

pip install Flask Flask-Session
redis-handson17


↓htmlファイルを置くディレクトリを作成し、htmlファイルも作成していきます。

mkdir templates/
sudo vim templates/login.html



【ソースコード(login.html)】

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
{% with messages = get_flashed_messages() %}
  {% if messages %}
    {% for message in messages %}
      <p>{{ message }}</p>
    {% endfor %}
  {% endif %}
{% endwith %}
    <h1>Login</h1>
    <form method="POST" action="/login">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required><br><br>

        <label for="password">Password:</label>
        <input type="password" id="password" name="password" required><br><br>

        <input type="submit" value="Login">
    </form>
</body>
</html>
redis-handson18



redis-handson19


[Esc]キーを押し、以下のコマンドで保存してエディターを終了します。

:wq


↓Flaskを実行するファイルを作成し、以下のソースコードを貼り付けましょう。

sudo vim app.py



【ソースコード(app.py)】

from flask import Flask, request, render_template, redirect, session, url_for
from redis import Redis
from flask_session import Session

app = Flask(__name__)
app.secret_key = 'your_secret_key'
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'your_prefix'
app.config['SESSION_REDIS'] = Redis(host='localhost', port=6379, db=0)

# セッションのセットアップ
Session(app)

# ダミーのユーザーデータ
users = {
    'user1': 'password1',
    'user2': 'password2'
}

# ログインページ
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        if users.get(username) == password:
            session['username'] = username
            return redirect(url_for('dashboard'))
        else:
            return 'ログインに失敗しました'

    return render_template('login.html')


# ダッシュボード(ログインが必要なページ)
@app.route('/dashboard')
def dashboard():
    if 'username' in session:
        username = session['username']
        return f'こんにちは、{username}さん! <a href="/about">ログイン継続チェック</a> <a href="/logout">ログアウト</a>'
    else:
        return 'ログインしてください。'


# /about ページ(ログインが必要)
@app.route('/about')
def about():
    if 'username' not in session:
        return f'ログインが必要です。 <a href="/login">ログイン</a>'
    username = session['username']  # 'username'をセッションから取得
    print('username:', username)
    return f'{username}さん!、ログイン継続中です! <a href="/logout">ログアウト</a>'



# ログアウト
@app.route('/logout')
def logout():
    if 'username' in session:
        session.pop('username')
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0')


redis-handson20



redis-handson21


[Esc]キーを押し、以下のコマンドで保存してエディターを終了します。

:wq


↓準備が整いましたので、Webアプリを起動しましょう。WARNINGが表示されますが、問題ないので進めてください。

python3 app.py


redis-handson22


↓ブラウザからWebアプリにアクセスします。アクセスできない場合は、セキュリティグループのインバウンドルールとパブリックIPアドレスを確認してください。

http://<EC2インスタンスパブリックIPアドレス>:5000/login


redis-handson23


↓ダミーのユーザーデータを用意していますので、Usename: user1、Password: password1 でログインしてみてください。

redis-handson24


ログインできましたでしょうか。
 

redis-handson25


↓今回はログインしたユーザーのセッションデータをRedisに保存するのが目的です。ログインしていなければアクセスできないページを用意してありますので、確認してみましょう。[ログイン接続チェック]をクリックしてください。

redis-handson26



redis-handson27


Usernameが表示され、ログイン継続中と出ました。


↓しかし、本当にRedisにセッションデータが保存されているのか気になりますよね。確認してみましょう。コマンドラインに戻り、[Ctrl + c]でWebアプリを一旦止めます。

redis-handson28


↓[redis6-cli]を実行し、以下のコマンドを実行します。

keys *
redis-handson29


↓いくつかデータが保存されていますが、今回のFlaskアプリのキー名は[your_prefix]から始まるデータです。

redis-handson30


↓値を確認してみます

GET <キー名>
例)GET your_prefixc8b8431a-d59f-4235-bf2c-75ed3ab77d93
redis-handson31


値の中にusernameとuser1が入っているのが確認できました。

↓もう一度、Webアプリを起動し、以下のページにアクセスしてください。セッションデータが保持されているので、アクセスできるかと思います。

http://<EC2インスタンスパブリックIPアドレス>:5000/about
redis-handson32


↓[ログアウト]をクリックしてください。

redis-handson33


↓それでは、もう一度redisのデータを確認してみます。[redis6-cli]→[keys *]を実行します。

redis-handson34


さきほどまであった、[your_prefixxxxxxxxxxxxxxxxxx]というキーが消えていますね。ログアウトしたことで、セッションデータが消えました。今回のハンズオンは以上です。

まとめ

Webアプリケーションを作成している中で、各実行プロセスがユーザーのログイン情報を保持できないという問題に直面しました。この問題の解決策として、セッションデータを外部ストアに保存する方法を検討し、その選択肢の一つとしてRedisを紹介しました。


Redisはインメモリデータストアとして高いパフォーマンスを持ち、セッションデータの管理に最適です。AWSの認定資格試験でも頻繁に登場する「Amazon ElastiCache for Redis」として知られており、その重要性を実感しました。


今回のハンズオンを通じて、Redisの動きや基本的な操作について理解が深まりました。外部ストアを利用することで、アプリケーションのスケーラビリティと信頼性が向上します。特にRedisを使用することで、高速なデータアクセスが可能となり、セッション管理が効率的に行えます。これにより、ユーザー体験の向上が期待できます。


今回の実践を通じて、Redisの導入と設定方法を学び、Flaskアプリケーションとの連携をスムーズに行うことができました。これからもRedisを活用して、より安定したWebアプリケーションの運用を目指していきたいと思います。同様の課題に直面している方々にとって、この情報が役立ち、問題解決の一助となることを願っています。

参考リンク:RedisFlask – クイックスタート