Upstash Redis と Fly.io でリアルタイムのエッジリーダーボードを構築する方法
Upstash Redis と Fly.io でエッジにリーダーボードを構築する
動的で魅力的な Web アプリケーションにおいて、リーダーボード(ランキング表)はユーザーの競争意欲を煽り、エンゲージメントを高めるための強力なツールです。このチュートリアルでは、Upstash Redis をバックエンドストレージとして使い、Fly.io でエッジにデプロイすることで、リアルタイムのリーダーボードを構築していきます。サーバーレス Redis サービスの効率性と、Fly.io のグローバル分散機能を組み合わせることで、世界中のユーザーに低レイテンシでのアクセスを提供できます。
Upstash Redis とは
Upstash はクラウドサービスで、シンプルさ・スケーラビリティ・使いやすさに重点を置いた完全マネージド型の Redis サービスを提供しています。汎用性が高く高性能なインメモリデータストアとして知られる Redis は、Upstash と組み合わせることでさらに強力になります。Upstash を利用すれば、インフラ管理に伴う運用上の複雑さを気にせず、さまざまなユースケース向けに Redis をシームレスにデプロイ・スケールできます。
Upstash Redis の主な特徴は以下の通りです。
簡単なデプロイ: Upstash はデプロイプロセスを大幅に簡素化します。インフラに関わる運用負荷を軽減したい開発者にとって最適な選択肢です。
高いパフォーマンス: Redis は超高速なデータ取得で知られており、タスクキューイング、メッセージパッシング、そして本チュートリアルで扱うリアルタイムリーダーボードなどに適しています。Upstash ならクラウドインフラによるシームレスなスケーリングが可能で、変動するワークロードにも効率的に対応できます。
スケーラビリティ: Redis は高度にスケーラブルであり、Upstash を使えば需要に応じて自動的にスケールします。アプリケーションが常に変動する負荷レベルに対応できるようになり、動的で拡張性のあるアプリケーションに理想的です。
データストア統合: Redis はメッセージブローカーと結果ストアの両方として機能するため、管理すべきコンポーネント数を減らし、アーキテクチャをシンプルに保てます。
リアルタイムリーダーボードアプリケーションに Upstash Redis を取り入れることで、Fly.io のグローバル分散能力を補完する完全マネージド型 Redis サービスの力を活かし、堅牢かつ応答性の高い Web アプリケーションアーキテクチャを実現できます。それでは実装に入り、Upstash Redis と Fly.io の組み合わせがプロジェクトをどのように次のレベルへ引き上げるのかを見ていきましょう。
前提条件
作業を始める前に、以下の準備が必要です。
Fly.io のアカウント
Flask と Python の基礎知識
Fly.io アカウントのセットアップと Redis データベースの作成
まず Fly.io でアカウントを作成し、Fly CLI をインストールします。
# Linux
curl -L https://fly.io/install.sh | sh
# その他のインストール方法: https://fly.io/docs/hands-on/install-flyctl/
インストール後、ターミナルから Fly にログインします。
fly auth login
ブラウザが開き、作成したアカウントでのログイン認証を求められます。これでターミナルから Fly を操作できるようになりました。
Fly のセットアップが完了したら、リーダーボードの構築に使用する Redis データベースを作成しましょう。
これで、Fly.io 経由でたった 1 コマンドで Upstash Redis データベースが作成されました。出力から、またはターミナルのコマンドで REDIS_URL を確認できます。
flyctl redis status upstash-fly-leaderboard
# または Upstash ダッシュボードを開く
fly redis dashboard <your_org_name | personal>
private_url を控えておきましょう。後ほど Flask アプリで必要になります。
Flask アプリケーションの開発
リーダーボードの作成には Flask を使用します。Flask は Web アプリケーション構築のためのミニマルな Python フレームワークです。まず依存関係をインストールしましょう。
# flask - Web アプリケーションフレームワーク
# redis - Redis への接続・操作のためのラッパー
# gunicorn - Python Web アプリケーション実行用の WSGI サーバー
$ pip install flask redis gunicorn
# 依存関係を requirements.txt に出力
$ pip freeze > requirements.txt
次に、Flask アプリの土台を作ります。app.py というモジュールを作成し、Flask アプリケーションを初期化して Upstash Redis に接続する最小限のコードを書きましょう。
import os
from flask import Flask, render_template, request, redirect, url_for
import redis
app = Flask(__name__)
# 接続文字列を環境変数から読み込む
UPSTASH_FLY_REDIS_CONNECTION_STRING = os.getenv('REDIS_URL')
LEADERBOARD_KEY = 'leaderboard'
# 接続文字列を使って Upstash Redis インスタンスへの接続を確立
redis_client = redis.from_url(UPSTASH_FLY_REDIS_CONNECTION_STRING)
ここで行っていることは以下の通りです。
Flask アプリの初期化
環境変数から REDIS_URL の読み込み
Fly.io で作成した Upstash Redis データベースとやり取りする redis_client の初期化
続いて、プレイヤーをリーダーボードに追加する関数と、スコア付きでプレイヤー一覧を取得する関数を定義します。
def add_score(player_id, score):
# リーダーボード内のプレイヤーのスコアを追加または更新
redis_client.zadd(LEADERBOARD_KEY, {player_id: score})
def get_leaderboard():
leaderboard = redis_client.zrevrange(LEADERBOARD_KEY, 0, 9, withscores=True)
formatted_leaderboard = [{'player_id': player_id.decode('utf-8'), 'score': int(score)} for player_id, score in
leaderboard]
return formatted_leaderboard
add_score 関数は player_id と score を受け取り、リーダーボードに追加します。zadd は Redis のコマンドで、1 つ以上のメンバーをスコア付きでソート済みセットに追加するために使われます。
2 つ目の get_leaderboard() 関数は、Redis のソート済みセット(リーダーボード)から上位 10 件のエントリーをスコア付きで取得し、プレイヤー ID と対応するスコアを含む整形されたリストとして返します。
では、Upstash Redis データベースとやり取りするための 3 つのエンドポイントを追加しましょう。
[GET] / — リーダーボードを取得
POST /submit_score — リーダーボードにスコアを送信
GET /clear_table — リーダーボードをクリア
@app.route('/')
def leaderboard():
# リーダーボードから上位 10 人を取得し、データとともにリーダーボードページへ描画
leaderboard = get_leaderboard()
return render_template('leaderboard.html', leaderboard=leaderboard)
@app.route('/submit_score', methods=['POST'])
def submit_score():
player_id = request.form['player_id']
score = int(request.form['score'])
# リーダーボードにプレイヤーのスコアを追加または更新する関数を呼び出し
add_score(player_id, score)
return redirect(url_for('leaderboard'))
@app.route('/clear_table', methods=['GET'])
def clear_table():
# リーダーボードの全データを削除
redis_client.delete(LEADERBOARD_KEY)
return redirect(url_for('leaderboard'))
ご覧のとおり、よりインタラクティブかつリアルタイムな体験にするため、フロントエンドページ leaderboard.html も描画しています。プロジェクトのルートに templates フォルダを作成し、その中に以下のコードで leaderboard.html ファイルを作成してください。
これでローカル環境でテストできます。ターミナルで環境変数を読み込みましょう。
# Linux
export REDIS_URL='YOUR_UPSTASH_FLY_REDIS_CONNECTION_STRING'
# Windows
set REDIS_URL='YOUR_UPSTASH_FLY_REDIS_CONNECTION_STRING'
# その後、以下を実行:
$ flask run
アプリケーションが起動し、リーダーボードの表示とレコードの追加ができるようになっているはずです。
結果を追加すると、データがリアルタイムで保存・更新・ソートされているのがすぐに確認できます。まさに私たちが実現したかったことです!🎉
Fly.io へのデプロイ
次に、Flask アプリを Fly.io にデプロイして仕上げましょう。コードベースのルートから以下を実行します。
flyctl launch
Scanning source code
Detected a Python app
Using the following build configuration:
Builder: paketobuildpacks/builder:base
Creating app in /home/valon/code/upstash-fly-leaderboard
We're about to launch your Python app on Fly.io. Here's what you're getting:
Organization: <MyOrg> (fly launch defaults to the personal org)
Name: upstash-leaderboard (derived from your directory name)
Region: Amsterdam, Netherlands (this is the fastest region for you)
App Machines: shared-cpu-1x, 1GB RAM (most apps need about 1GB of RAM)
Postgres: <none> (not requested)
Redis: <none> (not requested)
? Do you want to tweak these settings before proceeding? (y/N) : N
これによりコードベースが検出され、アプリケーション名やコードなどに基づいたデフォルト設定が適用されます。ここではデフォルト設定のまま進めるので、N を入力します。
すると fly.toml と Procfile が生成されます。
app = "upstash-fly-leaderboard"
primary_region = "otp" #
[build]
builder = "paketobuildpacks/builder:base"
[env]
PORT = "8080"
[http_service]
internal_port = 8080 # アプリが動作するポート
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ["app"]
[[vm]]
cpu_kind = "shared"
cpus = 1
memory_mb = 1024
リージョンを otp に変更した以外は、すべてデフォルトのままにしています。次に、実行コマンドが定義されている Procfile を更新し、gunicorn でポート 8080 にて起動するようにしましょう。
web: gunicorn -b 0.0.0.0:8080 app:app
ここで最初の app はモジュール名、もう一方の app は Flask アプリを定義したモジュール内の変数名です。
ほぼ完了ですが、コード内で REDIS_URL を環境変数として読み込んでいたことを思い出してください。ローカルでは Fly CLI を使って作成した Upstash Redis の値を設定しましたが、Fly.io 上ではシークレットとして設定する必要があります。
fly secrets set --app upstash-fly-leaderboard REDIS_URL=<>
すべての準備が整いました。アプリを Fly.io にデプロイしましょう。
fly deploy --ha=false
出力には、新しくデプロイされたアプリケーションにアクセスするための URL が表示されるはずです。
Watch your deployment at https://fly.io/apps/<app_name>/monitoring
-------
Updating existing machines in '<app_name>' with rolling strategy
-------
✔ Machine <machine_id> [app] update succeeded
-------
Visit your newly deployed app at https://<app_name>.fly.dev/
まとめ
このチュートリアルでは、Upstash Redis と Fly.io をシームレスに統合してリアルタイムのリーダーボードを作成しました。サーバーレス Redis サービスの効率性と Fly.io のグローバル分散能力を組み合わせることで、世界中のユーザーが低レイテンシでアクセスできる環境を実現できました。
さらに、ユーザー認証の追加、詳細な統計情報の表示など、アプリケーションのニーズに合わせた機能を自由に拡張してみてください。Upstash Redis のパワーと Fly.io のグローバルリーチによって、魅力的で応答性の高い Web アプリケーションの未来はすでにここにあります。
記事の完全なソースコードは、手順付きで GitHub リポジトリから入手できます。
https://github.com/vjanz/upstash-fly-redis-leaderboard
ご質問がある場合はお気軽にお問い合わせください。LinkedIn や GitHub でもつながれます。
参考資料
Upstash
https://redis.io
https://fly.io/
-
Redis運用アーキテクチャ完全ガイド:シニアエンジニアが押さえるべき設計と運用の要点
本ページの動画をご覧いただくには、JavaScriptを有効にし、HTML5動画に対応した最新のウェブブラウザをご利用ください。 はじめに:なぜ今、Redis運用アーキテクチャが重要なのか Redisは、圧倒的な高速性と柔軟なデータ構造により、キャッシュ、セッションストア、メッセージング、リアルタイム分析など、現代のシステム開発に欠かせないインメモリデータストアとなっています。しかし、単一インスタンスでの利用にとどまらず、本番環境で安定したサービスを提供するには、レプリケーション、フェイルオーバー、スケーリングといった運用面の設計が不可欠です。 本ガイドでは、シニアエンジニアの視点から、実務
-
Redis ZREVRANGEBYSCOREコマンド徹底解説!スコア範囲を指定してソート済みセットの要素を降順で取得する方法
このチュートリアルでは、RedisのZREVRANGEBYSCOREコマンドを使用して、指定したスコア範囲内に含まれるソート済みセット(Sorted Set)の全要素を、スコアの降順で取得する方法を詳しく解説します。 ZREVRANGEBYSCOREコマンドとは ZREVRANGEBYSCOREコマンドは、引数として渡されたmax(最大値)以下かつmin(最小値)以上のスコアを持つ、ソート済みセット内のすべての要素を返します。要素はスコアの降順で返され、同一のスコアを持つ要素同士は辞書順の逆順(降順)で並べられます。 デフォルトではmaxとminは閉区間(境界値を含む)として扱われますが、値の