Tutorial: utilizzo di Memorystore for Redis come classifica del gioco


Questo tutorial mostra come utilizzare Memorystore per Redis per creare un'applicazione leaderboard basata su ASP.NET in esecuzione su Google Kubernetes Engine (GKE), per poi pubblicare e recuperare i punteggi utilizzando un gioco di esempio separato basato su JavaScript. Questo documento è destinato agli sviluppatori di giochi che vogliono gestire le proprie classifiche nel cloud.

Introduzione

Le classifiche sono una funzionalità comune nei giochi multiplayer. Una classifica mostra le classifiche dei giocatori in tempo reale, incoraggiando i giocatori a essere più coinvolti nel gioco. Per acquisire le azioni dei giocatori e classificare il punteggio in tempo reale, un database in memoria come Redis è un'ottima scelta.

Il seguente diagramma mostra l'infrastruttura della classifica:

Diagramma che mostra un cluster GKE all'interno di un VPC e un'istanza Memorystore for Redis separata.

In Google Cloud, la classifica è composta da un cluster GKE all'interno di una rete VPC e da un'istanza Memorystore for Redis separata.

Il seguente diagramma mostra l'architettura delle applicazioni per questo tutorial. I client utilizzano l'API leaderboard per interagire con i punteggi che vengono gestiti in un'istanza Memorystore for Redis in esecuzione su Google Cloud.

Diagramma che mostra l'architettura dell'applicazione in questo tutorial

Metodi dell'API leaderboard

L'API per l'applicazione leaderboard include i seguenti metodi:

  • PostScore(string playerName, double score). Questo metodo pubblica un punteggio nella classifica per il giocatore specificato.
  • RetrieveScores(string centerKey, int offset, int numScores). Questo metodo scarica un insieme di punteggi. Se trasmetti un ID player come valore per centerKey, il metodo restituisce i punteggi superiori e inferiori a quelli del player specificato. Se non passi un valore per centerKey, il metodo restituisce i primi N punteggi assoluti, dove N è il valore trasmesso numScores. Ad esempio, per ricevere i primi 10 punteggi, chiama RetrieveScores('', 0, 10). Per ottenere 5 punteggi superiori e inferiori al punteggio di un giocatore, chiama RetrieveScores('player1', -5, 10).

Il repository di codice per l'esempio include un gioco simulato e un'implementazione di classifica di tipo proof of concept. Durante questo tutorial, eseguirai il deployment del gioco e della classifica e verificherai che l'API Classifica funzioni correttamente e sia possibile accedervi tramite internet.

Obiettivi

  • Creare un'istanza di Memorystore for Redis.
  • Crea un servizio headless con un endpoint che indirizza le richieste a questa istanza.
  • Eseguire il deployment dell'applicazione leaderboard in GKE.
  • Verifica la funzionalità leaderboard utilizzando l'applicazione di cui hai eseguito il deployment che effettua chiamate API.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud possono essere idonei a una prova senza costi aggiuntivi.

Prima di iniziare

  1. Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  3. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  4. Abilita le API Memorystore for Redis and Google Kubernetes Engine.

    Abilita le API

  5. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  6. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  7. Abilita le API Memorystore for Redis and Google Kubernetes Engine.

    Abilita le API

Preparazione dell'ambiente

In questo tutorial eseguirai comandi in Cloud Shell. Cloud Shell ti dà accesso alla riga di comando in Google Cloud e include Google Cloud CLI e altri strumenti necessari per lo sviluppo in Google Cloud. L'inizializzazione di Cloud Shell può richiedere diversi minuti.

  1. Apri Cloud Shell:

    Apri Cloud Shell

  2. Imposta la zona predefinita di Compute Engine sulla zona in cui intendi creare le risorse Google Cloud. In questo tutorial utilizzerai la zona us-central1-a nella regione us-central1.

    export REGION=us-central1
    export ZONE=us-central1-a
    gcloud config set compute/zone $ZONE
    
  3. Clona il repository GitHub che contiene il codice campione:

    git clone https://github.com/GoogleCloudPlatform/memstore-gaming-leaderboard.git
    
  4. Vai alla directory clonata:

    cd memstore-gaming-leaderboard
    
  5. Con un editor di testo, apri il file leaderboardapp/k8s/appdeploy.yaml e cambia il segnaposto [YOUR_PROJECT_ID] nel tuo ID progetto Google Cloud.

Creazione di un'istanza Memorystore for Redis

Per questo tutorial, creerai un'istanza di livello base di Memorystore for Redis, appropriata per i test e per l'ambito di questo tutorial. Per un deployment in produzione, consigliamo di eseguire il deployment di un'istanza di livello Standard, che fornisce uno SLA del 99,9% con failover automatico per garantire l'alta disponibilità dell'istanza. Per maggiori dettagli sulle istanze del livello Standard, consulta Alta disponibilità per Memorystore for Redis.

  • In Cloud Shell, crea un'istanza Memorystore for Redis da 1 GB:

    gcloud redis instances create cm-redis --size=1 \
      --tier=basic \
      --region=$REGION \
      --zone=$ZONE
    

    Il completamento di questo comando potrebbe richiedere alcuni minuti.

crea le immagini container dell'applicazione

Per questo tutorial, eseguirai il deployment di una semplice applicazione leaderboard utilizzando GKE. Poiché Unity e C# sono popolari nei giochi, il livello applicazione utilizza C# e ASP.NET framework.

Per eseguire il deployment dell'API leaderboard in un cluster GKE, devi prima caricarla in un registry come Container Registry.

  1. Apri il file README.md nel progetto GitHub che hai clonato.
  2. Segui le istruzioni per creare un'immagine Docker e caricarla in Container Registry.

Utilizzerai questa immagine per eseguire il deployment dell'applicazione leaderboard dopo aver creato il cluster nella sezione successiva.

Creazione o riutilizzo di un cluster GKE

Prima di eseguire il deployment dell'applicazione leaderboard, devi creare un cluster GKE con intervalli IP alias abilitati. Se hai già un cluster GKE (con intervalli IP alias), puoi utilizzarlo per questo tutorial. Se utilizzi un cluster esistente, devi eseguire un passaggio aggiuntivo per configurare lo strumento a riga di comando kubectl con le credenziali per il cluster.

  1. Se vuoi creare un cluster, creane uno denominato leaderboard che abbia due nodi:

    gcloud container clusters create leaderboard --num-nodes=2 --enable-ip-alias
    

    Il completamento di questo comando può richiedere alcuni minuti.

  2. Dopo aver atteso l'avvio del cluster, verifica che sia in esecuzione:

    gcloud container clusters list
    

    Il cluster è in esecuzione quando vedi una voce con nome leaderboard il cui stato è RUNNING.

Configura le credenziali per un cluster esistente

  1. Se utilizzi un cluster GKE esistente per questo tutorial, configura il file kubeconfig con le credenziali per il cluster. Per name-of-existing-cluster, utilizza il nome del cluster.

    gcloud container clusters get-credentials name-of-existing-cluster
    

Mappatura dell'istanza Memorystore for Redis a un servizio Kubernetes

Quando l'istanza Memorystore for Redis è pronta, crei un servizio all'interno del cluster GKE in modo che il livello di applicazione possa connettersi.

  1. Verifica che l'istanza Memorystore for Redis sia in esecuzione:

    gcloud redis instances list --region=$REGION
    

    Verrà visualizzato un output simile al seguente:

    INSTANCE_NAME  VERSION    REGION           TIER       SIZE_GB    HOST       PORT  NETWORK  RESERVED_IP  STATUS    CREATE_TIME
    cm-redis       REDIS_4_0  us-central1      STANDARD  1            10.0.0.3  6379  default  10.0.0.0/29  READY     2019-05-10T04:37:45
    

    L'istanza è in esecuzione quando la colonna STATUS mostra READY. Se il campo HOST è vuoto, l'istanza non ha completato il processo di avvio. Attendi un istante ed esegui di nuovo il comando redis instances list.

  2. Archivia l'indirizzo IP dell'istanza in una variabile di ambiente:

    export REDIS_IP=$(gcloud redis instances list --filter="name:cm-redis" --format="value(HOST)" \
        --region=$REGION)
    
  3. Crea il servizio Kubernetes per Redis:

    kubectl apply -f k8s/redis_headless_service.yaml
    

    Questo servizio non ha un selettore pod perché vuoi che punti a un indirizzo IP esterno al cluster Kubernetes.

  4. Crea un endpoint che definisce l'indirizzo IP Redis che hai recuperato in precedenza:

    sed "s|REDIS_IP|${REDIS_IP}|g" k8s/redis_endpoint.yaml | kubectl apply -f -
    
  5. Verifica che il servizio e l'endpoint siano stati creati correttamente:

    kubectl get services/redis endpoints/redis
    

    Se tutto funziona correttamente, verrà visualizzato un output come il seguente, con una voce per il servizio Redis e l'endpoint Redis:

    NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    service/redis      ClusterIP   10.59.241.103   none        6379/TCP   5m
    
    NAME               ENDPOINTS       AGE
    endpoints/redis    10.0.0.3:6379   4m
    

Per ulteriori informazioni sui servizi e sugli endpoint Kubernetes, vedi Best practice di Kubernetes: mappatura dei servizi esterni sul blog di Google Cloud.

Deployment dell'app e del servizio leaderboard in Kubernetes

L'istanza Redis è ora raggiungibile da un'applicazione di cui è stato eseguito il deployment nel cluster GKE. Di conseguenza, sei pronto a eseguire il deployment dell'app Classifica.

  • Segui le istruzioni nel file README.md incluse nel root del repository GitHub che hai clonato in precedenza.

Convalida del deployment in corso...

L'applicazione di gioco simulata fornita, scritta in JavaScript, può essere utilizzata per chiamare l'API leaderboard. Il seguente snippet di codice mostra il punteggio dei post del gioco fittizio al termine del gioco:

                    var scoreInfo = {
                        playerName: this.username,
                        score: this.calculateScore().toFixed(2)
                    };

                    var pThis = this;

                    var postUrl = "/api/score";
                    (async () => {
                        try {
                            await axios.post(postUrl, scoreInfo)
                        } catch (error) {
                            console.error(error);
                        }

                        var lbPromise = pThis.fetchLeaderboard();
                        var qPromise = pThis.fetchQuestions();

                        pThis.questions = await qPromise;
                        await lbPromise;
                    })();

Inoltre, l'app esegue una chiamata API per recuperare i punteggi della classifica, ovvero i punteggi migliori o i punteggi centrati sul nome del giocatore, in questo modo:

                    var pThis = this;
                    var getUrl = "/api/score/retrievescores";

                    (async () => {
                        try {
                            var params = {
                                centerKey: '',
                                offset: 0,
                                numScores: 11
                            };

                            if (pThis.centered) {
                                params.centerKey = pThis.username;
                                params.offset = -5;
                                params.numScores = 11;
                            }

                            const response = await axios.get(getUrl, { params: params });
                            pThis.leaderboard = response.data;
                        } catch (error) {
                            console.error(error);
                            return []
                        }
                    })();

Per accedere all'applicazione di esempio:

  1. Ottieni l'indirizzo IP del gioco simulato eseguendo questo comando:

    kubectl get ingress
    

    L'output è simile al seguente:

    NAME                      HOSTS   ADDRESS        PORTS   AGE
    memstore-gaming-ingress   *       34.102.192.4   80      43s
    
  2. Vai al seguente URL, dove ip_address_for_gke è l'indirizzo del gioco di simulazione:

    http://ip_address_for_gke.
    

Questo esempio è semplice, ma è adeguato per dimostrare l'utilizzo di base dell'API. Quando pubblichi o recuperi i punteggi direttamente dall'app client di gioco in esecuzione su un dispositivo o una macchina dell'utente, l'esempio chiama l'API leaderboard all'indirizzo IP pubblico assegnato al relativo oggetto Bilanciatore del carico Kubernetes. Per questa applicazione di esempio, sia l'API leaderboard che il client JavaScript sono ospitati allo stesso indirizzo IP che utilizzi per il comando kubectl get ingress mostrato in precedenza.

Come sono implementati i metodi

L'applicazione leaderboard, scritta in C#, utilizza la libreria StackExchange.Redis per comunicare con Redis. Gli snippet di codice che seguono mostrano come vengono implementati PostScore e RetrieveScores utilizzando Redis e la libreria StackExchange.Redis.

Il seguente snippet di codice mostra il metodo PostScore:

        public async Task<bool> PostScoreAsync(ScoreModel score)
        {
            IDatabase db = _redis.GetDatabase();

            // SortedSetAddAsync corresponds to ZADD
            return await db.SortedSetAddAsync(LEADERBOARD_KEY, score.PlayerName, score.Score);
        }

Il seguente snippet di codice mostra il metodo RetrieveScores:

        public async Task<IList<LeaderboardItemModel>> RetrieveScoresAsync(RetrieveScoresDetails retrievalDetails)
        {
            IDatabase db = _redis.GetDatabase();
            List<LeaderboardItemModel> leaderboard = new List<LeaderboardItemModel>();

            long offset = retrievalDetails.Offset;
            long numScores = retrievalDetails.NumScores;

            // If centered, get rank of specified user first
            if (!string.IsNullOrWhiteSpace(retrievalDetails.CenterKey))
            {
                // SortedSetRankAsync corresponds to ZREVRANK
                var rank = await db.SortedSetRankAsync(LEADERBOARD_KEY, retrievalDetails.CenterKey, Order.Descending);

                // If specified user is not present, return empty leaderboard
                if (!rank.HasValue)
                {
                    return leaderboard;
                }

                // Use rank to calculate offset
                offset = Math.Max(0, rank.Value + retrievalDetails.Offset);

                // Account for number of scores when we're attempting to center
                // at element in rank [0, abs(offset))
                if(offset <= 0)
                {
                    numScores = rank.Value + Math.Abs((long)retrievalDetails.Offset) + 1;
                }
            }

            // SortedSetRangeByScoreWithScoresAsync corresponds to ZREVRANGEBYSCORE [WITHSCORES]
            var scores = await db.SortedSetRangeByScoreWithScoresAsync(LEADERBOARD_KEY,
                skip: offset,
                take: numScores,
                order: Order.Descending);

            var startingRank = offset;
            for (int i = 0; i < scores.Length; i++)
            {
                var lbItem = new LeaderboardItemModel
                {
                    Rank = startingRank++,
                    PlayerName = scores[i].Element.ToString(),
                    Score = scores[i].Score
                };
                leaderboard.Add(lbItem);
            }

            return leaderboard;
        }

Aggiunte al gioco di esempio

L'API leaderboard segue le convenzioni REST ed è fornita solo come esempio. Quando esegui una classifica di un gioco in produzione, ti consigliamo di integrare un flusso di autenticazione in modo che possano essere pubblicati solo i punteggi provenienti da utenti convalidati.

Attualmente, Memorystore per Redis non fornisce persistenza per i punteggi dei giocatori. Pertanto, se si verifica un problema con l'app, potresti perdere le informazioni sulla classifica. Se il tuo gioco richiede una classifica persistente, devi periodicamente eseguire il backup dei punteggi della classifica in un database persistente.

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto.

Elimina il progetto

  1. Nella console Google Cloud, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Passaggi successivi