Almacenar datos en caché con Memorystore

Las aplicaciones web escalables de alto rendimiento suelen usar una caché de datos distribuida en memoria antes o en lugar de un almacenamiento persistente robusto para algunas tareas. Te recomendamos que uses Memorystore para Redis como servicio de almacenamiento en caché. Ten en cuenta que Memorystore para Redis no ofrece un nivel gratuito. Para obtener más información, consulta la página Precios de Memorystore.

Antes de empezar, asegúrate de que tu aplicación no supere las cuotas de Memorystore para Redis.

Cuándo usar una caché de memoria

Los datos de sesión, las preferencias de los usuarios y otros datos devueltos por las consultas de páginas web son buenos candidatos para el almacenamiento en caché. Por lo general, si una consulta que se ejecuta con frecuencia devuelve un conjunto de resultados que no tienen que aparecer en tu aplicación inmediatamente, puedes almacenar en caché los resultados. Las solicitudes posteriores pueden comprobar la caché y solo consultar la base de datos si los resultados no están o han caducado.

Si almacenas un valor solo en Memorystore sin crear una copia de seguridad en el almacenamiento persistente, asegúrate de que tu aplicación se comporte de forma aceptable si el valor caduca y se elimina de la caché. Por ejemplo, si la ausencia repentina de los datos de sesión de un usuario provocara que la sesión no funcionara correctamente, esos datos probablemente deberían almacenarse en la base de datos, además de en Memorystore.

Información sobre los permisos de Memorystore

Cada interacción con un servicio de Google Cloud debe autorizarse. Por ejemplo, para interactuar con una base de datos Redis alojada en Memorystore, tu aplicación debe proporcionar las credenciales de una cuenta que tenga autorización para acceder a Memorystore.

De forma predeterminada, tu aplicación proporciona las credenciales de la cuenta de servicio predeterminada de App Engine, que está autorizada para acceder a las bases de datos del mismo proyecto que tu aplicación.

Si se cumple alguna de las siguientes condiciones, debes usar una técnica de autenticación alternativa que proporcione credenciales de forma explícita:

  • Tu aplicación y la base de datos de Memorystore están en proyectos diferentes.Google Cloud

  • Has cambiado los roles asignados a la cuenta de servicio predeterminada de App Engine.

Para obtener información sobre técnicas de autenticación alternativas, consulta el artículo Configurar la autenticación para aplicaciones de producción de servidor a servidor.

Información general sobre el uso de Memorystore

Para usar Memorystore en tu aplicación, sigue estos pasos:

  1. Configura Memorystore para Redis. Para ello, debes crear una instancia de Redis en Memorystore y crear un acceso a VPC sin servidor que tu aplicación utilice para comunicarse con la instancia de Redis. El orden de creación de estas dos entidades independientes no es estricto y se pueden configurar en cualquier orden. Las instrucciones de esta guía muestran cómo configurar primero el acceso a VPC sin servidor.

  2. Instala una biblioteca de cliente para Redis y usa comandos de Redis para almacenar datos en caché.

    Memorystore para Redis es compatible con cualquier biblioteca de cliente de Redis. En esta guía se describe cómo usar la biblioteca de cliente Jedis para enviar comandos de Redis desde tu aplicación. Para obtener más información sobre cómo usar Jedis, consulta la wiki de Jedis.

  3. Prueba las actualizaciones.

  4. Despliega tu aplicación en App Engine.

Configurar Memorystore para Redis

Para configurar Memorystore para Redis, sigue estos pasos:

  1. Conecta tu aplicación de App Engine a una red de VPC. Tu aplicación solo puede comunicarse con Memorystore a través de un conector VPC.

    Asegúrate de añadir la información de conexión de la VPC al archivo app.yaml tal como se describe en el artículo Configurar la aplicación para que use el conector.

  2. Anota la dirección IP y el número de puerto de la instancia de Redis que crees. Usará esta información cuando cree un cliente de Redis en su código.

  3. Crea una instancia de Redis en Memorystore.

    Cuando se te pida que selecciones una región para tu instancia de Redis, elige la misma región en la que se encuentra tu aplicación de App Engine.

Instalar dependencias

Para que la biblioteca de cliente de Jedis esté disponible para tu aplicación cuando se ejecute en App Engine, añade la biblioteca a las dependencias de tu aplicación. Por ejemplo, si usas Maven, añade la siguiente dependencia a tu archivo pom.xml:
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>5.1.0</version>
</dependency>

Crear un cliente de Redis

Para interactuar con una base de datos Redis, tu código debe crear un cliente Redis para gestionar la conexión con tu base de datos Redis. En las siguientes secciones se describe cómo crear un cliente de Redis con la biblioteca de cliente Jedis.

Especificar variables de entorno

La biblioteca de cliente Jedis usa dos variables de entorno para crear la URL de tu base de datos Redis:

  • Variable para identificar la dirección IP de la base de datos Redis que has creado en Memorystore.
  • Variable para identificar el número de puerto de la base de datos Redis que has creado en Memorystore.

Te recomendamos que definas estas variables en el archivo app.yaml de tu aplicación en lugar de hacerlo directamente en el código. De esta forma, te resultará más fácil ejecutar tu aplicación en diferentes entornos, como un entorno local y App Engine.

Por ejemplo, añade las siguientes líneas a tu archivo app.yaml:

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

Importar Jedis y crear el cliente

Cuando usas la biblioteca Jedis, te recomendamos que crees un JedisPool y, a continuación, utilices el pool para crear un cliente. Las siguientes líneas de código usan las variables de entorno redis.host y redis.port que has definido anteriormente para crear un grupo:


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
      }
    }
  }
}

Para crear un cliente a partir del grupo, usa el método JedisPool.getResource(). Por ejemplo:


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());
    }
  }
}

Usar comandos de Redis para almacenar y recuperar datos en la caché

Aunque la base de datos Redis de Memorystore admite la mayoría de los comandos de Redis, solo tienes que usar unos pocos para almacenar y recuperar datos de la caché. En la siguiente tabla se sugieren comandos de Redis que puedes usar para almacenar datos en caché. Para saber cómo llamar a estos comandos desde tu aplicación, consulta la documentación de tu biblioteca de cliente.

Tarea Comando de Redis
Crea una entrada en la caché de datos y
define un tiempo de vencimiento para la entrada.
SETNX
MSETNX
Recuperar datos de la caché GET
MGET
Reemplazar los valores de caché actuales SET
MSET
Incrementar o reducir valores numéricos de la caché INCR
INCRBY
DECR
DECRBY
Eliminar entradas de la caché DEL
UNLINK
Admite interacciones simultáneas con la caché Consulta los detalles sobre las transacciones de Redis.

Probar las actualizaciones

Cuando pruebes tu aplicación de forma local, te recomendamos que ejecutes una instancia local de Redis para evitar interactuar con datos de producción (Memorystore no proporciona un emulador). Para instalar y ejecutar Redis de forma local, sigue las instrucciones de la documentación de Redis. Ten en cuenta que, por el momento, no es posible ejecutar Redis de forma local en Windows.

Desplegar una aplicación

Una vez que tu aplicación se ejecute en el servidor de desarrollo local sin errores, haz lo siguiente:

  1. Prueba la aplicación en App Engine.

  2. Si la aplicación se ejecuta sin errores, usa la división del tráfico para aumentar lentamente el tráfico de la aplicación actualizada. Monitoriza la aplicación de cerca para detectar cualquier problema con la base de datos antes de dirigir más tráfico a la aplicación actualizada.