この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。
わたしはPythonで書かれたWebフレームワークのFlaskを使い、Webアプリを作成しています。ログイン機能を実装したところ、ログイン状態を維持できない問題にぶちあたりました。
その解決策として、ログインのセッションデータを外部ストアに保存する必要がありました。
外部ストアに保存する方法の選択肢として、Redis、Memcached、データベースが考えられます。AWSの学習をする際に"Redis"がちょくちょく出てきていて興味があったので、"Redisで試してみよう"と思い立ったのです。
今回は「Amazon EC2を利用してRedisの簡単な使い方」と、「Flaskで作成したアプリのログインセッションデータをRedisに保存する方法」を紹介します。
Redisを使ってみよう
■Redisとは
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
↓
インストールが完了したら、起動します。以下のコマンドを順に実行してください。
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
↓キーと値を保存します。
SET mykey "Hello, Redis!"
↓保存した値を取り出します。
GET mykey
キーと値の保存・参照の仕方はシンプルでわかりやすいですね。
ハンズオン1は以上です。
■ハンズオン2:PythonでRedisを使ってみる
ハンズオン2はPythonでRedisを操作するコードを使って、Redisにキーと値を保存し、指定したキーの値を表示してみます。
↓"Python"をインストールします。環境によってはすでにインストール済みかもしれません。
sudo dnf install -y python3-pip python3-devel
↓PythonでRedisを扱うためのパッケージをインストールします。
pip install redis
↓
↓インストールが完了したら、Pythonファイルを保存するディレクトリを作成します。
mkdir test_redis/
↓ディレクトリを作成したら、実行ファイルを作成します。コマンドとソースコードは以下を利用してください。
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'))
↓
↓ソースコードを入力したら、[Esc]キーを押し、以下のコマンドで保存してエディターを終了します。
:wq
↓ディレクトリを移動し、pyファイルを実行しましょう。
cd test_redis/
python3 test_redis.py
キー"my_key"を指定して、値"Hello from Python!"が返ってきました。
ハンズオン2は以上です。
■ハンズオン3:Redis×Flaskを使ってみる
さいごに、WebフレームワークのFlaskを利用して、redisにセッションデータを保存してみます。Flaskについてはこちら
ハンズオン2の続きから始めますので、カレントディレクトリに注意してください。
↓必要なパッケージをインストールします。
pip install Flask Flask-Session
↓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>
↓
[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')
↓
[Esc]キーを押し、以下のコマンドで保存してエディターを終了します。
:wq
↓準備が整いましたので、Webアプリを起動しましょう。WARNINGが表示されますが、問題ないので進めてください。
python3 app.py
↓ブラウザからWebアプリにアクセスします。アクセスできない場合は、セキュリティグループのインバウンドルールとパブリックIPアドレスを確認してください。
http://<EC2インスタンスパブリックIPアドレス>:5000/login
↓ダミーのユーザーデータを用意していますので、Usename: user1、Password: password1 でログインしてみてください。
ログインできましたでしょうか。
↓今回はログインしたユーザーのセッションデータをRedisに保存するのが目的です。ログインしていなければアクセスできないページを用意してありますので、確認してみましょう。[ログイン接続チェック]をクリックしてください。
↓
Usernameが表示され、ログイン継続中と出ました。
↓しかし、本当にRedisにセッションデータが保存されているのか気になりますよね。確認してみましょう。コマンドラインに戻り、[Ctrl + c]でWebアプリを一旦止めます
↓[redis6-cli]を実行し、以下のコマンドを実行します。
keys *
↓いくつかデータが保存されていますが、今回のFlaskアプリのキー名は[your_prefix]から始まるデータです。
↓値を確認してみます
GET <キー名>
例)GET your_prefixc8b8431a-d59f-4235-bf2c-75ed3ab77d93
値の中にusernameとuser1が入っているのが確認できました。
↓もう一度、Webアプリを起動し、以下のページにアクセスしてください。セッションデータが保持されているので、アクセスできるかと思います。
http://<EC2インスタンスパブリックIPアドレス>:5000/about
↓[ログアウト]をクリックしてください。
↓それでは、もう一度redisのデータを確認してみます。[redis6-cli]→[keys *]を実行します。
さきほどまであった、[your_prefixxxxxxxxxxxxxxxxxx]というキーが消えていますね。ログアウトしたことで、セッションデータが消えました。
今回のハンズオンは以上です。
まとめ:【初心者向け】Amazon EC2でRedisを使ってみる
Webアプリケーションを作成していて、各実行プロセスがユーザーのログイン情報を保持できずに困っていました。
解決策は外部ストアを利用することで、外部ストアの選択肢のひとつに今回紹介したRedisがあったのです。AWSの認定資格で"Amazon ElastiCache for Redis"ってしょうちゅう出てきますよね。
今回のハンズオンを通して、"Redis"の動きや操作がなんとなくわかった気がします。
参考リンク:Redis、Flask – クイックスタート
↓ほかの協栄情報メンバーもPythonに関する記事を公開しています。ぜひ参考にしてみてください。
■【簡単】Pythonで始めるwebアプリ開発入門【Flask】(齊藤弘樹)
https://cloud5.jp/saitou-intro-flask/
■天気予報情報をスクレイピング(Python)で、LINE NotifyによりLINE通知の構築(INAMURA)
https://cloud5.jp/web-scraping_line-notify/
■Pythonでlxmlを用いてhtmlから情報取得(zhangzy)
https://cloud5.jp/python-ixml/
■仮想環境作成ツール”virtualenv”を使ってみる(齊藤弘樹)
https://cloud5.jp/saitou-howtouse-virtualenv/
■【初学者向け】PCにPythonを学習するための環境を整える part1【Windows編】(齊藤弘樹)
https://cloud5.jp/saitou-python-install/