Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

สร้าง Mobile Leaderboard ประสิทธิภาพสูงด้วย React Native, AWS Lambda และ Upstash Redis

สร้างแอป Leaderboard บน Mobile ด้วย React Native Backend: Serverless Framework + Python on AWS Lambda Database: Upstash Redis

1. ทำไมต้อง Upstash Redis?

Leaderboard ต้องการ:

  • เก็บ User + Score
  • เรียงลำดับตาม Score
  • Query Top N, Rank, Range ได้เร็ว

Redis Sorted Set (ZSET) ตอบโจทย์ทุกข้อ: O(log N) สำหรับ Insert/Update/Range Query

ข้อดีของ Upstash:

  • Pay-as-you-go + Free Tier
  • Setup ง่าย ไม่ต้อง Config Server
  • HTTP REST API - ใช้ใน Lambda ได้เลย

1.1 เริ่มต้น Upstash

  1. สร้าง Account/DB ที่ Console
  2. ทดลอง CLI ใน Console:
# เพิ่ม User + Score
ZADD Leaderboard 15 "Jack_Thang"

# ดู Leaderboard ทั้งหมด (Descending)
ZRANGE Leaderboard 0 -1 WITHSCORES

2. Serverless Framework + AWS Lambda

Install & Config

# Install Serverless
npm install -g serverless
serverless create --template aws-python3 --path leaderboard-api
cd leaderboard-api

# Plugin สำหรับ Python Dependencies
serverless plugin install -n serverless-python-requirements

serverless.yml

service: leaderboard-api
frameworkVersion: '3'
provider:
  name: aws
  runtime: python3.9
  region: us-east-1
plugins:
  - serverless-python-requirements
functions:
  addScore:
    handler: handler.addScore
    events:
      - httpApi: 'POST /add'
  getLeaderboard:
    handler: handler.getLeaderboard
    events:
      - httpApi: 'GET /getLeaderboard'

requirements.txt

redis==4.0.2

handler.py

import json
import redis
import os

r = redis.Redis(
    host=os.environ['REDIS_ENDPOINT'],
    port=os.environ['REDIS_PORT'],
    password=os.environ['REDIS_PASSWORD'],
    charset="utf-8",
    decode_responses=True
)

LEADERBOARD_KEY = "Leaderboard"

def addScore(event, context):
    info = json.loads(event["body"])
    score = info["score"]
    player_name = f"{info['firstname']}_{info['lastname']}"
    
    r.zadd(LEADERBOARD_KEY, {player_name: score})
    
    return {
        "statusCode": 200,
        "body": json.dumps({"message": "Score added successfully!"})
    }

def getLeaderboard(event, context):
    # Descending order (Highest first)
    score_list = r.zrange(LEADERBOARD_KEY, 0, -1, withscores=True, desc=True)
    
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "Leaderboard returned successfully!",
            "leaderboard": score_list
        })
    }

Deploy

serverless deploy -v

บันทึก Endpoints ที่ได้:

POST - https://xxx.execute-api.us-east-1.amazonaws.com/add
GET  - https://xxx.execute-api.us-east-1.amazonaws.com/getLeaderboard

3. React Native Mobile App

Screen 1: Submit Score

async addScore() {
  if (isNaN(this.state.score)) {
    Alert.alert("Error", "Please enter a valid score.");
    return;
  }
  if (!this.state.firstname || !this.state.lastname || !this.state.score) {
    Alert.alert("Error", "Please fill in the blanks.");
    return;
  }

  try {
    const response = await fetch('https://xxx.execute-api.us-east-1.amazonaws.com/add', {
      method: 'POST',
      headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
      body: JSON.stringify({
        firstname: this.state.firstname,
        lastname: this.state.lastname,
        score: parseInt(this.state.score)
      })
    });
    const data = await response.json();
    if (data.message === "Score added successfully!") {
      Alert.alert("Done!", "Score added successfully!");
    } else {
      Alert.alert("Error", "Please try again later.");
    }
  } catch (err) {
    console.error(err);
    Alert.alert("Error", "Please try again later.");
  }
}

Screen 2: Leaderboard View

async componentDidMount() {
  try {
    const response = await fetch('https://xxx.execute-api.us-east-1.amazonaws.com/getLeaderboard', {
      method: 'GET',
      headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }
    });
    const data = await response.json();
    this.setState({ userlist: data.leaderboard, reRender: !this.state.reRender });
  } catch (err) {
    console.error(err);
  }
}

// Render
render() {
  return (
    <View>
      {this.state.userlist.map(([name, score], index) => (
        <Text key={index}>#{index + 1} {name}: {score}</Text>
      ))}
    </View>
  );
}

สรุป

  • Leaderboard ด้วย Redis Sorted Set = Fast, Scalable, Simple
  • Serverless Framework จัดการ AWS Lambda ได้ง่าย
  • Upstash Redis: No Server Management, HTTP API, Pay-per-use
  • React Native เรียก REST API โดยตรง

Source Code: GitHub Repository