Daten mit Memorystore im Cache speichern

Leistungsfähige, skalierbare Webanwendungen verwenden für einige Aufgaben häufig einen verteilten speicherinternen Datencache vor einem robusten nichtflüchtigen Speicher oder anstelle dieses Speichers. Wir empfehlen die Verwendung von Memorystore for Redis als Caching-Dienst. Beachten Sie, dass Memorystore for Redis keine kostenlose Stufe bietet. Weitere Informationen finden Sie unter Memorystore – Preise.

Bevor Sie beginnen, müssen Sie dafür sorgen, dass Ihre Anwendung innerhalb der Kontingente für Memorystore for Redis bleibt.

Gründe für die Verwendung eines Memcache

Sitzungsdaten, Nutzereinstellungen und andere Daten, die von Abfragen für Webseiten zurückgegeben werden, eignen sich gut für das Caching. Wenn eine häufig ausgeführte Abfrage eine Reihe von Ergebnissen zurückgibt, die nicht sofort in Ihrer Anwendung angezeigt werden müssen, können Sie die Ergebnisse normalerweise im Cache speichern. Nachfolgende Anfragen können den Cache prüfen und die Datenbank nur abfragen, wenn Ergebnisse fehlen oder abgelaufen sind.

Wenn Sie einen Wert nur in Memorystore speichern, ohne ihn im nichtflüchtigen Speicher zu sichern, achten Sie darauf, dass Ihre Anwendung angemessen reagiert, wenn der Wert abläuft und aus dem Cache entfernt wird. Wenn beispielsweise Sitzungsdaten eines Nutzers plötzlich nicht mehr verfügbar sind und dies zu einer fehlerhaften Sitzung führen würde, sollten diese Daten nicht nur in Memorystore, sondern zusätzlich auch in der Datenbank gespeichert werden.

Informationen zu Memorystore-Berechtigungen

Jede Interaktion mit einem Google Cloud-Dienst muss autorisiert werden. Für die Interaktion mit einer von Memorystore gehosteten Redis-Datenbank muss Ihre Anwendung zum Beispiel die Anmeldedaten eines Kontos bereitstellen, das zum Zugriff auf Memorystore berechtigt ist.

Standardmäßig stellt Ihre Anwendung die Anmeldedaten für das Standarddienstkonto von App Engine bereit, das zum Zugriff auf Datenbanken berechtigt ist, die sich in demselben Projekt wie Ihre Anwendung befinden.

Wenn eine der folgenden Bedingungen zutrifft, müssen Sie eine alternative Authentifizierungsmethode verwenden, die Anmeldedaten explizit bereitstellt:

  • Ihre Anwendung und die Memorystore-Datenbank befinden sich in verschiedenen Google Cloud-Projekten.

  • Sie haben die Rollen geändert, die dem App Engine-Standarddienstkonto zugewiesen sind.

Informationen zu alternativen Authentifizierungsmethoden finden Sie unter Authentifizierung für Server-zu-Server-Produktionsanwendungen einrichten.

Überblick über die Verwendung von Memorystore

So verwenden Sie Memorystore in Ihrer Anwendung:

  1. Richten Sie Memorystore for Redis ein. Erstellen Sie dazu eine Redis-Instanz in Memorystore und einen serverlosen VPC-Zugriff, den Ihre Anwendung für die Kommunikation mit der Redis-Instanz verwendet.

  2. Installieren Sie eine Clientbibliothek für Redis und verwenden Sie Redis-Befehle, um Daten im Cache zu speichern.

    Memorystore for Redis ist mit allen Clientbibliotheken für Redis kompatibel.

    Go

    In diesem Leitfaden wird beschrieben, wie Sie mit der Clientbibliothek redigo Redis-Befehle aus Ihrer Anwendung senden.

    Java

    In diesem Leitfaden wird die Verwendung der Jedis erläutert, um Redis-Befehle von Ihrer Anwendung zu senden. Weitere Informationen zur Verwendung von Jedis finden Sie unter Jedis-Wiki.

    Node.js

    In diesem Leitfaden wird beschrieben, wie Sie mit der Clientbibliothek node_redis Redis-Befehle aus Ihrer Anwendung senden.

    PHP

    In dieser Anleitung wird beschrieben, wie Sie mit der PHPRedis Redis-Befehle von Ihrer App senden.

    Python

    In diesem Leitfaden wird beschrieben, wie Sie mit der Clientbibliothek redis-py 3.0 Redis-Befehle aus Ihrer Anwendung senden.

    Ruby

    In diesem Leitfaden wird beschrieben, wie Sie mit der Clientbibliothek redis-rb Redis-Befehle aus Ihrer Anwendung senden.

  3. Testen Sie Ihre Aktualisierungen.

  4. Stellen Sie die Anwendung in App Engine bereit.

Memorystore for Redis einrichten

So richten Sie Memorystore for Redis ein:

  1. Erstellen Sie eine Redis-Instanz in Memorystore.

    Wenn Sie aufgefordert werden, eine Region für Ihre Redis-Instanz auszuwählen, wählen Sie dieselbe Region aus, in der sich Ihre App Engine-Anwendung befindet.

  2. Notieren Sie sich die IP-Adresse und die Portnummer der von Ihnen erstellten Redis-Instanz. Sie benötigen diese Informationen, wenn Sie in Ihrem Code einen Redis-Client erstellen.

  3. Verbinden Sie Ihre App Engine-Anwendung mit einem VPC-Netzwerk. Ihre Anwendung kann nur über einen VPC-Connector mit Memorystore kommunizieren.

    Fügen Sie die Informationen zur VPC-Verbindung in die Datei app.yaml ein, wie unter Anwendung mit Connector konfigurieren beschrieben.

Abhängigkeiten installieren

Go

Fügen Sie die redigo-Clientbibliothek zu den Abhängigkeiten Ihrer Anwendung hinzu, um sie für Ihre Anwendung verfügbar zu machen, wenn sie in App Engine ausgeführt wird. Wenn Sie beispielsweise eine go.mod-Datei zum Deklarieren von Abhängigkeiten verwenden, fügen Sie die folgende Zeile zu Ihrer go.mod-Datei hinzu:

Modul github.com/GoogleCloudPlatform/golang-samples/tree/master/memorystore/redis

Hier finden Sie weitere Informationen, wie Sie für Ihre Go-Anwendung Abhängigkeiten angeben.

Java

Fügen Sie die Jedis-Clientbibliothek zu den Abhängigkeiten Ihrer Anwendung hinzu, um sie für Ihre Anwendung verfügbar zu machen, wenn sie in App Engine ausgeführt wird. Wenn Sie beispielsweise Maven verwenden, fügen Sie Ihrer Datei pom.xml die folgende Abhängigkeit hinzu:

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>5.1.0</version>
</dependency>

Node.js

Fügen Sie die node_redis-Clientbibliothek zur Datei package.json Ihrer Anwendung hinzu, um sie für Ihre Anwendung verfügbar zu machen, wenn sie in App Engine ausgeführt wird.

Beispiel:

{
  "name": "memorystore-redis",
  "description": "An example of using Memorystore(Redis) with Node.js",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": ">=16.0.0"
  },
  "dependencies": {
    "redis": "^4.0.0"
  }
}

Hier finden Sie weitere Informationen, wie Sie für Ihre Node.js-Anwendung Abhängigkeiten angeben.

PHP

Fügen Sie der Datei php.ini Ihrer Anwendung die Erweiterung redis.so hinzu, um die PHPRedis-Clientbibliothek für Ihre Anwendung verfügbar zu machen, wenn sie in App Engine ausgeführt wird. Beispiel:

; Enable the Redis extension on App Engine
extension=redis.so

Weitere Informationen zum Aktivieren von PHP-Erweiterungen in App Engine finden Sie unter Dynamisch ladbare Erweiterungen.

Python

Fügen Sie der Datei requirements.txt Ihrer Anwendung die folgende Zeile hinzu, um die redis-py-Clientbibliothek für Ihre Anwendung verfügbar zu machen, wenn sie in App Engine ausgeführt wird:

  redis

Die App Engine-Python 3-Laufzeitumgebung lädt automatisch alle Bibliotheken der requirements.txt-Datei Ihrer Anwendung hoch, wenn Sie die Anwendung bereitstellen.

Für die lokale Entwicklung empfehlen wir, Abhängigkeiten in einer virtuellen Umgebung wie venv zu installieren.

Ruby

Fügen Sie die redis-rb-Clientbibliothek zur Datei Gemfile Ihrer Anwendung hinzu, um sie für Ihre Anwendung verfügbar zu machen, wenn sie in App Engine ausgeführt wird.

  source "https://cloud.google.com/memorystore"

  gem "redis-rb"

Redis-Client erstellen

Für die Interaktion mit einer Redis-Datenbank muss Ihr Code einen Redis-Client erstellen, um die Verbindung zu Ihrer Redis-Datenbank zu verwalten. In den folgenden Abschnitten wird gezeigt, wie Sie einen Redis-Client mit der Redis-Clientbibliothek erstellen.

Umgebungsvariablen angeben

Die Redis-Clientbibliothek verwendet zwei Umgebungsvariablen, um die URL für Ihre Redis-Datenbank zusammenzustellen:

  • Eine Variable zur Identifizierung der IP-Adresse der Redis-Datenbank, die Sie in Memorystore erstellt haben.
  • Eine Variable zur Identifizierung der Portnummer der Redis-Datenbank, die Sie in Memorystore erstellt haben.

Wir empfehlen, diese Variablen in der Datei app.yaml Ihrer Anwendung zu definieren, anstatt sie direkt im Code zu definieren. Dies erleichtert die Ausführung der Anwendung in verschiedenen Umgebungen, z. B. in einer lokalen Umgebung und in App Engine. Weitere Informationen zu Umgebungsvariablen finden Sie auf der app.yaml-Referenzseite.

Go

Fügen Sie Ihrer app.yaml-Datei beispielsweise die folgenden Zeilen hinzu:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

Java

Fügen Sie Ihrer app.yaml-Datei beispielsweise die folgenden Zeilen hinzu:

  env_variables:
       redis.host: '10.112.12.112'
       redis.port: '6379'

Node.js

Fügen Sie Ihrer app.yaml-Datei beispielsweise die folgenden Zeilen hinzu:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

PHP

Fügen Sie Ihrer app.yaml-Datei beispielsweise die folgenden Zeilen hinzu:

  env_variables:
       REDIS_HOST: '10.112.12.112'
       REDIS_PORT: '6379'

Python

Fügen Sie Ihrer app.yaml-Datei beispielsweise die folgenden Zeilen hinzu:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

Ruby

Fügen Sie Ihrer app.yaml-Datei beispielsweise die folgenden Zeilen hinzu:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

Redis importieren und Client erstellen

Go

Nachdem Sie die Umgebungsvariablen REDISHOST und REDISPORT definiert haben, können Sie mithilfe der folgenden Zeilen die redigo-Clientbibliothek importieren, einen Verbindungspool erstellen und dann einen Redis-Client aus dem Pool abrufen:


// Command redis is a basic app that connects to a managed Redis instance.
package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/gomodule/redigo/redis"
)

var redisPool *redis.Pool

func incrementHandler(w http.ResponseWriter, r *http.Request) {
	conn := redisPool.Get()
	defer conn.Close()

	counter, err := redis.Int(conn.Do("INCR", "visits"))
	if err != nil {
		http.Error(w, "Error incrementing visitor counter", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Visitor number: %d", counter)
}

func main() {
	redisHost := os.Getenv("REDISHOST")
	redisPort := os.Getenv("REDISPORT")
	redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)

	const maxConnections = 10
	redisPool = &redis.Pool{
		MaxIdle: maxConnections,
		Dial:    func() (redis.Conn, error) { return redis.Dial("tcp", redisAddr) },
	}

	http.HandleFunc("/", incrementHandler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("Listening on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}

Java

Wenn Sie die Jedis-Bibliothek verwenden, empfehlen wir, einen JedisPool anzulegen und dann den Pool zum Erstellen eines Clients zu verwenden. Die folgenden Codezeilen verwenden die zuvor definierten redis.host- und redis.port-Umgebungsvariablen, um einen Pool zu erstellen:


package com.example.redis;

import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@WebListener
public class AppServletContextListener implements ServletContextListener {

  private Properties config = new Properties();

  private JedisPool createJedisPool() throws IOException {
    String host;
    Integer port;
    config.load(
        Thread.currentThread()
            .getContextClassLoader()
            .getResourceAsStream("application.properties"));
    host = config.getProperty("redis.host");
    port = Integer.valueOf(config.getProperty("redis.port", "6379"));

    JedisPoolConfig poolConfig = new JedisPoolConfig();
    // Default : 8, consider how many concurrent connections into Redis you will need under load
    poolConfig.setMaxTotal(128);

    return new JedisPool(poolConfig, host, port);
  }

  @Override
  public void contextDestroyed(ServletContextEvent event) {
    JedisPool jedisPool = (JedisPool) event.getServletContext().getAttribute("jedisPool");
    if (jedisPool != null) {
      jedisPool.destroy();
      event.getServletContext().setAttribute("jedisPool", null);
    }
  }

  // Run this before web application is started
  @Override
  public void contextInitialized(ServletContextEvent event) {
    JedisPool jedisPool = (JedisPool) event.getServletContext().getAttribute("jedisPool");
    if (jedisPool == null) {
      try {
        jedisPool = createJedisPool();
        event.getServletContext().setAttribute("jedisPool", jedisPool);
      } catch (IOException e) {
        // handle exception
      }
    }
  }
}

Verwenden Sie die Methode JedisPool.getResource(), um einen Client aus dem Pool zu erstellen. Beispiel:


package com.example.redis;

import java.io.IOException;
import java.net.SocketException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@WebServlet(name = "Track visits", value = "")
public class VisitCounterServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    try {
      JedisPool jedisPool = (JedisPool) req.getServletContext().getAttribute("jedisPool");

      if (jedisPool == null) {
        throw new SocketException("Error connecting to Jedis pool");
      }
      Long visits;

      try (Jedis jedis = jedisPool.getResource()) {
        visits = jedis.incr("visits");
      }

      resp.setStatus(HttpServletResponse.SC_OK);
      resp.getWriter().println("Visitor counter: " + String.valueOf(visits));
    } catch (Exception e) {
      resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
    }
  }
}

Node.js

Nachdem Sie die Umgebungsvariablen REDISHOST und REDISPORT definiert haben, können Sie mithilfe der folgenden Zeilen die node_redis-Clientbibliothek importieren und einen Redis-Client erstellen:

'use strict';
const http = require('http');
const redis = require('redis');

const REDISHOST = process.env.REDISHOST || 'localhost';
const REDISPORT = process.env.REDISPORT || 6379;

const client = redis.createClient(REDISPORT, REDISHOST);
client.on('error', err => console.error('ERR:REDIS:', err));

// create a server
http
  .createServer((req, res) => {
    // increment the visit counter
    client.incr('visits', (err, reply) => {
      if (err) {
        console.log(err);
        res.status(500).send(err.message);
        return;
      }
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end(`Visitor number: ${reply}\n`);
    });
  })
  .listen(8080);

PHP

Nachdem Sie die Umgebungsvariablen REDIS_HOST und REDIS_PORT definiert haben, können Sie die folgenden Zeilen verwenden, um einen Redis-Client zu erstellen:

<?php
/**
 * Copyright 2019 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Only serve traffic from "/"
switch (@parse_url($_SERVER['REQUEST_URI'])['path']) {
    case '/':
        break;
    default:
        http_response_code(404);
        exit('Not Found');
}

// Connect to Memorystore from App Engine.
if (!$host = getenv('REDIS_HOST')) {
    throw new Exception('The REDIS_HOST environment variable is required');
}

# Memorystore Redis port defaults to 6379
$port = getenv('REDIS_PORT') ?: '6379';

try {
    $redis = new Redis();
    $redis->connect($host, $port);
} catch (Exception $e) {
    return print('Error: ' . $e->getMessage());
}

$value = $redis->incr('counter');

printf('Visitor number: %s', $value);

Python

Nach dem Definieren der Umgebungsvariablen REDISHOST und REDISPORT verwenden Sie die folgenden Zeilen, um die redis-py-Bibliothek zu importieren und einen Client zu erstellen:

  import redis

  redis_host = os.environ.get('REDISHOST', 'localhost')
  redis_port = int(os.environ.get('REDISPORT', 6379))
  redis_client = redis.Redis(host=redis_host, port=redis_port)

Wenn Sie eine ältere Version von redis-py für andere Anwendungen verwendet haben, haben Sie möglicherweise statt Client die Klasse StrictClient verwendet. Inzwischen empfiehlt redis-py jedoch Client anstatt StrictClient.

Ruby

Keine weiteren Informationen zu dieser Laufzeit.

Daten im Cache mit Redis-Befehlen speichern und abrufen

Die Redis-Datenbank in Memorystore unterstützt die meisten Redis-Befehle, daher benötigen Sie zum Speichern und Abrufen von Daten aus dem Cache nur wenige Befehle. In der folgenden Tabelle werden Redis-Befehle vorgeschlagen, mit denen Sie Daten im Cache speichern können. Informationen zum Aufrufen dieser Befehle aus Ihrer Anwendung finden Sie in der Dokumentation der Clientbibliothek.

Aufgabe Redis-Befehl
Eintrag im Datencache erstellen und
eine Ablaufzeit für den Eintrag festlegen
SETNX
MSETNX
Daten aus dem Cache abrufen GET
MGET
Vorhandene Cachewerte ersetzen SET
MSET
Erhöht oder verringert numerische Cache-Werte INCR
INCRBY
DECR
DECRBY
Einträge aus dem Cache löschen DEL
UNLINK
Gleichzeitige Interaktionen mit dem Cache unterstützen Weitere Informationen zu Redis-Transaktionen

Bei Python erfordert die redis-py-Clientbibliothek, dass alle Transaktionen in einer Pipeline ausgeführt werden.

Aktualisierungen testen

Wenn Sie Ihre Anwendung lokal testen, sollten Sie eine lokale Instanz von Redis ausführen, um die Interaktion mit Produktionsdaten zu vermeiden (Memorystore stellt keinen Emulator bereit). Folgen Sie der Anleitung in der Redis-Dokumentation, um Redis lokal zu installieren und auszuführen. Redis kann derzeit nicht lokal unter Windows ausgeführt werden.

Weitere Informationen zum Testen von Anwendungen finden Sie unter Anwendung testen und bereitstellen.

Anwendung bereitstellen

Sobald Ihre Anwendung auf dem lokalen Entwicklungsserver fehlerfrei ausgeführt wird:

  1. Testen Sie die Anwendung in App Engine.

  2. Wenn die Anwendung fehlerfrei ausgeführt wird, verwenden Sie die Trafficaufteilung, um den Traffic für die aktualisierte Anwendung langsam hochzufahren. Prüfen Sie die Anwendung genau auf mögliche Datenbankprobleme, bevor Sie mehr Traffic zur aktualisierten Anwendung leiten.