Upstash Redis와 Fly.io로 엣지에서 실시간 리더보드 구축하기
역동적이고 몰입감 있는 웹 애플리케이션에서 리더보드(순위표)는 사용자 간 경쟁을 유도하고 참여도를 높이는 강력한 도구입니다. 이 튜토리얼에서는 Upstash Redis를 백엔드 저장소로 활용하고 Fly.io를 통해 엣지에 배포하여 실시간 리더보드를 만드는 과정을 단계별로 살펴봅니다. 서버리스 Redis의 효율성과 Fly.io의 글로벌 분산 배포 능력이 결합되면, 전 세계 어디서든 낮은 지연 시간으로 접근할 수 있는 애플리케이션을 만들 수 있습니다.
Upstash Redis란 무엇인가?
Upstash는 완전 관리형 Redis 서비스를 제공하는 클라우드 플랫폼으로, 단순성·확장성·사용 편의성에 중점을 두고 있습니다. 다재다능한 고성능 인메모리 데이터 저장소인 Redis가 Upstash와 결합하면 그 활용 가치가 한층 더 높아집니다. Upstash를 사용하면 인프라 관리에 따르는 운영 부담 없이도 다양한 용도로 Redis를 손쉽게 배포하고 확장할 수 있습니다.
Upstash Redis의 주요 특징은 다음과 같습니다.
손쉬운 배포: 복잡한 설정 과정을 대폭 줄여주므로, 인프라 운영 부담을 덜고 싶은 개발자에게 최적의 선택입니다.
뛰어난 성능: Redis는 빛처럼 빠른 데이터 조회 속도로 유명하며, 작업 큐, 메시지 전달, 그리고 이 튜토리얼에서 다룰 실시간 리더보드 처리에 적합합니다. Upstash의 클라우드 인프라를 활용하면 자동 확장이 가능해 다양한 워크로드를 효율적으로 감당할 수 있습니다.
확장성: Redis는 높은 확장성을 갖추고 있으며, Upstash를 사용하면 수요에 따라 자동으로 규모를 조정합니다. 덕분에 애플리케이션이 항상 변화하는 트래픽에 대비할 수 있어, 동적인 서비스에 이상적입니다.
통합 데이터 저장소: Redis는 메시지 브로커 역할과 결과 저장소 역할을 동시에 수행할 수 있어, 관리해야 할 컴포넌트 수를 줄이고 아키텍처를 단순화합니다.
실시간 리더보드 애플리케이션에 Upstash Redis를 도입하면 Fly.io의 글로벌 배포 능력과 상호 보완적인 완전 관리형 Redis의 장점을 누릴 수 있으며, 그 결과 견고하고 반응성이 뛰어난 웹 애플리케이션 아키텍처를 완성할 수 있습니다. 이제 구현 과정을 살펴보며 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를 통해 Upstash Redis 데이터베이스를 만들 수 있습니다.
생성된 데이터베이스의 REDIS_URL은 출력 결과나 다음 명령어로 확인할 수 있습니다.
flyctl redis status upstash-fly-leaderboard
# 또는 Upstash 대시보드 열기
fly redis dashboard <your_org_name | personal>
private_url 값을 복사해 두세요. 이후 Flask 앱에서 필요합니다.
Flask 애플리케이션 개발
리더보드를 만들기 위해 Flask를 사용합니다. Flask는 웹 애플리케이션 구축을 위한 미니멀한 Python 프레임워크입니다. 먼저 의존성 패키지를 설치합니다.
# flask - 웹 애플리케이션 프레임워크
# redis - Redis 연결 및 조작을 위한 래퍼
# gunicorn - Python 웹 애플리케이션 실행용 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는 정렬된 집합(sorted set)에 점수와 함께 하나 이상의 멤버를 추가하는 Redis 명령어입니다.
두 번째 함수인 get_leaderboard()는 Redis 정렬된 집합(리더보드)에서 점수와 함께 상위 10개 항목을 조회한 뒤, 플레이어 ID와 해당 점수가 담긴 포맷팅된 리스트를 반환합니다.
자, 이제 Upstash Redis 데이터베이스와 상호작용할 세 개의 엔드포인트를 추가해 보겠습니다.
[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
리전(region)을 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에 시크릿(secret)으로 등록합니다.
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의 글로벌 리치가 함께 만들어가는, 몰입도 높고 반응성 뛰어난 웹 애플리케이션의 미래가 이미 시작되었습니다.
이 글의 전체 소스 코드와 실행 방법은 GitHub 저장소에서 확인하실 수 있습니다.
https://github.com/vjanz/upstash-fly-redis-leaderboard
궁금한 점이 있다면 언제든 문의해 주세요. LinkedIn과 GitHub에서도 만나볼 수 있습니다.
참고 자료
Upstash
https://redis.io
https://fly.io/