

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Procedimientos recomendados y estrategias de almacenamiento en caché de ElastiCache
<a name="BestPractices"></a>

A continuación, puede encontrar los procedimientos recomendados para Amazon ElastiCache. Si observa estos procedimientos, mejorará el rendimiento y la fiabilidad de su caché. 

**Topics**
+ [Prácticas recomendadas generales](WorkingWithRedis.md)
+ [Prácticas recomendadas para utilizar réplicas de lectura](ReadReplicas.md)
+ [Comandos de Valkey, Memcached y Redis OSS compatibles y restringidos](SupportedCommands.md)
+ [Configuración y límites de Valkey y Redis OSS](RedisConfiguration.md)
+ [Ejemplos de clientes de IPv6 para Valkey, Memcached y Redis OSS](network-type-best-practices.md)
+ [Prácticas recomendadas para clientes (Valkey y Redis OSS)](BestPractices.Clients.redis.md)
+ [Prácticas recomendadas para clientes (Memcached)](BestPractices.Clients.memcached.md)
+ [Clústeres de ElastiCache de doble pila compatibles con TLS](#network-type-configuring-tls-enabled-dual-stack)
+ [Administración de la memoria reservada para Valkey y Redis OSS](redis-memory-management.md)
+ [Prácticas recomendadas al trabajar con clústeres basados en nodos de Valkey y Redis OSS](BestPractices.SelfDesigned.md)
+ [Estrategias de almacenamiento en caché para Memcached](Strategies.md)

# Prácticas recomendadas generales
<a name="WorkingWithRedis"></a>

A continuación, encontrará información sobre las prácticas recomendadas para utilizar las interfaces OSS de Valkey, Memcached y Redis en ellas. ElastiCache
+ **Utilice configuraciones habilitadas para el modo de clúster: el modo de clúster habilitado** permite que la caché se escale horizontalmente para lograr un mayor almacenamiento y rendimiento que una configuración en modo de clúster deshabilitado. ElastiCache La configuración sin servidor solo está disponible en una configuración habilitada para el modo de clúster.
+ **Utilice conexiones de larga duración**: crear una nueva conexión es caro, y requiere tiempo y recursos de CPU de la memoria caché. Reutilice las conexiones siempre que sea posible (por ejemplo, mediante la agrupación de conexiones) para amortizar este coste a lo largo de muchos comandos.
+ **Lectura desde réplicas**: si utiliza réplicas de lectura ElastiCache sin servidor o ha aprovisionado réplicas de lectura (clústeres basados en nodos), dirija las lecturas a las réplicas para lograr una mejor escalabilidad y reducir la latencia. and/or Las lecturas desde réplicas acaban siendo coherehentes con la principal.

  En un clúster basado en nodos, evite dirigir las solicitudes de lectura a una única réplica de lectura, ya que es posible que las lecturas no estén disponibles temporalmente si el nodo falla. Configure su cliente para que dirija las solicitudes de lectura al menos a dos réplicas de lectura, o dirija las lecturas a una única réplica y a la principal.

  En los sistemas ElastiCache sin servidor, la lectura desde el puerto de réplica (6380) dirigirá las lecturas a la zona de disponibilidad local del cliente siempre que sea posible, lo que reducirá la latencia de recuperación. Cuando se produzca un error, volverá automáticamente a los demás nodos.
+ **Evite los comandos costosos**: evite ejecutar operaciones computacionales e I/O intensivas, como los comandos y. `KEYS` `SMEMBERS` Recomendamos este enfoque porque estas operaciones aumentan la carga en el clúster e influyen en el rendimiento del clúster. En su lugar, utilice los comandos `SCAN` y `SSCAN`.
+ **Seguir las prácticas recomendadas de Lua**: evite los scripts Lua de ejecución prolongada y siempre declare por adelantado las claves que utiliza en los scripts Lua. Recomendamos este enfoque para determinar que el script Lua no está utilizando comandos de ranura cruzada. Asegúrese de que las claves utilizadas en scripts Lua pertenezcan a la misma ranura.
+ **Utilice sharded pub/sub**: cuando utilice Valkey o Redis OSS para soportar pub/sub cargas de trabajo con un alto rendimiento, le recomendamos que utilice [sharded pub/sub](https://valkey.io/topics/pubsub/) (disponible con Valkey y con Redis OSS 7 o posterior). Los clústeres tradicionales habilitados para pub/sub el modo clúster transmiten mensajes a todos los nodos del clúster, lo que puede resultar en un nivel alto. `EngineCPUUtilization` Tenga en cuenta que en los comandos ElastiCache tradicionales sin servidor. pub/sub commands internally use sharded pub/sub

**Topics**

# Prácticas recomendadas para utilizar réplicas de lectura
<a name="ReadReplicas"></a>

Muchas aplicaciones, como los almacenes de sesiones, las tablas de clasificación y los motores de recomendaciones, requieren una alta disponibilidad y gestionan muchas más operaciones de lectura que de escritura. A menudo, estas aplicaciones toleran datos ligeramente obsoletos (coherencia final), lo que significa que se acepta que distintos usuarios vean momentáneamente versiones ligeramente diferentes de los mismos datos. Por ejemplo:
+ Los resultados de las consultas en caché suelen tolerar datos ligeramente obsoletos, especialmente en el caso de los patrones de reserva de caché, en los que el origen de la verdad es externo.
+ En una tabla de clasificación de videojuegos, un retraso de unos segundos en la actualización de las puntuaciones no suele afectar de forma significativa a la experiencia del usuario.
+ En el caso de los almacenes de sesiones, algunos retrasos leves en la propagación de los datos de sesión entre las réplicas rara vez afectan a la funcionalidad de la aplicación.
+ Los motores de recomendaciones suelen utilizar el análisis de datos históricos, por lo que la coherencia en tiempo real es menos importante.

La coherencia final implica que todos los nodos de réplica devolverán los mismos datos una vez que se complete el proceso de replicación, normalmente en cuestión de milisegundos. En estos casos de uso, implementar réplicas de lectura es una estrategia eficaz para reducir la latencia al leer desde la instancia. ElastiCache

El uso de réplicas de lectura en Amazon ElastiCache puede proporcionar importantes beneficios de rendimiento a través de:

**Mejora de la escalabilidad de lectura**
+ Distribuye las operaciones de lectura entre varios nodos de réplica.
+ Las descargas leen el tráfico del nodo principal.
+ Se reduce la latencia de lectura al atender las solicitudes de réplicas más cercanas geográficamente.

**Rendimiento optimizado del nodo principal**
+ Asigna los recursos del nodo principal a las operaciones de escritura.
+ Reduce la sobrecarga de la conexión en el nodo principal.
+ Mejora el rendimiento de escritura y mantiene mejores tiempos de respuesta durante los períodos de más tráfico.

## Uso de Read from Replica en Serverless ElastiCache
<a name="ReadReplicas.serverless"></a>

ElastiCache serverless proporciona dos puntos finales diferentes para diferentes requisitos de coherencia. Los dos puntos de conexión utilizan el mismo nombre de DNS, pero puertos diferentes. Para utilizar el read-from-replica puerto, debe autorizar el acceso a ambos puertos desde la aplicación cliente mediante la [configuración de los grupos de seguridad y las listas de control de acceso a la red de su VPC](set-up.md#elasticache-install-grant-access-VPN).

**Punto de conexión del principal (puerto 6379)**
+ Se utiliza para operaciones que requieren coherencia inmediata.
+ Garantiza la lectura de la mayoría de los datos up-to-date
+ Es ideal para transacciones y operaciones de escritura críticas.
+ Es necesario para las operaciones de escritura.
+ Ejemplo: `test-12345.serverless.use1.cache.amazonaws.com:6379`

**Punto de conexión con latencia optimizada (puerto 6380)**
+ Optimizado para operaciones de lectura que pueden tolerar la coherencia final.
+ Cuando es posible, la ElastiCache tecnología sin servidor enruta automáticamente las solicitudes de lectura al nodo de réplica en la zona de disponibilidad local del cliente. Esta optimización reduce la latencia al evitar la latencia de red adicional que se produce al recuperar datos de un nodo en una zona de disponibilidad diferente.
+ ElastiCache serverless selecciona automáticamente los nodos disponibles en otras zonas si un nodo local no está disponible
+ Ejemplo: `test-12345.serverless.use1.cache.amazonaws.com:6380`
+ Los clientes como Glide y Lettuce detectarán automáticamente las lecturas y las enrutarán hacia el punto de conexión con latencia optimizada si está configurada la lectura desde réplicas. Si su cliente no permite configurar el enrutamiento (por ejemplo, valkey-java y versiones anteriores de jedis), debe definir la configuración correcta de puerto y cliente para la lectura desde réplicas.

## Conexión para leer réplicas en ElastiCache Serverless: Valkey y Glide
<a name="ReadReplicas.connecting-primary"></a>

En el siguiente fragmento de código, se muestra cómo configurar la lectura desde una réplica para ElastiCache Serverless en la biblioteca Valkey glide. No necesita especificar el puerto para la lectura desde réplicas, pero sí configurar el parámetro de enrutamiento `ReadFrom.PREFER_REPLICA`.

```
package glide.examples;

import glide.api.GlideClusterClient;
import glide.api.logging.Logger;
import glide.api.models.configuration.GlideClusterClientConfiguration;
import glide.api.models.configuration.NodeAddress;
import glide.api.models.exceptions.ClosingException;
import glide.api.models.exceptions.ConnectionException;
import glide.api.models.exceptions.TimeoutException;
import glide.api.models.configuration.ReadFrom;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class ClusterExample {

    public static void main(String[] args) {
        // Set logger configuration
        Logger.setLoggerConfig(Logger.Level.INFO);

        GlideClusterClient client = null;

        try {
            System.out.println("Connecting to Valkey Glide...");

            // Configure the Glide Client
            GlideClusterClientConfiguration config = GlideClusterClientConfiguration.builder()
                .address(NodeAddress.builder()
                    .host("your-endpoint")
                    .port(6379)
                    .build())
                .useTLS(true)
                .readFrom(ReadFrom.PREFER_REPLICA)
                .build();

            // Create the GlideClusterClient
            client = GlideClusterClient.createClient(config).get();
            System.out.println("Connected successfully.");

            // Perform SET operation
            CompletableFuture<String> setResponse = client.set("key", "value");
            System.out.println("Set key 'key' to 'value': " + setResponse.get());

            // Perform GET operation
            CompletableFuture<String> getResponse = client.get("key");
            System.out.println("Get response for 'key': " + getResponse.get());

            // Perform PING operation
            CompletableFuture<String> pingResponse = client.ping();
            System.out.println("PING response: " + pingResponse.get());

        } catch (ClosingException | ConnectionException | TimeoutException | ExecutionException e) {
            System.err.println("An exception occurred: ");
            e.printStackTrace();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // Close the client connection
            if (client != null) {
                try {
                    client.close();
                    System.out.println("Client connection closed.");
                } catch (ClosingException | ExecutionException e) {
                    System.err.println("Error closing client: " + e.getMessage());
                }
            }
        }
    }
}
```

# Comandos de Valkey, Memcached y Redis OSS compatibles y restringidos
<a name="SupportedCommands"></a>

## Comandos de Valkey y Redis OSS compatibles
<a name="SupportedCommandsRedis"></a>

**Comandos de Valkey y Redis OSS compatibles**

Las cachés sin servidor admiten los siguientes comandos de Valkey y Redis OSS. Además de estos comandos, estos [Comandos de Valkey y Redis OSS compatiblesComandos JSON](json-list-commands.md) también son compatibles.

Para obtener más información sobre los comandos del filtro de Bloom, consulte [Comandos de filtros de Bloom](BloomFilters.md#SupportedCommandsBloom)

**Comandos de mapa de bits**
+ `BITCOUNT`

  Cuenta el número de bits establecidos (recuento de integrantes) de una cadena.

  [Más información](https://valkey.io/commands/bitcount/)
+ `BITFIELD`

  Realiza operaciones arbitrarias con enteros de campos de bits en cadenas.

  [Más información](https://valkey.io/commands/bitfield/)
+ `BITFIELD_RO`

  Realiza operaciones arbitrarias de solo lectura con enteros de campos de bits en cadenas.

  [Más información](https://valkey.io/commands/bitfield_ro/)
+ `BITOP`

  Realiza operaciones bit a bit en varias cadenas y almacena el resultado.

  [Más información](https://valkey.io/commands/bitop/)
+ `BITPOS`

  Busca el primer bit activo (1) o inactivo (0) en una cadena.

  [Más información](https://valkey.io/commands/bitpos/)
+ `GETBIT`

  Devuelve el valor de un bit en una posición determinada.

  [Más información](https://valkey.io/commands/getbit/)
+ `SETBIT`

  Pone a 1 o 0 el bit de una posición determinada en el valor de la cadena. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/setbit/)

**Comandos de administración de clústeres**
+ `CLUSTER COUNTKEYSINSLOT`

  Devuelve el número de claves en un slot hash.

  [Más información](https://valkey.io/commands/cluster-countkeysinslot/)
+ `CLUSTER GETKEYSINSLOT`

  Devuelve los nombres de las claves de un slot hash.

  [Más información](https://valkey.io/commands/cluster-getkeysinslot/)
+ `CLUSTER INFO`

  Devuelve información sobre el estado de un nodo. En una caché sin servidor, devuelve el estado de la única “partición” virtual expuesta al cliente.

  [Más información](https://valkey.io/commands/cluster-info/)
+ `CLUSTER KEYSLOT`

  Devuelve el slot hash de una clave.

  [Más información](https://valkey.io/commands/cluster-keyslot/)
+ `CLUSTER MYID`

  Devuelve el ID de un nodo. En una caché sin servidor, devuelve el estado de la única “partición” virtual expuesta al cliente. 

  [Más información](https://valkey.io/commands/cluster-myid/)
+ `CLUSTER NODES`

  Devuelve la configuración del clúster de un nodo. En una caché sin servidor, devuelve el estado de la única “partición” virtual expuesta al cliente. 

  [Más información](https://valkey.io/commands/cluster-nodes/)
+ `CLUSTER REPLICAS`

  Muestra los nodos de réplica de un nodo maestro. En una caché sin servidor, devuelve el estado de la única “partición” virtual expuesta al cliente. 

  [Más información](https://valkey.io/commands/cluster-replicas/)
+ `CLUSTER SHARDS`

  Devuelve la asignación de slots del clúster a las particiones. En una caché sin servidor, devuelve el estado de la única “partición” virtual expuesta al cliente. 

  [Más información](https://valkey.io/commands/cluster-shards/)
+ `CLUSTER SLOTS`

  Devuelve la asignación de slots del clúster a los nodos. En una caché sin servidor, devuelve el estado de la única “partición” virtual expuesta al cliente. 

  [Más información](https://valkey.io/commands/cluster-slots/)
+ `CLUSTER SLOT-STATS`

  Permite realizar un seguimiento de las métricas por ranura del recuento de claves, el uso de la CPU, los bytes de red entrantes y los bytes de red salientes. 

  [Más información](https://valkey.io/commands/cluster-slot-stats/)
+ `READONLY`

  Habilita las consultas de solo lectura para una conexión a un nodo de réplica de un clúster de Valkey o Redis OSS.

  [Más información](https://valkey.io/commands/readonly/)
+ `READWRITE`

  Habilita las consultas de lectura-escritura para una conexión a un nodo de réplica de un clúster de Valkey o Redis OSS.

  [Más información](https://valkey.io/commands/readwrite/)
+ `SCRIPT SHOW`

  Devuelve el código fuente original de un script en la caché de scripts.

  [Más información](https://valkey.io/commands/script-show/)

**Comandos de administración de conexiones**
+ `AUTH`

  Autentica la conexión.

  [Más información](https://valkey.io/commands/auth/)
+ `CLIENT GETNAME`

  Devuelve el nombre de la conexión.

  [Más información](https://valkey.io/commands/client-getname/)
+ `CLIENT REPLY`

  Le dice al servidor si debe responder a los comandos.

  [Más información](https://valkey.io/commands/client-reply/)
+ `CLIENT SETNAME`

  Establece el nombre de la conexión.

  [Más información](https://valkey.io/commands/client-setname/)
+ `ECHO`

  Devuelve la cadena determinada.

  [Más información](https://valkey.io/commands/echo/)
+ `HELLO`

  Protocolos de enlace con el servidor de Valkey o Redis OSS.

  [Más información](https://valkey.io/commands/hello/)
+ `PING`

  Devuelve la respuesta de vivacidad del servidor.

  [Más información](https://valkey.io/commands/ping/)
+ `QUIT`

  Cierra la conexión.

  [Más información](https://valkey.io/commands/quit/)
+ `RESET`

  Restablece la conexión.

  [Más información](https://valkey.io/commands/reset/)
+ `SELECT`

  Cambia la base de datos seleccionada.

  [Más información](https://valkey.io/commands/select/)

**Comandos genéricos**
+ `COPY`

  Copia el valor de una clave en una nueva clave.

  [Más información](https://valkey.io/commands/copy/)
+ `DEL`

  Elimina una o varias claves.

  [Más información](https://valkey.io/commands/del/)
+ `DUMP`

  Devuelve una representación serializada del valor almacenado en una clave.

  [Más información](https://valkey.io/commands/dump/)
+ `EXISTS`

  Determina si hay una o más claves.

  [Más información](https://valkey.io/commands/exists/)
+ `EXPIRE`

  Establece el tiempo de caducidad de una clave en segundos.

  [Más información](https://valkey.io/commands/expire/)
+ `EXPIREAT`

  Establece el tiempo de caducidad de una clave en una marca de tiempo de Unix.

  [Más información](https://valkey.io/commands/expireat/)
+ `EXPIRETIME`

  Devuelve el tiempo de caducidad de una clave como una marca de tiempo de Unix.

  [Más información](https://valkey.io/commands/expiretime/)
+ `PERSIST`

  Elimina el tiempo de caducidad de una clave.

  [Más información](https://valkey.io/commands/persist/)
+ `PEXPIRE`

  Establece el tiempo de caducidad de una clave en segundos.

  [Más información](https://valkey.io/commands/pexpire/)
+ `PEXPIREAT`

  Establece el tiempo de caducidad de una clave como una marca de milisegundos de Unix.

  [Más información](https://valkey.io/commands/pexpireat/)
+ `PEXPIRETIME`

  Devuelve el tiempo de caducidad de una clave como una marca de tiempo de milisegundos de Unix.

  [Más información](https://valkey.io/commands/pexpiretime/)
+ `PTTL`

  Devuelve el tiempo de caducidad de una clave en milisegundos.

  [Más información](https://valkey.io/commands/pttl/)
+ `RANDOMKEY`

  Devuelve un nombre de clave aleatorio de la base de datos.

  [Más información](https://valkey.io/commands/randomkey/)
+ `RENAME`

  Cambia el nombre de una clave y sobrescribe el destino.

  [Más información](https://valkey.io/commands/rename/)
+ `RENAMENX`

  Cambia el nombre de una clave solo cuando el nombre de la clave de destino no existe.

  [Más información](https://valkey.io/commands/renamenx/)
+ `RESTORE`

  Crea una clave a partir de la representación serializada de un valor.

  [Más información](https://valkey.io/commands/restore/)
+ `SCAN`

  Hace una iteración sobre los nombres de claves en la base de datos.

  [Más información](https://valkey.io/commands/scan/)
+ `SORT`

  Ordena los elementos de una lista, un conjunto o un conjunto ordenado y, opcionalmente, almacena el resultado.

  [Más información](https://valkey.io/commands/sort/)
+ `SORT_RO`

  Devuelve los elementos ordenados de una lista, un conjunto o un conjunto ordenado.

  [Más información](https://valkey.io/commands/sort_ro/)
+ `TOUCH`

  Devuelve el número de claves existentes entre las claves especificadas tras actualizar la hora en la que se accedió a ellas por última vez.

  [Más información](https://valkey.io/commands/touch/)
+ `TTL`

  Devuelve el tiempo de caducidad de una clave en segundos.

  [Más información](https://valkey.io/commands/ttl/)
+ `TYPE`

  Determina el tipo de valor almacenado en una clave.

  [Más información](https://valkey.io/commands/type/)
+ `UNLINK`

  Elimina de forma asíncrona una o más claves.

  [Más información](https://valkey.io/commands/unlink/)

**Comandos geoespaciales**
+ `GEOADD`

  Añade uno o varios miembros a un índice geoespacial. La clave se crea si no existe.

  [Más información](https://valkey.io/commands/geoadd/)
+ `GEODIST`

  Devuelve la distancia entre dos miembros de un índice geoespacial.

  [Más información](https://valkey.io/commands/geodist/)
+ `GEOHASH`

  Devuelve los miembros de un índice geoespacial como cadenas geohash.

  [Más información](https://valkey.io/commands/geohash/)
+ `GEOPOS`

  Devuelve la longitud y la latitud de los miembros de un índice geoespacial.

  [Más información](https://valkey.io/commands/geopos/)
+ `GEORADIUS`

  Consulta un índice geoespacial para ver los miembros que se encuentran a una distancia de una coordenada y, si lo desea, almacena el resultado.

  [Más información](https://valkey.io/commands/georadius/)
+ `GEORADIUS_RO`

  Devuelve los miembros de un índice geoespacial que se encuentran a una determinada distancia de una coordenada.

  [Más información](https://valkey.io/commands/georadius_ro/)
+ `GEORADIUSBYMEMBER`

  Consulta un índice geoespacial para ver los miembros que se encuentran a una determinada distancia de un miembro y, si lo desea, almacena el resultado.

  [Más información](https://valkey.io/commands/georadiusbymember/)
+ `GEORADIUSBYMEMBER_RO`

  Devuelve los miembros de un índice geoespacial que se encuentran a una determinada distancia de un miembro.

  [Más información](https://valkey.io/commands/georadiusbymember_ro/)
+ `GEOSEARCH`

  Consulta en un índice geoespacial a los miembros que se encuentran dentro del área de un cuadro o un círculo.

  [Más información](https://valkey.io/commands/geosearch/)
+ `GEOSEARCHSTORE`

  Consulta en un índice geoespacial a los miembros que se encuentran dentro del área de un cuadro o un círculo y, opcionalmente, almacena el resultado.

  [Más información](https://valkey.io/commands/geosearchstore/)

**Comandos hash**
+ `HDEL`

  Elimina uno o más campos (y sus valores) de un hash. Elimina el hash si no queda ningún campo.

  [Más información](https://valkey.io/commands/hdel/)
+ `HEXISTS`

  Determina si hay un campo en un hash.

  [Más información](https://valkey.io/commands/hexists/)
+ `HGET`

  Devuelve el valor de un campo en un hash.

  [Más información](https://valkey.io/commands/hget/)
+ `HGETALL`

  Devuelve todos los campos y valores de un hash.

  [Más información](https://valkey.io/commands/hgetall/)
+ `HINCRBY`

  Incrementa el valor entero de un campo en un hash por un número determinado. Usa 0 como valor inicial si el campo no existe.

  [Más información](https://valkey.io/commands/hincrby/)
+ `HINCRBYFLOAT`

  Incrementa el valor de punto flotante de un campo por un número determinado. Usa 0 como valor inicial si el campo no existe.

  [Más información](https://valkey.io/commands/hincrbyfloat/)
+ `HKEYS`

  Devuelve todos los campos de un hash.

  [Más información](https://valkey.io/commands/hkeys/)
+ `HLEN`

  Devuelve el número de campos en un hash.

  [Más información](https://valkey.io/commands/hlen/)
+ `HMGET`

  Devuelve todos los campos y valores en un hash.

  [Más información](https://valkey.io/commands/hmget/)
+ `HMSET`

  Establece los valores de varios campos.

  [Más información](https://valkey.io/commands/hmset/)
+ `HRANDFIELD`

  Devuelve uno o más campos aleatorios de un hash.

  [Más información](https://valkey.io/commands/hrandfield/)
+ `HSCAN`

  Hace iteraciones sobre los campos y valores de un hash.

  [Más información](https://valkey.io/commands/hscan/)
+ `HSET`

  Crea o modifica el valor de un campo en un hash.

  [Más información](https://valkey.io/commands/hset/)
+ `HSETNX`

  Establece el valor de un campo en un hash solo cuando el campo no existe.

  [Más información](https://valkey.io/commands/hsetnx/)
+ `HSTRLEN`

  Devuelve la longitud del valor de un campo.

  [Más información](https://valkey.io/commands/hstrlen/)
+ `HVALS`

  Devuelve todos valores de un hash.

  [Más información](https://valkey.io/commands/hvals/)

**HyperLogLog Comandos**
+ `PFADD`

  Añade elementos a una HyperLogLog clave. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/pfadd/)
+ `PFCOUNT`

  Devuelve la cardinalidad aproximada de los conjuntos observados por las HyperLogLog claves.

  [Más información](https://valkey.io/commands/pfcount/)
+ `PFMERGE`

  Combina uno o más HyperLogLog valores en una sola clave.

  [Más información](https://valkey.io/commands/pfmerge/)

**Comandos de listas**
+ `BLMOVE`

  Saca un elemento de una lista, lo coloca en otra y lo devuelve. De lo contrario, bloquea hasta que haya un elemento disponible. Elimina la lista si se ha movido el último elemento.

  [Más información](https://valkey.io/commands/blmove/)
+ `BLMPOP`

  Saca el primer elemento de una de las múltiples listas. De lo contrario, bloquea hasta que haya un elemento disponible. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/blmpop/)
+ `BLPOP`

  Elimina y devuelve el primer elemento de una lista. De lo contrario, bloquea hasta que haya un elemento disponible. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/blpop/)
+ `BRPOP`

  Elimina y devuelve el último elemento de una lista. De lo contrario, bloquea hasta que haya un elemento disponible. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/brpop/)
+ `BRPOPLPUSH`

  Saca un elemento de una lista, lo coloca en otra y lo devuelve. De lo contrario, bloquea hasta que haya un elemento disponible. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/brpoplpush/)
+ `LINDEX`

  Devuelve un elemento de una lista por su índice.

  [Más información](https://valkey.io/commands/lindex/)
+ `LINSERT`

  Inserta un elemento antes o después de otro elemento de una lista.

  [Más información](https://valkey.io/commands/linsert/)
+ `LLEN`

  Devuelve la longitud de una lista.

  [Más información](https://valkey.io/commands/llen/)
+ `LMOVE`

  Devuelve un elemento después de sacarlo de una lista y pasarlo a otra. Elimina la lista si se ha movido el último elemento.

  [Más información](https://valkey.io/commands/lmove/)
+ `LMPOP`

  Devuelve varios elementos de una lista después de eliminarlos. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/lmpop/)
+ `LPOP`

  Devuelve los primeros elementos de una lista después de eliminarla. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/lpop/)
+ `LPOS`

  Devuelve el índice de los elementos coincidentes de una lista.

  [Más información](https://valkey.io/commands/lpos/)
+ `LPUSH`

  Antepone uno o más elementos a una lista. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/lpush/)
+ `LPUSHX`

  Antepone uno o más elementos a una lista solo cuando la lista existe.

  [Más información](https://valkey.io/commands/lpushx/)
+ `LRANGE`

  Devuelve un rango de elementos de una lista.

  [Más información](https://valkey.io/commands/lrange/)
+ `LREM`

  Elimina elementos de una lista. Elimina la lista si se ha eliminado el último elemento.

  [Más información](https://valkey.io/commands/lrem/)
+ `LSET`

  Establece el valor de un elemento de una lista por su índice.

  [Más información](https://valkey.io/commands/lset/)
+ `LTRIM`

  Elimina los elementos de ambos extremos de la lista. Elimina la lista si se han recortado todos los elementos.

  [Más información](https://valkey.io/commands/ltrim/)
+ `RPOP`

  Elimina y devuelve los últimos elementos de una lista. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/rpop/)
+ `RPOPLPUSH`

  Devuelve el último elemento de una lista después de extraerlo y colocarlo en otra lista. Elimina la lista si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/rpoplpush/)
+ `RPUSH`

  Antepone uno o más elementos a una lista. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/rpush/)
+ `RPUSHX`

  Añade un elemento a una lista solo cuando la lista existe.

  [Más información](https://valkey.io/commands/rpushx/)

**Comandos Pub/Sub**

**nota**  
Los comandos PUBSUB utilizan internamente PUBSUB con particiones, por lo que los nombres de los canales se mezclarán.
+ `PUBLISH`

  Publica un mensaje en un canal.

  [Más información](https://valkey.io/commands/publish/)
+ `PUBSUB CHANNELS`

  Devuelve los canales activos.

  [Más información](https://valkey.io/commands/pubsub-channels/)
+ `PUBSUB NUMSUB`

  Devuelve el recuento de suscriptores a los canales.

  [Más información](https://valkey.io/commands/pubsub-numsub/)
+ `PUBSUB SHARDCHANNELS`

  Devuelve los canales de particiones activos.

  [Más información](https://valkey.io/commands/pubsub-shardchannels/)
+ `PUBSUB SHARDNUMSUB`

  Devuelve el recuento de suscriptores a los canales de particiones.

  [Más información](https://valkey.io/commands/pubsub-shardnumsub/)
+ `SPUBLISH`

  Publicación de un mensaje en un canal de partición

  [Más información](https://valkey.io/commands/spublish/)
+ `SSUBSCRIBE`

  Escucha los mensajes publicados en los canales de particiones.

  [Más información](https://valkey.io/commands/ssubscribe/)
+ `SUBSCRIBE`

  Escucha los mensajes publicados en los canales.

  [Más información](https://valkey.io/commands/subscribe/)
+ `SUNSUBSCRIBE`

  Deja de escuchar los mensajes publicados en los canales de particiones.

  [Más información](https://valkey.io/commands/sunsubscribe/)
+ `UNSUBSCRIBE`

  Deja de escuchar los mensajes publicados en los canales.

  [Más información](https://valkey.io/commands/unsubscribe/)

**Comandos de scripts**
+ `EVAL`

  Ejecuta un script de Lua en el lado del servidor.

  [Más información](https://valkey.io/commands/eval/)
+ `EVAL_RO`

  Ejecuta un script de Lua de solo lectura en el lado del servidor.

  [Más información](https://valkey.io/commands/eval_ro/)
+ `EVALSHA`

  Ejecuta un script de Lua del lado del servidor por resumen. SHA1 

  [Más información](https://valkey.io/commands/evalsha/)
+ `EVALSHA_RO`

  Ejecuta un script de Lua del lado del servidor de solo lectura mediante resumen. SHA1 

  [Más información](https://valkey.io/commands/evalsha_ro/)
+ `SCRIPT EXISTS`

  Determina si hay scripts de Lua del lado del servidor en la caché de scripts.

  [Más información](https://valkey.io/commands/script-exists/)
+ `SCRIPT FLUSH`

  Actualmente no está en funcionamiento y la caché del script está administrada por el servicio. 

  [Más información](https://valkey.io/commands/script-flush/)
+ `SCRIPT LOAD`

  Carga un script de Lua del lado del servidor en la caché de scripts.

  [Más información](https://valkey.io/commands/script-load/)

**Comandos de administración de servidores**

**nota**  
Cuando se utilizan ElastiCache clústeres basados en nodos para Valkey y Redis OSS, el cliente debe enviar los comandos de vaciado a todos los servidores principales para vaciar todas las claves. ElastiCache Serverless para Valkey y Redis OSS funciona de forma diferente, ya que abstrae la topología del clúster subyacente. El resultado es que, en ElastiCache Serverless, `FLUSHDB` los `FLUSHALL` comandos siempre vaciarán todas las claves del clúster. Por este motivo, los comandos de vaciado no se pueden incluir en una transacción sin servidor. 
+ `ACL CAT`

  Muestra las categorías de ACL o los comandos dentro de una categoría.

  [Más información](https://valkey.io/commands/acl-cat/)
+ `ACL GENPASS`

  Genera una contraseña segura y pseudoaleatoria que se puede utilizar para identificar a los usuarios de ACL.

  [Más información](https://valkey.io/commands/acl-genpass/)
+ `ACL GETUSER`

  Muestra las reglas de ACL de un usuario.

  [Más información](https://valkey.io/commands/acl-getuser/)
+ `ACL LIST`

  Coloca las reglas vigentes en formato de archivo ACL.

  [Más información](https://valkey.io/commands/acl-list/)
+ `ACL USERS`

  Muestra todos los usuarios de ACL.

  [Más información](https://valkey.io/commands/acl-users/)
+ `ACL WHOAMI`

  Devuelve el nombre de usuario autenticado de la conexión actual.

  [Más información](https://valkey.io/commands/acl-whoami/)
+ `DBSIZE`

  Devuelve el número de claves de la base de datos actualmente seleccionada. No se garantiza que esta operación sea integral en todos los slots.

  [Más información](https://valkey.io/commands/dbsize/)
+ `COMMAND`

  Devuelve información detallada sobre todos los comandos.

  [Más información](https://valkey.io/commands/command/)
+ `COMMAND COUNT`

  Devuelve un recuento de comandos.

  [Más información](https://valkey.io/commands/command-count/)
+ `COMMAND DOCS`

  Devuelve información documental sobre un comando, varios o todos ellos.

  [Más información](https://valkey.io/commands/command-docs/)
+ `COMMAND GETKEYS`

  Extrae los nombres de claves de un comando arbitrario.

  [Más información](https://valkey.io/commands/command-getkeys/)
+ `COMMAND GETKEYSANDFLAGS`

  Extrae los nombres de claves y los indicadores de acceso de un comando arbitrario.

  [Más información](https://valkey.io/commands/command-getkeysandflags/)
+ `COMMAND INFO`

  Devuelve información sobre un comando, varios o todos ellos.

  [Más información](https://valkey.io/commands/command-info/)
+ `COMMAND LIST`

  Devuelve una lista de nombres de comandos.

  [Más información](https://valkey.io/commands/command-list/)
+ `COMMANDLOG`

  Contenedor para los comandos del registro de comandos.

  [Más información](https://valkey.io/commands/commandlog/)
+ `COMMANDLOG GET`

  Devuelve las entradas del registro de comandos especificado.

  [Más información](https://valkey.io/commands/commandlog-get/)
+ `COMMANDLOG HELP`

  Muestra texto útil sobre los distintos subcomandos.

  [Más información](https://valkey.io/commands/commandlog-help/)
+ `COMMANDLOG LEN`

  Devuelve el número de entradas del tipo de registro de comandos especificado.

  [Más información](https://valkey.io/commands/commandlog-len/)
+ `COMMANDLOG RESET`

  Borra todas las entradas del tipo de registro de comandos especificado.

  [Más información](https://valkey.io/commands/commandlog-reset/)
+ `FLUSHALL`

  Elimina todas las claves de todas las bases de datos. No se garantiza que esta operación sea integral en todos los slots. 

  [Más información](https://valkey.io/commands/flushall/)
+ `FLUSHDB`

  Elimina todas las claves de la base de datos actual. No se garantiza que esta operación sea integral en todos los slots.

  [Más información](https://valkey.io/commands/flushdb/)
+ `INFO`

  Devuelve información y estadísticas sobre el servidor.

  [Más información](https://valkey.io/commands/info/)
+ `LOLWUT`

  Muestra expresiones de arte computacional y la versión de Valkey o Redis OSS.

  [Más información](https://valkey.io/commands/lolwut/)
+ `ROLE`

  Devuelve la función de réplica.

  [Más información](https://valkey.io/commands/role/)
+ `TIME`

  Devuelve la hora del servidor.

  [Más información](https://valkey.io/commands/time/)

**Comandos para conjuntos**
+ `SADD`

  Añade uno o varios miembros a un conjunto. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/sadd/)
+ `SCARD`

  Devuelve el número de miembros de un conjunto.

  [Más información](https://valkey.io/commands/scard/)
+ `SDIFF`

  Devuelve la diferencia de varios conjuntos.

  [Más información](https://valkey.io/commands/sdiff/)
+ `SDIFFSTORE`

  Almacena la diferencia de varios conjuntos en una clave.

  [Más información](https://valkey.io/commands/sdiffstore/)
+ `SINTER`

  Devuelve la intersección de varios conjuntos.

  [Más información](https://valkey.io/commands/sinter/)
+ `SINTERCARD`

  Devuelve el número de miembros de la intersección de varios conjuntos.

  [Más información](https://valkey.io/commands/sintercard/)
+ `SINTERSTORE`

  Almacena la intersección de varios conjuntos en una clave.

  [Más información](https://valkey.io/commands/sinterstore/)
+ `SISMEMBER`

  Determina si un miembro pertenece a un conjunto.

  [Más información](https://valkey.io/commands/sismember/)
+ `SMEMBERS`

  Devuelve todos los miembros de un conjunto.

  [Más información](https://valkey.io/commands/smembers/)
+ `SMISMEMBER`

  Determina si varios miembros pertenecen a un conjunto.

  [Más información](https://valkey.io/commands/smismember/)
+ `SMOVE`

  Mueve un miembro de un conjunto a otro.

  [Más información](https://valkey.io/commands/smove/)
+ `SPOP`

  Devuelve uno o más miembros aleatorios de un conjunto después de eliminarlos. Elimina la lista si se ha sacado el último miembro.

  [Más información](https://valkey.io/commands/spop/)
+ `SRANDMEMBER`

  Obtiene uno o varios miembros aleatorios de un conjunto

  [Más información](https://valkey.io/commands/srandmember/)
+ `SREM`

  Elimina uno o varios miembros de un conjunto. Elimina el conjunto si se ha extraído el último miembro.

  [Más información](https://valkey.io/commands/srem/)
+ `SSCAN`

  Hace iteraciones sobre los miembros de un conjunto.

  [Más información](https://valkey.io/commands/sscan/)
+ `SUNION`

  Devuelve la unión de varios conjuntos.

  [Más información](https://valkey.io/commands/sunion/)
+ `SUNIONSTORE`

  Almacena la unión de varios conjuntos en una clave.

  [Más información](https://valkey.io/commands/sunionstore/)

**Comandos de conjuntos ordenados**
+ `BZMPOP`

  Elimina y devuelve un miembro por puntuación desde uno o más conjuntos ordenados. De lo contrario, bloquea hasta que haya un miembro disponible. Elimina el conjunto ordenado si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/bzmpop/)
+ `BZPOPMAX`

  Elimina y devuelve el miembro con la puntuación más alta de uno o más conjuntos ordenados. De lo contrario, bloquea hasta que haya un miembro disponible. Elimina el conjunto ordenado si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/bzpopmax/)
+ `BZPOPMIN`

  Elimina y devuelve el miembro con la puntuación más baja de uno o más conjuntos ordenados. De lo contrario, bloquea hasta que haya un miembro disponible. Elimina el conjunto ordenado si se ha sacado el último elemento.

  [Más información](https://valkey.io/commands/bzpopmin/)
+ `ZADD`

  Añade uno o más miembros a un conjunto ordenado o actualiza sus puntuaciones. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/zadd/)
+ `ZCARD`

  Devuelve el número de miembros de un conjunto ordenado.

  [Más información](https://valkey.io/commands/zcard/)
+ `ZCOUNT`

  Devuelve el recuento de miembros de un conjunto ordenado con puntuaciones dentro de un rango determinado.

  [Más información](https://valkey.io/commands/zcount/)
+ `ZDIFF`

  Devuelve la diferencia entre varios conjuntos ordenados.

  [Más información](https://valkey.io/commands/zdiff/)
+ `ZDIFFSTORE`

  Almacena la diferencia de varios conjuntos en una clave.

  [Más información](https://valkey.io/commands/zdiffstore/)
+ `ZINCRBY`

  Incrementa la puntuación de un miembro en un conjunto ordenado.

  [Más información](https://valkey.io/commands/zincrby/)
+ `ZINTER`

  Devuelve la intersección de varios conjuntos ordenados.

  [Más información](https://valkey.io/commands/zinter/)
+ `ZINTERCARD`

  Devuelve el número de miembros de la intersección de varios conjuntos ordenados.

  [Más información](https://valkey.io/commands/zintercard/)
+ `ZINTERSTORE`

  Almacena la intersección de varios conjuntos ordenados en una clave.

  [Más información](https://valkey.io/commands/zinterstore/)
+ `ZLEXCOUNT`

  Devuelve el número de miembros de un conjunto ordenado dentro de un rango lexicográfico.

  [Más información](https://valkey.io/commands/zlexcount/)
+ `ZMPOP`

  Devuelve los miembros con la puntuación más alta o más baja de uno o más conjuntos ordenados después de eliminarlos. Elimina el conjunto ordenado si se ha sacado el último miembro.

  [Más información](https://valkey.io/commands/zmpop/)
+ `ZMSCORE`

  Devuelve la puntuación de uno o más miembros de un conjunto ordenado.

  [Más información](https://valkey.io/commands/zmscore/)
+ `ZPOPMAX`

  Devuelve los miembros con la puntuación más alta de un conjunto ordenado después de eliminarlos. Elimina el conjunto ordenado si se ha sacado el último miembro.

  [Más información](https://valkey.io/commands/zpopmax/)
+ `ZPOPMIN`

  Devuelve los miembros con la puntuación más baja de un conjunto ordenado después de eliminarlos. Elimina el conjunto ordenado si se ha sacado el último miembro.

  [Más información](https://valkey.io/commands/zpopmin/)
+ `ZRANDMEMBER`

  Devuelve uno o más miembros aleatorios de un conjunto ordenado.

  [Más información](https://valkey.io/commands/zrandmember/)
+ `ZRANGE`

  Devuelve los miembros de un conjunto ordenado dentro de un rango de índices.

  [Más información](https://valkey.io/commands/zrange/)
+ `ZRANGEBYLEX`

  Devuelve los miembros de un conjunto ordenado dentro de un rango lexicográfico.

  [Más información](https://valkey.io/commands/zrangebylex/)
+ `ZRANGEBYSCORE`

  Devuelve los miembros de un conjunto ordenado dentro de un rango de puntuaciones.

  [Más información](https://valkey.io/commands/zrangebyscore/)
+ `ZRANGESTORE`

  Almacena un rango de miembros de un conjunto ordenado en una clave.

  [Más información](https://valkey.io/commands/zrangestore/)
+ `ZRANK`

  Devuelve el índice de un miembro en un conjunto ordenado por puntuaciones ascendentes.

  [Más información](https://valkey.io/commands/zrank/)
+ `ZREM`

  Elimina uno o varios miembros de un conjunto ordenado. Elimina el conjunto ordenado si se han eliminado todos los miembros.

  [Más información](https://valkey.io/commands/zrem/)
+ `ZREMRANGEBYLEX`

  Elimina los miembros de un conjunto ordenado dentro de un rango lexicográfico. Elimina el conjunto ordenado si se han eliminado todos los miembros.

  [Más información](https://valkey.io/commands/zremrangebylex/)
+ `ZREMRANGEBYRANK`

  Elimina los miembros de un conjunto ordenado dentro de un rango de índices. Elimina el conjunto ordenado si se han eliminado todos los miembros.

  [Más información](https://valkey.io/commands/zremrangebyrank/)
+ `ZREMRANGEBYSCORE`

  Elimina los miembros de un conjunto ordenado dentro de un rango de puntuaciones. Elimina el conjunto ordenado si se han eliminado todos los miembros.

  [Más información](https://valkey.io/commands/zremrangebyscore/)
+ `ZREVRANGE`

  Devuelve los miembros de un conjunto ordenado dentro de un rango de índices en orden inverso.

  [Más información](https://valkey.io/commands/zrevrange/)
+ `ZREVRANGEBYLEX`

  Devuelve los miembros de un conjunto ordenado dentro de un rango lexicográfico en orden inverso.

  [Más información](https://valkey.io/commands/zrevrangebylex/)
+ `ZREVRANGEBYSCORE`

  Devuelve los miembros de un conjunto ordenado dentro de un rango de puntuaciones en orden inverso.

  [Más información](https://valkey.io/commands/zrevrangebyscore/)
+ `ZREVRANK`

  Devuelve el índice de un miembro en un conjunto ordenado por puntuaciones descendientes.

  [Más información](https://valkey.io/commands/zrevrank/)
+ `ZSCAN`

  Hace iteraciones sobre los miembros y las puntuaciones de un conjunto ordenado.

  [Más información](https://valkey.io/commands/zscan/)
+ `ZSCORE`

  Devuelve la puntuación de un miembro en un conjunto ordenado.

  [Más información](https://valkey.io/commands/zscore/)
+ `ZUNION`

  Devuelve la unión de varios conjuntos ordenados.

  [Más información](https://valkey.io/commands/zunion/)
+ `ZUNIONSTORE`

  Almacena la unión de varios conjuntos ordenados en una clave.

  [Más información](https://valkey.io/commands/zunionstore/)

**Comandos de transmisión**
+ `XACK`

  Devuelve el número de mensajes confirmados correctamente por el miembro del grupo de consumidores de una transmisión.

  [Más información](https://valkey.io/commands/xack/)
+ `XADD`

  Añade un mensaje nuevo a una transmisión. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/xadd/)
+ `XAUTOCLAIM`

  Cambia o adquiere la propiedad de los mensajes de un grupo de consumidores, como si los mensajes se hubieran entregado como miembro del grupo de consumidores.

  [Más información](https://valkey.io/commands/xautoclaim/)
+ `XCLAIM`

  Cambia o adquiere la propiedad de un mensaje en un grupo de consumidores, como si el mensaje se hubiera entregado por parte de un miembro del grupo de consumidores.

  [Más información](https://valkey.io/commands/xclaim/)
+ `XDEL`

  Devuelve el número de mensajes después de eliminarlos de una transmisión.

  [Más información](https://valkey.io/commands/xdel/)
+ `XGROUP CREATE`

  Crea un grupo de consumidores. 

  [Más información](https://valkey.io/commands/xgroup-create/)
+ `XGROUP CREATECONSUMER`

  Crea un consumidor en un grupo de consumidores.

  [Más información](https://valkey.io/commands/xgroup-createconsumer/)
+ `XGROUP DELCONSUMER`

  Elimina un consumidor de un grupo de consumidores.

  [Más información](https://valkey.io/commands/xgroup-delconsumer/)
+ `XGROUP DESTROY`

  Destruye un grupo de consumidores.

  [Más información](https://valkey.io/commands/xgroup-destroy/)
+ `XGROUP SETID`

  Establece el último ID entregado de un grupo de consumidores.

  [Más información](https://valkey.io/commands/xgroup-setid/)
+ `XINFO CONSUMERS`

  Devuelve una lista de los consumidores de un grupo de consumidores.

  [Más información](https://valkey.io/commands/xinfo-consumers/)
+ `XINFO GROUPS`

  Devuelve una lista de los grupos de consumidores de una transmisión.

  [Más información](https://valkey.io/commands/xinfo-groups/)
+ `XINFO STREAM`

  Devuelve información sobre una transmisión.

  [Más información](https://valkey.io/commands/xinfo-stream/)
+ `XLEN`

  Devuelve la cantidad de mensajes en una transmisión.

  [Más información](https://valkey.io/commands/xlen/)
+ `XPENDING`

  Devuelve la información y las entradas de la lista de entradas pendientes de un grupo de consumidores de una transmisión.

  [Más información](https://valkey.io/commands/xpending/)
+ `XRANGE`

  Devuelve los mensajes de una secuencia dentro de un rango de. IDs

  [Más información](https://valkey.io/commands/xrange/)
+ `XREAD`

  Devuelve los mensajes de varios flujos con IDs un número mayor al solicitado. De lo contrario, bloquea hasta que haya un mensaje disponible.

  [Más información](https://valkey.io/commands/xread/)
+ `XREADGROUP`

  Devuelve mensajes nuevos o históricos de una transmisión para un consumidor en un grupo. De lo contrario, bloquea hasta que haya un mensaje disponible.

  [Más información](https://valkey.io/commands/xreadgroup/)
+ `XREVRANGE`

  Devuelve los mensajes de una secuencia dentro de un rango de IDs en orden inverso.

  [Más información](https://valkey.io/commands/xrevrange/)
+ `XTRIM`

  Elimina los mensajes desde el principio de una transmisión.

  [Más información](https://valkey.io/commands/xtrim/)

**Comandos de cadenas**
+ `APPEND`

  Añade una cadena al valor de una clave. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/append/)
+ `DECR`

  Disminuye en uno el valor entero de una clave. Utiliza 0 como valor inicial si la clave no existe.

  [Más información](https://valkey.io/commands/decr/)
+ `DECRBY`

  Disminuye un número del valor entero de una clave. Utiliza 0 como valor inicial si la clave no existe.

  [Más información](https://valkey.io/commands/decrby/)
+ `GET`

  Devuelve el valor de cadena de una clave.

  [Más información](https://valkey.io/commands/get/)
+ `GETDEL`

  Devuelve el valor de cadena de una clave tras eliminarla.

  [Más información](https://valkey.io/commands/getdel/)
+ `GETEX`

  Devuelve el valor de cadena de una clave tras establecer su fecha de caducidad.

  [Más información](https://valkey.io/commands/getex/)
+ `GETRANGE`

  Devuelve una subcadena de la cadena almacenada en una clave.

  [Más información](https://valkey.io/commands/getrange/)
+ `GETSET`

  Devuelve el valor de cadena anterior de una clave después de establecerla en un nuevo valor.

  [Más información](https://valkey.io/commands/getset/)
+ `INCR`

  Aumenta en uno el valor entero de una clave. Utiliza 0 como valor inicial si la clave no existe.

  [Más información](https://valkey.io/commands/incr/)
+ `INCRBY`

  Incrementa en un número determinado el valor entero de una clave. Utiliza 0 como valor inicial si la clave no existe.

  [Más información](https://valkey.io/commands/incrby/)
+ `INCRBYFLOAT`

  Incrementa en un número determinado el valor de punto flotante de una clave. Utiliza 0 como valor inicial si la clave no existe.

  [Más información](https://valkey.io/commands/incrbyfloat/)
+ `LCS`

  Busca la subcadena común más larga.

  [Más información](https://valkey.io/commands/lcs/)
+ `MGET`

  Devuelve íntegramente los valores de cadena de una o más claves.

  [Más información](https://valkey.io/commands/mget/)
+ `MSET`

  Crea o modifica íntegramente los valores de cadena de una o más claves.

  [Más información](https://valkey.io/commands/mset/)
+ `MSETNX`

  Modifica íntegramente los valores de cadena de una o más claves solo cuando no existen todas las claves.

  [Más información](https://valkey.io/commands/msetnx/)
+ `PSETEX`

  Establece tanto el valor de la cadena como el tiempo de caducidad en milisegundos de una clave. La clave se crea si no existe.

  [Más información](https://valkey.io/commands/psetex/)
+ `SET`

  Establece el valor de cadena de una clave e ignora el tipo. La clave se crea si no existe.

  [Más información](https://valkey.io/commands/set/)
+ `SETEX`

  Establece el valor de la cadena y el tiempo de caducidad de una clave. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/setex/)
+ `SETNX`

  Establece el valor de cadena de una clave solo cuando la clave no existe.

  [Más información](https://valkey.io/commands/setnx/)
+ `SETRANGE`

  Sobrescribe una parte del valor de una cadena por otra a partir de una determinada posición. Crea la clave si esta no existe.

  [Más información](https://valkey.io/commands/setrange/)
+ `STRLEN`

  Devuelve la longitud del valor de la cadena.

  [Más información](https://valkey.io/commands/strlen/)
+ `SUBSTR`

  Devuelve una subcadena a partir de un valor de cadena.

  [Más información](https://valkey.io/commands/substr/)

**Comandos de transacción**
+ `DISCARD`

  Descarta una transacción.

  [Más información](https://valkey.io/commands/discard/)
+ `EXEC`

  Ejecuta todos los comandos de una transacción.

  [Más información](https://valkey.io/commands/exec/)
+ `MULTI`

  Inicia una transacción.

  [Más información](https://valkey.io/commands/multi/)

## Comandos restringidos de Valkey y Redis OSS
<a name="RestrictedCommandsRedis"></a>

Para ofrecer una experiencia de servicio gestionado, ElastiCache restringe el acceso a determinados comandos específicos del motor de caché que requieren privilegios avanzados. En las cachés que ejecutan Redis OSS, los siguientes comandos no están disponibles:
+ `acl setuser`
+ `acl load`
+ `acl save`
+ `acl deluser`
+ `bgrewriteaof`
+ `bgsave`
+ `cluster addslot`
+ `cluster addslotsrange`
+ `cluster bumpepoch`
+ `cluster delslot`
+ `cluster delslotsrange `
+ `cluster failover `
+ `cluster flushslots `
+ `cluster forget `
+ `cluster links`
+ `cluster meet`
+ `cluster setslot`
+ `config`
+ `debug`
+ `migrate`
+ `psync`
+ `replicaof`
+ `save`
+ `slaveof`
+ `shutdown`
+ `sync`

Además, los siguientes comandos no están disponibles para las cachés sin servidor:
+ `acl log`
+ `client caching`
+ `client getredir`
+ `client id`
+ `client info`
+ `client kill`
+ `client list`
+ `client no-evict`
+ `client pause`
+ `client tracking`
+ `client trackinginfo`
+ `client unblock`
+ `client unpause`
+ `cluster count-failure-reports`
+ `commandlog`
+ `commandlog get`
+ `commandlog help`
+ `commandlog len`
+ `commandlog reset`
+ `fcall`
+ `fcall_ro`
+ `function`
+ `function delete`
+ `function dump`
+ `function flush`
+ `function help`
+ `function kill`
+ `function list`
+ `function load`
+ `function restore`
+ `function stats`
+ `keys`
+ `lastsave`
+ `latency`
+ `latency doctor`
+ `latency graph`
+ `latency help`
+ `latency histogram`
+ `latency history`
+ `latency latest`
+ `latency reset`
+ `memory`
+ `memory doctor`
+ `memory help`
+ `memory malloc-stats`
+ `memory purge`
+ `memory stats`
+ `memory usage`
+ `monitor`
+ `move`
+ `object`
+ `object encoding`
+ `object freq`
+ `object help`
+ `object idletime`
+ `object refcount`
+ `pfdebug`
+ `pfselftest`
+ `psubscribe`
+ `pubsub numpat`
+ `punsubscribe`
+ `script kill`
+ `slowlog`
+ `slowlog get`
+ `slowlog help`
+ `slowlog len`
+ `slowlog reset`
+ `swapdb`
+ `wait`

## Comandos compatibles con Memcached
<a name="SupportedCommandsMem"></a>

ElastiCache Serverless for Memcached admite todos los [comandos](https://github.com/memcached/memcached/wiki/Commands) de memcached de la versión 1.6 de código abierto de memcached, excepto los siguientes: 
+ Las conexiones de cliente requieren TLS, por lo que no se admite el protocolo UDP.
+ El protocolo binario no es compatible, ya que está oficialmente [obsoleto](https://github.com/memcached/memcached/wiki/ReleaseNotes160) en memcached 1.6.
+ Los comandos `GET/GETS` están limitados a 16 KB para evitar posibles ataques de DoS al servidor con la obtención de una gran cantidad de claves.
+ El comando `flush_all` retrasado se rechazará con `CLIENT_ERROR`.
+ No se admiten los comandos que configuran el motor o revelan información interna sobre el estado o los registros del motor, como los siguientes:
  + En el comando `STATS`, solo se admiten `stats` y `stats reset`. Otras variantes devolverán un `ERROR`
  + `lru / lru_crawler`: modificación de la configuración de LRU y el rastreador de LRU
  + `watch`: observa los registros del servidor memcached
  + `verbosity`: configura el nivel de registro del servidor
  + `me`: no se admite el comando meta debug (me)

# Configuración y límites de Valkey y Redis OSS
<a name="RedisConfiguration"></a>

Cada uno de los motores OSS de Valkey y Redis proporciona una serie de parámetros de configuración, algunos de los cuales se pueden modificar ElastiCache para Redis OSS y otros no se pueden modificar para proporcionar un rendimiento y una fiabilidad estables.

## Cachés sin servidor
<a name="RedisConfiguration.Serverless"></a>

En el caso de las cachés sin servidor, no se utilizan grupos de parámetros y no se puede modificar ninguna parte de la configuración de Valkey o Redis OSS. Los siguientes parámetros de Valkey o Redis OSS están implementados:


****  

|  Name  |  Details  |  Description (Descripción)  | 
| --- | --- | --- | 
| acl-pubsub-default | `allchannels` | Permisos de canal pubsub predeterminados para los usuarios de ACL en la caché. | 
| client-output-buffer-limit | `normal 0 0 0` `pubsub 32mb 8mb 60` | Los clientes normales no tienen límite de búfer. PUB/SUB los clientes se desconectarán si superan una cartera de 32 MiB o si superan una acumulación de 8 MiB durante 60 segundos. | 
| client-query-buffer-limit | 1 GiB | El tamaño máximo de un búfer de consulta de cliente. Además, los clientes no pueden emitir una solicitud con más de 3999 argumentos. | 
| cluster-allow-pubsubshard-when-down | yes | Esto permite que la caché sirva el tráfico de pubsub mientras esté parcialmente inactiva. | 
| cluster-allow-reads-when-down | yes | Esto permite que la caché sirva el tráfico de lectura mientras esté parcialmente inactiva. | 
| cluster-enabled | yes | Todas las cachés sin servidor están habilitadas para el modo de clúster, lo que les permite dividir sus datos de forma transparente en varias particiones de backend. Los clientes observan todos los slots como si perteneciesen a un único nodo virtual. | 
| cluster-require-full-coverage | no | Cuando el espacio de claves esté parcialmente inactivo (es decir, hay, al menos, un slot hash inaccesible), la memoria caché seguirá aceptando consultas para la parte del espacio de claves que aún esté cubierta. El espacio de claves en su totalidad estará siempre “cubierto” por un único nodo virtual en cluster slots. | 
| lua-time-limit | 5000 | El tiempo máximo de ejecución de un script de Lua, en milisegundos, antes ElastiCache de que tome medidas para detenerlo. Si se supera el valor de `lua-time-limit`, todos los comandos de Valkey o Redis OSS devolverán un error con el formato *\$1\$1\$1\$1-BUSY*. Dado que este estado puede provocar interferencias con muchas operaciones esenciales de Valkey o Redis OSS, primero ElastiCache emitirá un comando *SCRIPT* KILL. Si esto no funciona, ElastiCache reiniciará forzosamente Valkey o Redis OSS. | 
| maxclients | 65000 | Número máximo de clientes que pueden conectarse a la vez. Las conexiones adicionales que se establezcan pueden realizarse correctamente o no. | 
| maxmemory-policy | volatile-lru | Los elementos con un TTL configurado se expulsan tras una estimación least-recently-used (LRU) cuando se alcanza el límite de memoria de la caché. | 
| notify-keyspace-events | (una cadena vacía) | Actualmente, los eventos de espacio de claves no son compatibles con las cachés sin servidor. | 
| port | Puerto principal: 6379 Puerto de lectura: 6380 | Las cachés sin servidor muestran dos puertos con el mismo nombre de host. El puerto principal permite escribir y leer, mientras que el puerto de lectura permite lecturas coherentes posteriores de menor latencia mediante el comando READONLY. | 
| proto-max-bulk-len | 512 MiB | El tamaño máximo de una sola solicitud de elemento. | 
| timeout | 0 | Los clientes no se desconectan de forma ineludible tras un tiempo de inactividad específico, pero es posible que se desconecten durante el estado estable para equilibrar la carga. | 

Además, existen los siguientes límites:


****  

|  Name  |  Details  |  Description (Descripción)  | 
| --- | --- | --- | 
| Tamaño por caché | 5000 GiB | Cantidad máxima de datos que se puede almacenar por caché sin servidor. | 
| Tamaño por slot | 32 GiB | El tamaño máximo de una única ranura de hash de Valkey o Redis OSS. Los clientes que intenten almacenar más datos en una sola ranura de Valkey o Redis OSS activarán la política de expulsión en la ranura y, si no se puede expulsar ninguna clave, recibirán un error de memoria insuficiente (OOM). | 
| ECPU por caché | 15 000 000 ECPU/segundo | ElastiCache Métrica de unidades de procesamiento (ECPU). La cantidad de datos ECPUs consumidos por las solicitudes depende del tiempo empleado por la vCPU y de la cantidad de datos transferidos. | 
| ECPU por ranura | 30 000 a 90 000 ECPU/segundo | Máximo 30 000 ECPUs/second por ranura o 90 000 ECPUs/second si se utiliza Read from Replica mediante conexiones READONLY. | 
| Argumentos por solicitud | 3.999 | Número máximo de argumentos por solicitud. Si un cliente envía más argumentos por solicitud, se genera un error. | 
| Longitud del nombre de la clave | 4 KiB | El tamaño máximo de una sola clave de Valkey o Redis OSS o el nombre de un canal. Los clientes que hagan referencia a claves de un tamaño mayor a este valor recibirán un error. | 
| El tamaño del script de Lua | 4 MiB | El tamaño máximo de un único script de Lua de Valkey o Redis OSS. Los intentos de cargar un script de Lua con un tamaño superior a este recibirán un error. | 

## Clústeres basados en nodos
<a name="RedisConfiguration.SelfDesigned"></a>

Con respecto a los clústeres basados en nodos, consulte [Parámetros de Valkey y Redis OSS](ParameterGroups.Engine.md#ParameterGroups.Redis) para obtener información sobre los valores predeterminados de los parámetros de configuración y para saber cuáles son configurables. Por lo general, se recomiendan los valores predeterminados, a menos que tenga un caso de uso específico que requiera anularlos.

# Ejemplos de clientes de IPv6 para Valkey, Memcached y Redis OSS
<a name="network-type-best-practices"></a>

ElastiCache es compatible con Valkey, Memcached y Redis OSS. Esto significa que los clientes que admiten conexiones de IPv6 deberían poder conectarse a clústeres de ElastiCache para Memcached habilitados para IPv6. Hay algunas advertencias que merece la pena señalar al interactuar con recursos habilitados para IPv6.

Puede consultar la publicación [Best practices for Valkey and Redis clients](https://aws.amazon.com/blogs/database/best-practices-redis-clients-and-amazon-elasticache-for-redis/) en AWS Database Blog para obtener recomendaciones sobre la configuración de los clientes de Valkey y Redis OSS para los recursos de ElastiCache.

A continuación, se presentan las prácticas recomendadas para interactuar con los recursos de ElastiCache habilitados para IPv6 con las bibliotecas de cliente de código abierto que se utilizan habitualmente. 

## Clientes validados con Valkey y Redis OSS
<a name="network-type-validated-clients-redis"></a>

ElastiCache es compatible con Valkey y Redis OSS de código abierto. Esto significa que los clientes de Valkey y Redis OSS de código abierto que admiten conexiones de IPv6 deberían poder conectarse a los clústeres de ElastiCache para Redis OSS habilitados para IPv6. Además, varios de los clientes de Python y Java más populares se han probado y validado específicamente para que funcionen con todas las configuraciones de tipos de red compatibles (solo IPv4, solo IPv6 y doble pila).

Los siguientes clientes se han validado específicamente para funcionar con todas las configuraciones de tipo de red admitidas para Valkey y Redis OSS.

Clientes validados:
+ [Redis Py ()](https://github.com/redis/redis-py): [4.1.2](https://github.com/redis/redis-py/tree/v4.1.2)
+ [Lettuce](https://lettuce.io/): [versión 6.1.6.RELEASE](https://github.com/lettuce-io/lettuce-core/tree/6.1.6.RELEASE)
+ [Jedis](https://github.com/redis/jedis): [versión 3.6.0](https://github.com/redis/jedis/tree/jedis-3.6.0)

# Prácticas recomendadas para clientes (Valkey y Redis OSS)
<a name="BestPractices.Clients.redis"></a>

Descubra las prácticas recomendadas en escenarios habituales y siga los ejemplos de código de algunas de las bibliotecas cliente de Valkey y Redis OSS de código abierto más populares (redis-py, PHPRedis y Lettuce), así como las prácticas recomendadas para interactuar con los recursos de ElastiCache con bibliotecas cliente de Memcached de código abierto de uso habitual.

**Topics**
+ [Gran cantidad de conexiones (Valkey y Redis OSS)](BestPractices.Clients.Redis.Connections.md)
+ [Detección de clústeres por parte del cliente y retroceso exponencial (Valkey y Redis OSS)](BestPractices.Clients.Redis.Discovery.md)
+ [Configuración de un tiempo de espera del cliente (Valkey y Redis OSS)](BestPractices.Clients.Redis.ClientTimeout.md)
+ [Configuración de un tiempo de espera del servidor (Valkey y Redis OSS)](BestPractices.Clients.Redis.ServerTimeout.md)
+ [Scripts de Lua](BestPractices.Clients.Redis.LuaScripts.md)
+ [Almacenamiento de elementos compuestos de gran tamaño (Valkey y Redis OSS)](BestPractices.Clients.Redis.LargeItems.md)
+ [Configuración del cliente de Lettuce (Valkey y Redis OSS)](BestPractices.Clients-lettuce.md)
+ [Configuración de un protocolo preferido para clústeres de doble pila (Valkey y Redis OSS)](#network-type-configuring-dual-stack-redis)

# Gran cantidad de conexiones (Valkey y Redis OSS)
<a name="BestPractices.Clients.Redis.Connections"></a>

Las cachés sin servidor y los nodos individuales de ElastiCache para Redis OSS admiten hasta 65 000 conexiones de clientes simultáneas. Sin embargo, para optimizar el rendimiento, recomendamos que las aplicaciones cliente no funcionen constantemente con ese volumen de conexiones. Valkey y Redis OSS tienen cada uno un subproceso basado en un bucle de eventos en el que las solicitudes entrantes de los clientes se gestionan de forma secuencial. Esto significa que el tiempo de respuesta de un cliente determinado se hace más largo a medida que aumenta el número de clientes conectados.

Puede tomar las siguientes medidas para evitar un cuello de botella en la conexión del servidor de Valkey o Redis OSS:
+ Llevar a cabo las operaciones de lectura a partir de réplicas de lectura. Puede hacer esto usando los puntos de conexión del lector ElastiCache con el modo de clúster deshabilitado o usando réplicas para las lecturas con el modo de clúster habilitado, lo que incluye una caché sin servidor.
+ Distribuir el tráfico de escritura entre varios nodos principales. Puede hacerlo de dos formas. Puede utilizar un clúster de Valkey y Redis OSS con varias particiones en un cliente compatible con el modo de clúster. También puede escribir en varios nodos principales con el modo de clúster deshabilitado y con partición en el lado del cliente. Esto se hace automáticamente en una memoria caché sin servidor.
+ Usar un grupo de conexiones cuando esté disponible en la biblioteca de su cliente.

En general, crear una conexión de TCP es una operación costosa desde el punto de vista computacional en comparación con los comandos típicos de Valkey o Redis OSS. Por ejemplo, gestionar una solicitud SET/GET es una orden de magnitud más rápido cuando se reutiliza una conexión existente. El uso de un grupo de conexiones de clientes con un tamaño finito reduce la sobrecarga en la administración de conexiones. También limita el número de conexiones entrantes simultáneas desde la aplicación cliente.

El siguiente ejemplo de código de PHPRedis muestra cómo se crea una nueva conexión para cada nueva solicitud de usuario:

```
$redis = new Redis();
if ($redis->connect($HOST, $PORT) != TRUE) {
	//ERROR: connection failed
	return;
}
$redis->set($key, $value);
unset($redis);
$redis = NULL;
```

Hemos comparado este código en bucle en una instancia de Amazon Elastic Compute Cloud (Amazon EC2) conectada a un nodo ElastiCache para Redis OSS de Graviton2 (m6g.2xlarge). Hemos colocado el cliente y el servidor dentro de la misma zona de disponibilidad. La latencia media de toda la operación fue de 2,82 milisegundos.

Cuando actualizamos el código y utilizamos conexiones persistentes y un grupo de conexiones, la latencia media de toda la operación fue de 0,21 milisegundos:

```
$redis = new Redis();
if ($redis->pconnect($HOST, $PORT) != TRUE) {
	// ERROR: connection failed
	return;
}
$redis->set($key, $value);
unset($redis);
$redis = NULL;
```

Configuraciones de redis.ini obligatorias:
+ `redis.pconnect.pooling_enabled=1`
+ `redis.pconnect.connection_limit=10`

El siguiente código es un ejemplo de un [grupo de conexiones Redis-py](https://redis.readthedocs.io/en/stable/):

```
conn = Redis(connection_pool=redis.BlockingConnectionPool(host=HOST, max_connections=10))
conn.set(key, value)
```

El siguiente código es un ejemplo de un [grupo de conexiones Lettuce](https://lettuce.io/core/release/reference/#_connection_pooling):

```
RedisClient client = RedisClient.create(RedisURI.create(HOST, PORT));
GenericObjectPool<StatefulRedisConnection> pool = ConnectionPoolSupport.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
pool.setMaxTotal(10); // Configure max connections to 10
try (StatefulRedisConnection connection = pool.borrowObject()) {
	RedisCommands syncCommands = connection.sync();
	syncCommands.set(key, value);
}
```

# Detección de clústeres por parte del cliente y retroceso exponencial (Valkey y Redis OSS)
<a name="BestPractices.Clients.Redis.Discovery"></a>

Al conectarse a un clúster de ElastiCache Valkey o Redis OSS con el modo de clúster habilitado, la biblioteca cliente correspondiente debe reconocer los clústeres. Los clientes deben obtener un mapa de los slots hash de los nodos correspondientes del clúster para poder enviar las solicitudes a los nodos correctos, y evitar así la sobrecarga de rendimiento que supone gestionar las redirecciones del clúster. Como resultado, el cliente debe descubrir (o detectar) una lista completa de los slots y los nodos mapeados en dos situaciones diferentes:
+ El cliente se inicializa y debe completar la configuración inicial de los slots.
+ Se recibe una redirección MOVED del servidor; por ejemplo, en una conmutación por error, cuando la réplica se hace cargo de todos los slots atendidos por el nodo principal anterior, o en una nueva partición, cuando los slots se mueven del nodo principal de origen al nodo principal de destino.

Por lo general, el proceso de detección por parte del cliente se lleva a cabo enviando un comando CLUSTER SLOT o CLUSTER NODE al servidor de Valkey o Redis OSS. Recomendamos el método CLUSTER SLOT porque devuelve al cliente el conjunto de rangos de slots, así como los nodos principales y de réplica asociados. Es un método que no requiere un análisis adicional por parte del cliente y es más eficaz.

En función de la topología del clúster, el tamaño de la respuesta al comando CLUSTER SLOT puede variar según el tamaño del clúster. Los clústeres más grandes y con más nodos producen una respuesta mayor. Por lo tanto, es importante asegurarse de que la cantidad de clientes que llevan a cabo la detección de la topología del clúster no aumente de forma ilimitada. Por ejemplo, cuando la aplicación cliente se inicia o pierde la conexión con el servidor y debe realizar una detección de clústeres, un error común es que la aplicación cliente desencadene varias solicitudes de reconexión y detección sin añadir un retroceso exponencial con el nuevo intento. Esto puede hacer que el servidor de Valkey o Redis OSS deje de responder durante mucho tiempo, con un uso de la CPU del 100 %. La interrupción se prolonga si cada comando CLUSTER SLOT debe procesar una gran cantidad de nodos en el bus del clúster. En el pasado, hemos observado varias interrupciones en los clientes debido a este comportamiento en varios lenguajes diferentes, como Python (redis-py-cluster) y Java (Lettuce y Redisson).

En una caché sin servidor, muchos de los problemas se mitigan automáticamente porque la topología de clúster expuesta es estática y consta de dos entradas: un punto de conexión de escritura y otro de lectura. La detección de clústeres también se distribuye automáticamente entre varios nodos cuando se utiliza el punto de conexión de la caché. Sin embargo, las siguientes recomendaciones siguen siendo útiles.

A fin de mitigar el impacto causado por una entrada repentina de solicitudes de conexión y detección, recomendamos lo siguiente:
+ Implemente un grupo de conexiones de cliente con un tamaño finito a fin de limitar el número de conexiones entrantes simultáneas desde la aplicación cliente.
+ Cuando el cliente se desconecte del servidor debido al tiempo de espera, vuelva a intentarlo con retroceso exponencial y fluctuación. Esto evitará que varios clientes sobrecarguen el servidor al mismo tiempo.
+ Utilice la guía en [Búsqueda de puntos de conexión en ElastiCache](Endpoints.md) para encontrar el punto de conexión del clúster que necesitará a fin de realizar la detección del clúster. De este modo, distribuirá la carga de detección entre todos los nodos del clúster (hasta 90), en lugar de centrarse en unos pocos nodos raíz codificados del clúster.

A continuación, se muestran algunos ejemplos de código para la lógica de reintentos de retroceso exponencial en redis-py, PHPRedis y Lettuce.

**Ejemplo 1 de lógica de retroceso: redis-py**

Redis-py tiene un mecanismo de reintento incorporado: se lleva a cabo un reintento inmediatamente después de un error. Este mecanismo se puede activar mediante el argumento `retry_on_timeout` proporcionado al crear un objeto de [Redis OSS](https://redis.readthedocs.io/en/stable/examples/connection_examples.html#redis.Redis). Aquí mostramos un mecanismo de reintento personalizado con retroceso exponencial y fluctuación. Hemos enviado una solicitud de extracción para implementar de forma nativa el retroceso exponencial en [redis-py (1494)](https://github.com/andymccurdy/redis-py/pull/1494). En el futuro, puede que no sea necesario implementarlo manualmente.

```
def run_with_backoff(function, retries=5):
base_backoff = 0.1 # base 100ms backoff
max_backoff = 10 # sleep for maximum 10 seconds
tries = 0
while True:
try:
  return function()
except (ConnectionError, TimeoutError):
  if tries >= retries:
	raise
  backoff = min(max_backoff, base_backoff * (pow(2, tries) + random.random()))
  print(f"sleeping for {backoff:.2f}s")
  sleep(backoff)
  tries += 1
```

Luego, puede utilizar el siguiente código para establecer un valor:

```
client = redis.Redis(connection_pool=redis.BlockingConnectionPool(host=HOST, max_connections=10))
res = run_with_backoff(lambda: client.set("key", "value"))
print(res)
```

En función de la carga de trabajo, es posible que desee cambiar el valor del retroceso base (de 1 segundo a unas pocas decenas o cientos de milisegundos) para las cargas de trabajo sensibles a la latencia.

**Ejemplo 2 de lógica de retroceso: PHPRedis**

PHPRedis tiene un mecanismo de reintento incorporado: hay un número máximo de reintento de 10 veces (no configurable). Hay un retraso configurable entre los intentos (con una fluctuación a partir del segundo reintento). Para obtener más información, consulte el siguiente [código de muestra](https://github.com/phpredis/phpredis/blob/b0b9dd78ef7c15af936144c1b17df1a9273d72ab/library.c#L335-L368). Enviamos una solicitud de extracción para implementar de forma nativa el retroceso exponencial en [PHPredis (1986)](https://github.com/phpredis/phpredis/pull/1986); desde entonces, se ha fusionado y [documentado](https://github.com/phpredis/phpredis/blob/develop/README.md#retry-and-backoff). Si utiliza la última versión de PHPRedis, no será necesario implementarla manualmente, pero hemos incluido aquí la referencia para las versiones anteriores. De momento, aquí tiene un ejemplo de código para configurar el retraso del mecanismo de reintento:

```
$timeout = 0.1; // 100 millisecond connection timeout
$retry_interval = 100; // 100 millisecond retry interval
$client = new Redis();
if($client->pconnect($HOST, $PORT, $timeout, NULL, $retry_interval) != TRUE) {
	return; // ERROR: connection failed
}
$client->set($key, $value);
```

**Ejemplo 3 de lógica de retroceso: Lettuce**

Lettuce tiene mecanismos de reintento incorporados que emplean las estrategias de retroceso exponencial descritas en la publicación [Exponential Backoff and Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/). A continuación, puede ver un fragmento de código con el método de fluctuación total:

```
public static void main(String[] args)
{
	ClientResources resources = null;
	RedisClient client = null;

	try {
		resources = DefaultClientResources.builder()
				.reconnectDelay(Delay.fullJitter(
			Duration.ofMillis(100),     // minimum 100 millisecond delay
			Duration.ofSeconds(5),      // maximum 5 second delay
			100, TimeUnit.MILLISECONDS) // 100 millisecond base
		).build();

		client = RedisClient.create(resources, RedisURI.create(HOST, PORT));
		client.setOptions(ClientOptions.builder()
	.socketOptions(SocketOptions.builder().connectTimeout(Duration.ofMillis(100)).build()) // 100 millisecond connection timeout
	.timeoutOptions(TimeoutOptions.builder().fixedTimeout(Duration.ofSeconds(5)).build()) // 5 second command timeout
	.build());

	    // use the connection pool from above example
	} finally {
		if (connection != null) {
			connection.close();
		}

		if (client != null){
			client.shutdown();
		}

		if (resources != null){
			resources.shutdown();
		}

	}
}
```

# Configuración de un tiempo de espera del cliente (Valkey y Redis OSS)
<a name="BestPractices.Clients.Redis.ClientTimeout"></a>

**Configuración del tiempo de espera del cliente**

Configure el tiempo de espera del lado del cliente de la manera adecuada, a fin de que el servidor tenga tiempo suficiente para procesar la solicitud y generar la respuesta. Esto también le permitirá responder rápido a los errores si no se puede establecer la conexión con el servidor. Ciertos comandos de Valkey o Redis OSS pueden ser más costosos desde el punto de vista computacional que otros. Un ejemplo de esto son los scripts de Lua o las transacciones MULTI/EXEC con varios comandos que deben ejecutarse de forma integral. Por lo general, es recomendable aumentar el tiempo de espera del cliente para evitar que este se quede sin tiempo antes de recibir la respuesta del servidor, lo que incluye lo siguiente:
+ Ejecutar comandos en varias claves
+ Ejecutar transacciones MULTI/EXEC o scripts de Lua que consten de varios comandos individuales de Valkey o Redis OSS
+ Leer valores grandes
+ Realizar operaciones de bloqueo, como BLPOP

En el caso de una operación de bloqueo como BLPOP, el procedimiento recomendado es establecer el tiempo de espera del comando en un número inferior al tiempo de espera del socket.

A continuación, encontrará ejemplos de código para implementar un tiempo de espera del lado del cliente en redis-py, PHPRedis y Lettuce.

**Ejemplo 1 de configuración de tiempo de espera: redis-py**

A continuación, puede ver un ejemplo de código con redis-py:

```
# connect to Redis server with a 100 millisecond timeout
# give every Redis command a 2 second timeout
client = redis.Redis(connection_pool=redis.BlockingConnectionPool(host=HOST, max_connections=10,socket_connect_timeout=0.1,socket_timeout=2))

res = client.set("key", "value") # will timeout after 2 seconds
print(res)                       # if there is a connection error

res = client.blpop("list", timeout=1) # will timeout after 1 second
                                      # less than the 2 second socket timeout
print(res)
```

**Ejemplo 2 de configuración de tiempo de espera: PHPRedis**

A continuación, puede ver un ejemplo de código con PHPRedis:

```
// connect to Redis server with a 100ms timeout
// give every Redis command a 2s timeout
$client = new Redis();
$timeout = 0.1; // 100 millisecond connection timeout
$retry_interval = 100; // 100 millisecond retry interval
$client = new Redis();
if($client->pconnect($HOST, $PORT, 0.1, NULL, 100, $read_timeout=2) != TRUE){
	return; // ERROR: connection failed
}
$client->set($key, $value);

$res = $client->set("key", "value"); // will timeout after 2 seconds
print "$res\n";                      // if there is a connection error

$res = $client->blpop("list", 1); // will timeout after 1 second
print "$res\n";                   // less than the 2 second socket timeout
```

**Ejemplo 3 de configuración de tiempo de espera: Lettuce**

A continuación, puede ver un ejemplo de código con Lettuce:

```
// connect to Redis server and give every command a 2 second timeout
public static void main(String[] args)
{
	RedisClient client = null;
	StatefulRedisConnection<String, String> connection = null;
	try {
		client = RedisClient.create(RedisURI.create(HOST, PORT));
		client.setOptions(ClientOptions.builder()
	.socketOptions(SocketOptions.builder().connectTimeout(Duration.ofMillis(100)).build()) // 100 millisecond connection timeout
	.timeoutOptions(TimeoutOptions.builder().fixedTimeout(Duration.ofSeconds(2)).build()) // 2 second command timeout 
	.build());

		// use the connection pool from above example

		commands.set("key", "value"); // will timeout after 2 seconds
		commands.blpop(1, "list"); // BLPOP with 1 second timeout
	} finally {
		if (connection != null) {
			connection.close();
		}

		if (client != null){
			client.shutdown();
		}
	}
}
```

# Configuración de un tiempo de espera del servidor (Valkey y Redis OSS)
<a name="BestPractices.Clients.Redis.ServerTimeout"></a>

Hemos observado casos en los que la aplicación de un cliente tiene un gran número de clientes inactivos conectados, pero no envía comandos de forma activa. En estos casos, se pueden agotar las 65 000 conexiones con un número elevado de clientes inactivos. Para evitar este tipo de situaciones, configure el tiempo de espera adecuadamente en el servidor mediante [Parámetros de Valkey y Redis OSS](ParameterGroups.Engine.md#ParameterGroups.Redis). Esto garantiza que el servidor tome la iniciativa en desconectar a los clientes inactivos para evitar un aumento en el número de conexiones. Esta configuración no está disponible en las caché sin servidor.

# Scripts de Lua
<a name="BestPractices.Clients.Redis.LuaScripts"></a>

Valkey y Redis OSS admiten más de 200 comandos, incluidos los que ejecutan scripts de Lua. Sin embargo, en lo que respecta a los scripts de Lua, hay varios inconvenientes que pueden afectar a la memoria y a la disponibilidad de Valkey o Redis OSS.

**Scripts de Lua no parametrizados**

Cada script de Lua se almacena en caché en el servidor de Valkey o Redis OSS antes de ejecutarse. Los scripts de Lua no parametrizados son únicos, lo que puede provocar que el servidor de Valkey o Redis OSS almacene una gran cantidad de ellos y consuma más memoria. Para mitigar esta situación, asegúrese de que todos los scripts de Lua estén parametrizados y ejecute SCRIPT FLUSH con regularidad a fin de depurar los scripts de Lua almacenados en caché si es necesario.

También tenga en cuenta que se deben proporcionar claves. Si no se proporciona ningún valor para el parámetro KEY, el script fallará. Por ejemplo, lo siguiente no funcionará: 

```
serverless-test-lst4hg.serverless.use1.cache.amazonaws.com:6379> eval 'return "Hello World"' 0
(error) ERR Lua scripts without any input keys are not supported.
```

Esto sí funcionará:

```
serverless-test-lst4hg.serverless.use1.cache.amazonaws.com:6379> eval 'return redis.call("get", KEYS[1])' 1 mykey-2
"myvalue-2"
```

En el siguiente ejemplo, se muestra cómo definir y utilizar parámetros: En primer lugar, tenemos el ejemplo de un método no parametrizado que da como resultado tres scripts de Lua en caché diferentes (no recomendable):

```
eval "return redis.call('set','key1','1')" 0
eval "return redis.call('set','key2','2')" 0
eval "return redis.call('set','key3','3')" 0
```

En lugar de esto, utilice el siguiente patrón para crear un único script que pueda aceptar los parámetros pasados:

```
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 key1 1 
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 key2 2 
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 key3 3
```

**Scripts de Lua de larga duración**

Los scripts de Lua pueden ejecutar varios comandos de forma atómica, por lo que pueden tardar más en completarse que un comando normal de Valkey o Redis OSS. Si el script de Lua solo ejecuta operaciones de solo lectura, puede detenerlo durante la ejecución. Sin embargo, cuando el script de Lua lleve a cabo operaciones de escritura, no se puede detener y debe ejecutarse hasta el final. Un script de Lua de ejecución prolongada que esté mutando puede provocar que el servidor de Valkey o Redis OSS deje de responder durante mucho tiempo. Para mitigar este problema, evite el uso de scripts de Lua de larga duración y pruébelos en un entorno de preproducción.

**Script de Lua con escrituras encubiertas**

Aunque Valkey o Redis OSS hayan superado la `maxmemory`, un script de Lua puede seguir escribiendo nuevos datos en Valkey o Redis OSS de varias maneras:
+ El script se inicia cuando el servidor de Valkey o Redis OSS está por debajo de `maxmemory` y contiene varias operaciones de escritura en su interior.
+ El primer comando de escritura del script no consume memoria (como DEL) y va seguido de más operaciones de escritura que sí consumen memoria.
+ Puede mitigar este problema configurando una política de expulsión adecuada en un servidor de Valkey o Redis OSS que no sea `noeviction`. Esto permite que Redis OSS expulse elementos y libere memoria entre los scripts de Lua.

# Almacenamiento de elementos compuestos de gran tamaño (Valkey y Redis OSS)
<a name="BestPractices.Clients.Redis.LargeItems"></a>

En algunos casos, una aplicación puede almacenar elementos compuestos de gran tamaño en Valkey o Redis OSS (como un conjunto de datos hash de varios GB). Esto no es recomendable, ya que suele provocar problemas de rendimiento en Valkey o Redis OSS. Por ejemplo, el cliente puede ejecutar un comando HGETALL para recuperar toda la colección de hash de varios GB. Se puede generar una presión en la memoria importante para el servidor de Valkey o Redis OSS que almacena el elemento de gran tamaño en el búfer de salida del cliente. Además, para la migración de slots en modo clúster, ElastiCache no migra los slots que contienen elementos con un tamaño serializado superior a 256 MB.

Para resolver los problemas implicados en la gestión de elementos de gran tamaño, recomendamos lo siguiente:
+ Divida el elemento compuesto grande en varios elementos más pequeños. Algo que puede hacer es dividir una colección hash grande en campos clave-valor individuales con un esquema de nombres de clave que refleje adecuadamente la colección; por ejemplo, puede utilizar un prefijo común en el nombre de la clave para identificar la colección de elementos. Si debe acceder a varios campos de la misma colección de forma integral, puede usar el comando MGET para recuperar varios valores clave en el mismo comando.
+ Si ha evaluado todas las opciones y sigue sin poder dividir el conjunto de datos de gran tamaño de la colección, intente utilizar comandos que funcionen en un subconjunto de los datos de la colección, en lugar de en toda la colección. Evite los casos de uso que requieran recuperar de forma integral toda la colección de varios GB con el mismo comando. Un ejemplo de esto es el uso de los comandos HGET o HMGET, en lugar de HGETALL, en las colecciones de hash.

# Configuración del cliente de Lettuce (Valkey y Redis OSS)
<a name="BestPractices.Clients-lettuce"></a>

En esta sección se describen las opciones de configuración recomendadas de Java y Lettuce y cómo se aplican a los clústeres de ElastiCache.

Las recomendaciones de esta sección se probaron con la versión 6.2.2 de Lettuce.

**Topics**
+ [Ejemplo: Configuración de Lettuce para el modo de clúster con TLS habilitado](BestPractices.Clients-lettuce-cme.md)
+ [Ejemplo: Configuración de Lettuce para el modo de clúster deshabilitado con TLS habilitado](BestPractices.Clients-lettuce-cmd.md)

**TTL de la caché DNS de Java**

La máquina virtual de Java (JVM) almacena en caché las búsquedas de nombres DNS. Cuando la JVM resuelve un nombre de host en una dirección IP, almacena en caché la dirección IP durante un periodo de tiempo especificado, conocido como *tiempo de vida* (TTL).

La elección del valor de TTL implica un compromiso entre latencia y la capacidad de respuesta a los cambios. Con TTL más cortos, los solucionadores de DNS detectan las actualizaciones en el DNS del clúster con mayor rapidez. Esto puede hacer que la aplicación responda más rápido a las sustituciones u otros flujos de trabajo a los que se somete el clúster. Sin embargo, si el TTL es demasiado bajo, aumenta el volumen de consultas, lo que puede aumentar la latencia de la aplicación. Aunque no existe un valor de TTL correcto, vale la pena esperar a que surta efecto un cambio cuando se configura el valor de TTL.

Como los nodos de ElastiCache utilizan entradas de nombres de DNS que pueden cambiar de vez en cuando, recomendamos que configure JVM con un TTL bajo de 5 a 10 segundos. Con esto, se asegurará de que, cuando cambie la dirección IP de un nodo, su aplicación pueda recibir y utilizar la nueva dirección IP del recurso volviendo a consultar la entrada de DNS.

En algunas configuraciones de Java, el TTL predeterminado de JVM está establecido de forma que nunca se actualicen las entradas DNS hasta que se reinicie la JVM.

Para obtener más información sobre cómo configurar el TTL de JVM, consulte [Cómo configurar el TTL de JVM](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-jvm-ttl.html#how-to-set-the-jvm-ttl).

**Versión de Lettuce**

Recomendamos usar la versión 6.2.2 o posterior de Lettuce.

**puntos de conexión**

Cuando utilice clústeres habilitados para el modo de clúster, establezca `redisUri` en el punto de conexión de configuración del clúster. La búsqueda de DNS para este URI devuelve una lista de todos los nodos disponibles en el clúster y se resuelve aleatoriamente en uno de ellos durante la inicialización del clúster. Para obtener más información sobre cómo funciona la actualización de topología, consulte *dynamicRefreshResources* más adelante en este tema.

**SocketOption**

Habilite [KeepAlive](https://lettuce.io/core/release/api/io/lettuce/core/SocketOptions.KeepAliveOptions.html). Al habilitar esta opción, se reduce la necesidad de gestionar las conexiones erróneas durante el tiempo de ejecución del comando.

Asegúrese de configurar el [Tiempo de espera de la conexión](https://lettuce.io/core/release/api/io/lettuce/core/SocketOptions.Builder.html#connectTimeout-java.time.Duration-) en función de los requisitos de la aplicación y la carga de trabajo. Para obtener más información, consulte la sección de tiempos de espera más adelante en este tema.

**ClusterClientOption: Opciones de cliente habilitadas para el modo de clúster**

Habilite [AutoReconnect](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterClientOptions.Builder.html#autoReconnect-boolean-) cuando se pierda la conexión.

Establezca [CommandTimeout](https://lettuce.io/core/release/api/io/lettuPrce/core/RedisURI.html#getTimeout--). Para obtener más información, consulte la sección Tiempos de espera más adelante en este tema.

Establezca [nodeFilter](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterClientOptions.Builder.html#nodeFilter-java.util.function.Predicate-) para filtrar los nodos con errores de la topología. Lettuce guarda todos los nodos que se encuentran en la salida de los “nodos del clúster” (incluidos los nodos con el estado PFAIL/FAIL) en las “particiones” del cliente. Durante el proceso de creación de la topología del clúster, intenta conectarse a todos los nodos de partición. Este comportamiento de Lettuce de agregar nodos con errores puede provocar errores de conexión (o advertencias) cuando los nodos se sustituyen por cualquier motivo. 

Por ejemplo, una vez que finaliza una conmutación por error y el clúster inicia el proceso de recuperación, mientras se actualiza la topología del clúster, el mapa de nodos del bus del clúster tiene un breve periodo de tiempo en el que el nodo inactivo se muestra como nodo FAIL, antes de que se elimine por completo de la topología. Durante este periodo, el cliente de Lettuce lo considera un nodo en buen estado y se conecta continuamente a él. Esto provoca un error cuando se agota el reintento. 

Por ejemplo:

```
final ClusterClientOptions clusterClientOptions = 
    ClusterClientOptions.builder()
    ... // other options
    .nodeFilter(it -> 
        ! (it.is(RedisClusterNode.NodeFlag.FAIL) 
        || it.is(RedisClusterNode.NodeFlag.EVENTUAL_FAIL) 
        || it.is(RedisClusterNode.NodeFlag.HANDSHAKE)
        || it.is(RedisClusterNode.NodeFlag.NOADDR)))
    .validateClusterNodeMembership(false)
    .build();
redisClusterClient.setOptions(clusterClientOptions);
```

**nota**  
El filtrado de nodos se utiliza mejor con DynamicRefreshSources configurado en verdadero. De lo contrario, si la vista de topología se toma de un solo nodo raíz problemático, que ve que un nodo principal de alguna partición está produciendo un error, filtrará este nodo principal, lo que hará que las ranuras no queden cubiertas. Tener varios nodos raíz (cuando DynamicRefreshSources es verdadero) reduce la probabilidad de que se produzca este problema, ya que al menos algunos de los nodos raíz deberían tener una vista de topología actualizada después de una conmutación por error con el nodo principal recién promocionado.

**ClusterTopologyRefreshOptions: opciones para controlar la actualización de la topología del clúster del cliente habilitado para el modo de clúster**

**nota**  
Los clústeres desactivados en modo de clúster no admiten los comandos de detección de clústeres y no son compatibles con la funcionalidad de detección de topología dinámica de todos los clientes.  
El modo de clúster desactivado con ElastiCache no es compatible con `MasterSlaveTopologyRefresh` de Lettuce. En cambio, para el modo de clúster desactivado puede configurar `StaticMasterReplicaTopologyProvider` y proporcionar los puntos de conexión de lectura y escritura del clúster.  
Para obtener más información acerca de la conexión a clústeres desactivados en modo de clúster, consulte [Búsqueda de puntos de conexión de un clúster de Valkey o Redis OSS (modo de clúster deshabilitado) (consola)](Endpoints.md#Endpoints.Find.Redis).  
Si desea utilizar la funcionalidad de detección de topología dinámica de Lettuce, puede crear un clúster habilitado para el modo de clúster con la configuración del mismo fragmento que el clúster existente. Sin embargo, para los clústeres habilitados para el modo de clúster, recomendamos configurar al menos 3 particiones con al menos 1 réplica para admitir una conmutación por error rápida.

Habilite [enablePeriodicRefresh](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#enablePeriodicRefresh-java.time.Duration-). Esto permite las actualizaciones periódicas de la topología del clúster para que el cliente actualice la topología del clúster en los intervalos del periodo de actualización (predeterminado: 60 segundos). Cuando están desactivadas, el cliente actualiza la topología del clúster solo cuando se producen errores al intentar ejecutar comandos en el clúster. 

Con esta opción habilitada, puede reducir la latencia asociada a la actualización de la topología del clúster agregando este trabajo a una tarea que se esté ejecutando en segundo plano. Aunque la actualización de la topología se realiza en un trabajo que se esté ejecutando en segundo plano, puede resultar algo lenta para los clústeres con muchos nodos. Esto se debe a que se están consultando las vistas de todos los nodos para obtener la vista de clúster más actualizada. Si ejecuta un clúster grande, es posible que desee aumentar el periodo.

Habilite [enableAllAdaptiveRefreshTriggers](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#enableAllAdaptiveRefreshTriggers--). Esto permite actualizar la topología adaptativa y utilizar todos los [disparadores](https://lettuce.io/core/6.1.6.RELEASE/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.RefreshTrigger.html): MOVED\$1REDIRECT, ASK\$1REDIRECT, PERSISTENT\$1RECONNECTS, UNCOVERED\$1SLOT, UNKNOWN\$1NODE. Los desencadenadores de actualización adaptativa inician las actualizaciones de la vista de topología en función de los eventos que se producen durante las operaciones de clúster de Valkey y Redis OSS. Al habilitar esta opción, se actualiza inmediatamente la topología cuando se activa uno de los desencadenadores anteriores. Las actualizaciones desencadenadas adaptativas tienen un límite de velocidad mediante un tiempo de espera porque los eventos se pueden producir a gran escala (tiempo de espera predeterminado entre actualizaciones: 30).

Habilite [closeStaleConnections](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#closeStaleConnections-boolean-). Esto permite cerrar las conexiones obsoletas al actualizar la topología del clúster. Solo entra en vigor si [ClusterTopologyRefreshOptions.isPeriodicRefreshEnabled()](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.html#isPeriodicRefreshEnabled--) es verdadero. Cuando se habilita, el cliente puede cerrar las conexiones obsoletas y crear otras nuevas en segundo plano. Esto reduce la necesidad de gestionar las conexiones erróneas durante el tiempo de ejecución del comando.

Habilite [dynamicRefreshResources](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#dynamicRefreshSources-boolean-). Recomendamos habilitar dynamicRefreshResources para clústeres pequeños y desactivarlo para clústeres grandes. dynamicRefreshResources permite detectar los nodos del clúster desde el nodo raíz proporcionado (por ejemplo, el punto de conexión de configuración del clúster). Utiliza todos los nodos detectados como orígenes para actualizar la topología del clúster. 

El uso de la actualización dinámica consulta todos los nodos detectados para la topología del clúster e intenta elegir la vista de clúster más precisa. Si se establece en falso, solo se utilizan los nodos raíz iniciales como orígenes para la detección de la topología y el número de clientes se obtiene solo para los nodos raíz iniciales. Cuando se desactiva, si el punto de conexión de la configuración del clúster se resuelve como un nodo con errores, se produce un error al intentar actualizar la vista del clúster y se producen excepciones. Este escenario se puede producir porque pasa algún tiempo hasta que la entrada de un nodo con errores se elimina del punto de conexión de la configuración del clúster. Por lo tanto, el punto de conexión de la configuración aún se puede resolver aleatoriamente en un nodo erróneo durante un breve periodo de tiempo. 

Sin embargo, cuando se habilita, utilizamos todos los nodos del clúster que se reciben de la vista de clústeres para consultar la vista actual. Como filtramos los nodos con errores de esa vista, la actualización de la topología se realizará correctamente. Sin embargo, cuando dynamicRefreshSources es verdadero, Lettuce consulta todos los nodos para obtener la vista del clúster y, a continuación, compara los resultados. Por lo tanto, puede resultar caro para los clústeres con muchos nodos. Le sugerimos que desactive esta característica para los clústeres con muchos nodos. 

```
final ClusterTopologyRefreshOptions topologyOptions = 
    ClusterTopologyRefreshOptions.builder()
    .enableAllAdaptiveRefreshTriggers()
    .enablePeriodicRefresh()
    .dynamicRefreshSources(true)
    .build();
```

**ClientResources**

Configure [DnsResolver](https://lettuce.io/core/release/api/io/lettuce/core/resource/DefaultClientResources.Builder.html#dnsResolver-io.lettuce.core.resource.DnsResolver-) con [DirContextDnsResolver](https://lettuce.io/core/release/api/io/lettuce/core/resource/DirContextDnsResolver.html). El servicio de resolución de DNS se basa en com.sun.jndi.dns.DnsContextFactory de Java.

Configure [reconnectDelay](https://lettuce.io/core/release/api/io/lettuce/core/resource/DefaultClientResources.Builder.html#reconnectDelay-io.lettuce.core.resource.Delay-) con retroceso exponencial y fluctuación total. Lettuce tiene mecanismos de reintento integrados basados en las estrategias de retroceso exponencial. Para obtener más información, consulte [Retroceso exponencial y fluctuación](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter) en el blog de arquitectura de AWS. Para obtener más información sobre la importancia de contar con una estrategia de reintento, consulte las secciones sobre lógica de retraso de la [Publicación del blog sobre mejores prácticas](https://aws.amazon.com/blogs/database/best-practices-redis-clients-and-amazon-elasticache-for-redis/) en el blog de base de datos de AWS.

```
ClientResources clientResources = DefaultClientResources.builder()
   .dnsResolver(new DirContextDnsResolver())
    .reconnectDelay(
        Delay.fullJitter(
            Duration.ofMillis(100),     // minimum 100 millisecond delay
            Duration.ofSeconds(10),      // maximum 10 second delay
            100, TimeUnit.MILLISECONDS)) // 100 millisecond base
    .build();
```

**Tiempos de espera**

Utilice un valor de tiempo de espera de conexión inferior al tiempo de espera del comando. Lettuce utiliza un establecimiento de conexión diferida. Por lo tanto, si el tiempo de espera de conexión es superior al tiempo de espera del comando, puede producirse un periodo de error persistente tras una actualización de la topología si Lettuce intenta conectarse a un nodo en mal estado y siempre se supera el tiempo de espera del comando. 

Utilice un tiempo de espera de comando dinámico para diferentes comandos. Le recomendamos que establezca el tiempo de espera del comando en función de la duración esperada del comando. Por ejemplo, utilice un tiempo de espera más largo para los comandos que se repiten en varias claves, como los scripts FLUSHDB, FLUSHALL, KEYS, SMEMBERS o Lua. Utilice tiempos de espera más cortos para los comandos de una sola clave, como SET, GET y HSET.

**nota**  
Los tiempos de espera que se configuran en el siguiente ejemplo son para pruebas que ejecutaron comandos SET/GET con claves y valores de hasta 20 bytes de longitud. El tiempo de procesamiento puede ser mayor cuando los comandos son complejos o las claves y los valores son más grandes. Debe establecer los tiempos de espera en función del caso de uso de la aplicación. 

```
private static final Duration META_COMMAND_TIMEOUT = Duration.ofMillis(1000);
private static final Duration DEFAULT_COMMAND_TIMEOUT = Duration.ofMillis(250);
// Socket connect timeout should be lower than command timeout for Lettuce
private static final Duration CONNECT_TIMEOUT = Duration.ofMillis(100);
    
SocketOptions socketOptions = SocketOptions.builder()
    .connectTimeout(CONNECT_TIMEOUT)
    .build();
 

class DynamicClusterTimeout extends TimeoutSource {
     private static final Set<ProtocolKeyword> META_COMMAND_TYPES = ImmutableSet.<ProtocolKeyword>builder()
          .add(CommandType.FLUSHDB)
          .add(CommandType.FLUSHALL)
          .add(CommandType.CLUSTER)
          .add(CommandType.INFO)
          .add(CommandType.KEYS)
          .build();

    private final Duration defaultCommandTimeout;
    private final Duration metaCommandTimeout;

    DynamicClusterTimeout(Duration defaultTimeout, Duration metaTimeout)
    {
        defaultCommandTimeout = defaultTimeout;
        metaCommandTimeout = metaTimeout;
    }

    @Override
    public long getTimeout(RedisCommand<?, ?, ?> command) {
        if (META_COMMAND_TYPES.contains(command.getType())) {
            return metaCommandTimeout.toMillis();
        }
        return defaultCommandTimeout.toMillis();
    }
}

// Use a dynamic timeout for commands, to avoid timeouts during
// cluster management and slow operations.
TimeoutOptions timeoutOptions = TimeoutOptions.builder()
.timeoutSource(
    new DynamicClusterTimeout(DEFAULT_COMMAND_TIMEOUT, META_COMMAND_TIMEOUT))
.build();
```

# Ejemplo: Configuración de Lettuce para el modo de clúster con TLS habilitado
<a name="BestPractices.Clients-lettuce-cme"></a>

**nota**  
Los tiempos de espera del siguiente ejemplo son para pruebas que ejecutaron comandos SET/GET con claves y valores de hasta 20 bytes de longitud. El tiempo de procesamiento puede ser mayor cuando los comandos son complejos o las claves y los valores son más grandes. Debe establecer los tiempos de espera en función del caso de uso de la aplicación. 

```
// Set DNS cache TTL
public void setJVMProperties() {
    java.security.Security.setProperty("networkaddress.cache.ttl", "10");
}

private static final Duration META_COMMAND_TIMEOUT = Duration.ofMillis(1000);
private static final Duration DEFAULT_COMMAND_TIMEOUT = Duration.ofMillis(250);
// Socket connect timeout should be lower than command timeout for Lettuce
private static final Duration CONNECT_TIMEOUT = Duration.ofMillis(100);

// Create RedisURI from the cluster configuration endpoint
clusterConfigurationEndpoint = <cluster-configuration-endpoint> // TODO: add your cluster configuration endpoint
final RedisURI redisUriCluster =
    RedisURI.Builder.redis(clusterConfigurationEndpoint)
        .withPort(6379)
        .withSsl(true)
        .build();

// Configure the client's resources                
ClientResources clientResources = DefaultClientResources.builder()
    .reconnectDelay(
        Delay.fullJitter(
            Duration.ofMillis(100),     // minimum 100 millisecond delay
            Duration.ofSeconds(10),      // maximum 10 second delay
            100, TimeUnit.MILLISECONDS)) // 100 millisecond base
    .dnsResolver(new DirContextDnsResolver())
    .build(); 

// Create a cluster client instance with the URI and resources
RedisClusterClient redisClusterClient = 
    RedisClusterClient.create(clientResources, redisUriCluster);

// Use a dynamic timeout for commands, to avoid timeouts during
// cluster management and slow operations.
class DynamicClusterTimeout extends TimeoutSource {
     private static final Set<ProtocolKeyword> META_COMMAND_TYPES = ImmutableSet.<ProtocolKeyword>builder()
          .add(CommandType.FLUSHDB)
          .add(CommandType.FLUSHALL)
          .add(CommandType.CLUSTER)
          .add(CommandType.INFO)
          .add(CommandType.KEYS)
          .build();

    private final Duration metaCommandTimeout;
    private final Duration defaultCommandTimeout;

    DynamicClusterTimeout(Duration defaultTimeout, Duration metaTimeout)
    {
        defaultCommandTimeout = defaultTimeout;
        metaCommandTimeout = metaTimeout;
    }

    @Override
    public long getTimeout(RedisCommand<?, ?, ?> command) {
        if (META_COMMAND_TYPES.contains(command.getType())) {
            return metaCommandTimeout.toMillis();
        }
        return defaultCommandTimeout.toMillis();
    }
}

TimeoutOptions timeoutOptions = TimeoutOptions.builder()
    .timeoutSource(new DynamicClusterTimeout(DEFAULT_COMMAND_TIMEOUT, META_COMMAND_TIMEOUT))
     .build();

// Configure the topology refreshment options
final ClusterTopologyRefreshOptions topologyOptions = 
    ClusterTopologyRefreshOptions.builder()
    .enableAllAdaptiveRefreshTriggers()
    .enablePeriodicRefresh()
    .dynamicRefreshSources(true)
    .build();

// Configure the socket options
final SocketOptions socketOptions = 
    SocketOptions.builder()
    .connectTimeout(CONNECT_TIMEOUT) 
    .keepAlive(true)
    .build();

// Configure the client's options
final ClusterClientOptions clusterClientOptions = 
    ClusterClientOptions.builder()
    .topologyRefreshOptions(topologyOptions)
    .socketOptions(socketOptions)
    .autoReconnect(true)
    .timeoutOptions(timeoutOptions) 
    .nodeFilter(it -> 
        ! (it.is(RedisClusterNode.NodeFlag.FAIL) 
        || it.is(RedisClusterNode.NodeFlag.EVENTUAL_FAIL) 
        || it.is(RedisClusterNode.NodeFlag.NOADDR))) 
    .validateClusterNodeMembership(false)
    .build();
    
redisClusterClient.setOptions(clusterClientOptions);

// Get a connection
final StatefulRedisClusterConnection<String, String> connection = 
    redisClusterClient.connect();

// Get cluster sync/async commands   
RedisAdvancedClusterCommands<String, String> sync = connection.sync();
RedisAdvancedClusterAsyncCommands<String, String> async = connection.async();
```

# Ejemplo: Configuración de Lettuce para el modo de clúster deshabilitado con TLS habilitado
<a name="BestPractices.Clients-lettuce-cmd"></a>

**nota**  
Los tiempos de espera del siguiente ejemplo son para pruebas que ejecutaron comandos SET/GET con claves y valores de hasta 20 bytes de longitud. El tiempo de procesamiento puede ser mayor cuando los comandos son complejos o las claves y los valores son más grandes. Debe establecer los tiempos de espera en función del caso de uso de la aplicación. 

```
// Set DNS cache TTL
public void setJVMProperties() {
    java.security.Security.setProperty("networkaddress.cache.ttl", "10");
}

private static final Duration META_COMMAND_TIMEOUT = Duration.ofMillis(1000);
private static final Duration DEFAULT_COMMAND_TIMEOUT = Duration.ofMillis(250);
// Socket connect timeout should be lower than command timeout for Lettuce
private static final Duration CONNECT_TIMEOUT = Duration.ofMillis(100);

// Create RedisURI from the primary/reader endpoint
clusterEndpoint = <primary/reader-endpoint> // TODO: add your node endpoint
RedisURI redisUriStandalone =
    RedisURI.Builder.redis(clusterEndpoint).withPort(6379).withSsl(true).withDatabase(0).build();

ClientResources clientResources =
    DefaultClientResources.builder()
        .dnsResolver(new DirContextDnsResolver())
        .reconnectDelay(
            Delay.fullJitter(
                Duration.ofMillis(100), // minimum 100 millisecond delay
                Duration.ofSeconds(10), // maximum 10 second delay
                100,
                TimeUnit.MILLISECONDS)) // 100 millisecond base
        .build();

// Use a dynamic timeout for commands, to avoid timeouts during
// slow operations.
class DynamicTimeout extends TimeoutSource {
     private static final Set<ProtocolKeyword> META_COMMAND_TYPES = ImmutableSet.<ProtocolKeyword>builder()
          .add(CommandType.FLUSHDB)
          .add(CommandType.FLUSHALL)
          .add(CommandType.INFO)
          .add(CommandType.KEYS)
          .build();

    private final Duration metaCommandTimeout;
    private final Duration defaultCommandTimeout;

    DynamicTimeout(Duration defaultTimeout, Duration metaTimeout)
    {
        defaultCommandTimeout = defaultTimeout;
        metaCommandTimeout = metaTimeout;
    }

    @Override
    public long getTimeout(RedisCommand<?, ?, ?> command) {
        if (META_COMMAND_TYPES.contains(command.getType())) {
            return metaCommandTimeout.toMillis();
        }
        return defaultCommandTimeout.toMillis();
    }
}

TimeoutOptions timeoutOptions = TimeoutOptions.builder()
    .timeoutSource(new DynamicTimeout(DEFAULT_COMMAND_TIMEOUT, META_COMMAND_TIMEOUT))
     .build();                      
                                    
final SocketOptions socketOptions =
    SocketOptions.builder().connectTimeout(CONNECT_TIMEOUT).keepAlive(true).build();

ClientOptions clientOptions =
    ClientOptions.builder().timeoutOptions(timeoutOptions).socketOptions(socketOptions).build();

RedisClient redisClient = RedisClient.create(clientResources, redisUriStandalone);
redisClient.setOptions(clientOptions);
```

## Configuración de un protocolo preferido para clústeres de doble pila (Valkey y Redis OSS)
<a name="network-type-configuring-dual-stack-redis"></a>

En el caso de los clústeres de Valkey o Redis OSS habilitados para el modo de clúster, puede controlar el protocolo que los clientes utilizarán para conectarse a los nodos del clúster con el parámetro de detección de IP. El parámetro de detección de IP se puede establecer en IPv4 o IPv6. 

Para los clústeres de Valkey o Redis OSS, el parámetro de detección de IP establece el protocolo IP utilizado en la salida de las [ranuras del clúster ()](https://valkey.io/commands/cluster-slots/), las [particiones del clúster ()](https://valkey.io/commands/cluster-shards/) y los [nodos del clúster ()](https://valkey.io/commands/cluster-nodes/). Los clientes utilizan estos comandos para detectar la topología del clúster. Los clientes usan las IP de estos comandos para conectarse a los otros nodos del clúster. 

Cambiar la detección de IP no provocará ningún tiempo de inactividad para los clientes conectados. Sin embargo, los cambios tardarán algún tiempo en propagarse. Para determinar cuándo los cambios se han propagado por completo para un clúster de Valkey o Redis OSS, supervise la salida de `cluster slots`. Una vez que todos los nodos devueltos por el comando de ranuras del clúster registren las IP con el nuevo protocolo, los cambios terminarán de propagarse. 

Ejemplo con Redis-Py:

```
cluster = RedisCluster(host="xxxx", port=6379)
target_type = IPv6Address # Or IPv4Address if changing to IPv4

nodes = set()
while len(nodes) == 0 or not all((type(ip_address(host)) is target_type) for host in nodes):
    nodes = set()

   # This refreshes the cluster topology and will discovery any node updates.
   # Under the hood it calls cluster slots
    cluster.nodes_manager.initialize()
    for node in cluster.get_nodes():
        nodes.add(node.host)
    self.logger.info(nodes)

    time.sleep(1)
```

Ejemplo con Lettuce:

```
RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.create("xxxx", 6379));

Class targetProtocolType = Inet6Address.class; // Or Inet4Address.class if you're switching to IPv4

Set<String> nodes;
    
do {
   // Check for any changes in the cluster topology.
   // Under the hood this calls cluster slots
    clusterClient.refreshPartitions();
    Set<String> nodes = new HashSet<>();

    for (RedisClusterNode node : clusterClient.getPartitions().getPartitions()) {
        nodes.add(node.getUri().getHost());
    }

    Thread.sleep(1000);
} while (!nodes.stream().allMatch(node -> {
            try {
                return finalTargetProtocolType.isInstance(InetAddress.getByName(node));
            } catch (UnknownHostException ignored) {}
            return false;
}));
```

# Prácticas recomendadas para clientes (Memcached)
<a name="BestPractices.Clients.memcached"></a>

Conozca las prácticas recomendadas para escenarios comunes con clústeres de ElastiCache para Memcached.

**Topics**
+ [Configuración de su ElastiCache cliente para un equilibrio de carga eficiente (Memcached)](BestPractices.LoadBalancing.md)
+ [Clientes validados con Memcached](network-type-validated-clients-memcached.md)
+ [Configuración de un protocolo preferido para clústeres de doble pila (Memcached)](network-type-configuring-dual-stack-memcached.md)

# Configuración de su ElastiCache cliente para un equilibrio de carga eficiente (Memcached)
<a name="BestPractices.LoadBalancing"></a>

**nota**  
Esta sección se aplica a clústeres de Memcached de varios nodos basados en nodos.

Para utilizar de forma eficaz varios nodos de ElastiCache Memcached, debe poder distribuir las claves de caché entre los nodos. Una manera sencilla de equilibrar la carga de un clúster con *n* nodos es calcular el hash de la clave del objeto y aplicar la función mod al resultado mediante *n*: `hash(key) mod n`. El valor resultante (de 0 a *n*-1) es el número del nodo en el que deberá colocar el objeto. 

Este enfoque es sencillo y funciona bien siempre que el número de nodos (*n*) sea constante. Sin embargo, siempre que agregue o elimine un nodo del clúster, el número de claves que deben moverse será *(n (1)/n* (donde *n* es el nuevo número de nodos). Por lo tanto, este enfoque da como resultado el traslado de un gran número de claves, lo que se traduce en un gran número de pérdidas iniciales de caché, especialmente cuando el número de nodos es elevado. En el mejor de los casos, al escalar de 1 a 2 resultados de nodos, se obtienen (2-1)/2 (50 %) de claves para trasladar. Al escalar de 9 a 10 nodos, se obtienen (10-1)/10 (90 %) de claves para trasladar. Si va a ampliar debido a un pico de tráfico, no deseará tener muchas pérdidas de caché. Un gran número de pérdidas de caché devuelve coincidencias con la base de datos, que ya está sobrecargada por el pico de tráfico.

La solución a este dilema es un uso consistente de la función hash. Una utilización consistente de hash emplea un algoritmo según el cual, siempre que se agregue o elimine un nodo de un clúster, el número de claves que deba moverse será aproximadamente *1/n* (donde *n* es el número de nodos nuevo). En el peor de los casos, al escalar de 1 a 2 resultados de nodos, se obtienen 1/2 (50 por ciento) de claves para trasladar. Al escalar de 9 a 10 nodos, se obtienen 1/10 (10 por ciento) de claves para trasladar.

Como usuario, deberá controlar qué algoritmo de hash se usa para los clústeres de varios nodos. Recomendamos configurar sus clientes para que utilicen hash de forma consistente. Afortunadamente, hay muchas bibliotecas de cliente de Memcached en la mayoría de los idiomas comunes que implementan hash de forma consistente. Consulte la documentación de la biblioteca que va a utilizar para ver si admite el uso consistente de hash y saber cómo implementarlo.

Si trabaja en Java, PHP o.NET, le recomendamos que utilice una de las bibliotecas ElastiCache cliente de Amazon.

## Uso consistente de hash con Java
<a name="BestPractices.LoadBalancing.Java"></a>

El cliente Java de ElastiCache Memcached se basa en el cliente Java spymemcached de código abierto, que incorpora funciones de hash consistentes. La biblioteca incluye una clase que implementa un hash coherente. KetamaConnectionFactory De forma predeterminada, el uso consistente de hash está desactivado en spymemcached.

Para obtener más información, consulte la KetamaConnectionFactory documentación en [KetamaConnectionFactory](https://github.com/RTBHOUSE/spymemcached/blob/master/src/main/java/net/spy/memcached/KetamaConnectionFactory.java).

## Uso consistente de hash utilizando PHP con Memcached
<a name="BestPractices.LoadBalancing.PHP"></a>

El cliente PHP de ElastiCache Memcached es un contenedor de la biblioteca PHP integrada de Memcached. De forma predeterminada, el uso consistente de hash está desactivado en la biblioteca PHP de Memcached.

Utilice el siguiente código para habilitar el uso consistente de hash.

```
$m = new Memcached();
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
```

Además del código anterior, recomendamos habilitar también `memcached.sess_consistent_hash` en su archivo php.ini.

 [Para obtener más información, consulte la documentación de configuración en tiempo de ejecución de Memcached PHP en http://php. net/manual/en/memcached.configuración.php.](http://php.net/manual/en/memcached.configuration.php) Tenga en cuenta específicamente el parámetro `memcached.sess_consistent_hash`.

## Uso consistente de hash utilizando .NET con Memcached
<a name="BestPractices.LoadBalancing.dotNET"></a>

El cliente.NET de ElastiCache Memcached es un envoltorio de Enyim Memcached. De forma predeterminada, el uso consistente de hash está habilitado en el cliente Enyim Memcached.

 [Para obtener más información, consulte la documentación en -Configuration\$1. `memcached/locator` https://github.com/enyim/ EnyimMemcached/wiki/MemcachedClient user-content-memcachedlocator](https://github.com/enyim/EnyimMemcached/wiki/MemcachedClient-Configuration#user-content-memcachedlocator)

# Clientes validados con Memcached
<a name="network-type-validated-clients-memcached"></a>

Los siguientes clientes se han validado específicamente para funcionar con todas las configuraciones de tipo de red admitidas para Memcached.

Clientes validados:
+ [AWS ElastiCache Cluster Client Memcached para Php](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-php): [versión \$13.6.2](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-php/tree/v3.2.0)
+ [AWS ElastiCache Cluster Client Memcached para Java](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-java): versión principal más reciente en Github

# Configuración de un protocolo preferido para clústeres de doble pila (Memcached)
<a name="network-type-configuring-dual-stack-memcached"></a>

Para los clústeres de Memcached, puede controlar el protocolo que los clientes utilizarán para conectarse a los nodos del clúster con el parámetro de detección de IP. El parámetro de detección de IP se puede establecer en IPv4 o IPv6. 

El parámetro de detección de IP controla el protocolo IP utilizado en la salida del clúster config get. Lo que, a su vez, determinará el protocolo IP utilizado por los clientes que admiten la detección automática de clústeres de ElastiCache para Memcached.

Cambiar la detección de IP no provocará ningún tiempo de inactividad para los clientes conectados. Sin embargo, los cambios tardarán algún tiempo en propagarse. 

Monitoree la salida de `getAvailableNodeEndPoints` para Java y para que Php monitoree la salida de `getServerList`. Una vez que la salida de estas funciones registre las IP de todos los nodos del clúster que utilizan el protocolo actualizado, los cambios terminarán de propagarse.

Ejemplo de Java:

```
MemcachedClient client = new MemcachedClient(new InetSocketAddress("xxxx", 11211));

Class targetProtocolType = Inet6Address.class; // Or Inet4Address.class if you're switching to IPv4

Set<String> nodes;
    
do {
    nodes = client.getAvailableNodeEndPoints().stream().map(NodeEndPoint::getIpAddress).collect(Collectors.toSet());

    Thread.sleep(1000);
} while (!nodes.stream().allMatch(node -> {
            try {
                return finalTargetProtocolType.isInstance(InetAddress.getByName(node));
            } catch (UnknownHostException ignored) {}
            return false;
        }));
```

Ejemplo de Php:

```
$client = new Memcached;
$client->setOption(Memcached::OPT_CLIENT_MODE, Memcached::DYNAMIC_CLIENT_MODE);
$client->addServer("xxxx", 11211);

$nodes = [];
$target_ips_count = 0;
do {
    # The PHP memcached client only updates the server list if the polling interval has expired and a
    # command is sent
    $client->get('test');
 
    $nodes = $client->getServerList();

    sleep(1);
    $target_ips_count = 0;

    // For IPv4 use FILTER_FLAG_IPV4
    $target_ips_count = count(array_filter($nodes, function($node) { return filter_var($node["ipaddress"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); }));
 
} while (count($nodes) !== $target_ips_count);
```

Todas las conexiones de cliente existentes que se crearon antes de que se actualizara la detección de IP seguirán conectadas mediante el protocolo anterior. Todos los clientes validados se volverán a conectar automáticamente al clúster mediante el nuevo protocolo IP una vez que se detecten los cambios en el resultado de los comandos de detección del clúster. Sin embargo, esto depende de la implementación del cliente.

## Clústeres de ElastiCache de doble pila compatibles con TLS
<a name="network-type-configuring-tls-enabled-dual-stack"></a>

Cuando se habilita TLS para los clústeres de ElastiCache, las funciones de detección de clústeres (`cluster slots`, `cluster shards` y `cluster nodes` para Redis) o `config get cluster` para Memcached devuelven nombres de host en lugar de IP. A continuación, se utilizan los nombres de host en lugar de las IP para conectarse al clúster de ElastiCache y realizar un protocolo de enlace TLS. Esto significa que los clientes no se verán afectados por el parámetro de detección de IP. En el caso de los clústeres habilitados para TLS, el parámetro de detección de IP no tiene ningún efecto en el protocolo IP preferido. En cambio, el protocolo IP utilizado se determinará según el protocolo IP que prefiera el cliente al resolver los nombres de host de DNS.

**Clientes de Java**

Al conectarse desde un entorno de Java que admite IPv4 e IPv6, Java preferirá de forma predeterminada IPv4 en lugar de IPv6 por motivos de compatibilidad con versiones anteriores. Sin embargo, la preferencia del protocolo IP se puede configurar mediante los argumentos de JVM. Para preferir IPv4, JVM acepta `-Djava.net.preferIPv4Stack=true` y para preferir IPv6 establece `-Djava.net.preferIPv6Stack=true`. La configuración de `-Djava.net.preferIPv4Stack=true` significa que JVM ya no realizará ninguna conexión IPv6. **En el caso de Valkey o Redis OSS, esto incluye a otras aplicaciones que no son de Valkey ni de Redis OSS.**

**Preferencias de nivel de host**

En general, si el cliente o el entorno de ejecución del cliente no ofrecen opciones de configuración para establecer una preferencia de protocolo IP, al realizar la resolución de DNS, el protocolo IP dependerá de la configuración del host. De forma predeterminada, la mayoría de los hosts prefieren IPv6 en lugar de IPv4, pero esta preferencia se puede establecer en el nivel de host. Esto afectará a todas las solicitudes de DNS de ese host, no solo a las dirigidas a los clústeres de ElastiCache.

**Hosts de Linux**

Para Linux, se puede configurar una preferencia de protocolo IP modificando el archivo `gai.conf`. El archivo `gai.conf` se encuentra en `/etc/gai.conf`. Si no se especifica `gai.conf`, debería haber disponible un ejemplo en `/usr/share/doc/glibc-common-x.xx/gai.conf` que se pueda copiar a `/etc/gai.conf`. Además, la configuración predeterminada no debe estar comentada. Si desea actualizar la configuración para preferir IPv4 al conectarse a un clúster de ElastiCache, actualice la prioridad del rango de CIDR que abarca las IP del clúster para que esté por encima de la prioridad de las conexiones IPv6 predeterminadas. De forma predeterminada, las conexiones IPv6 tienen una prioridad de 40. Por ejemplo, suponiendo que el clúster esté ubicado en una subred con el CIDR 172.31.0.0:0/16, la siguiente configuración haría que los clientes prefirieran las conexiones IPv4 a ese clúster.

```
label ::1/128       0
label ::/0          1
label 2002::/16     2
label ::/96         3
label ::ffff:0:0/96 4
label fec0::/10     5
label fc00::/7      6
label 2001:0::/32   7
label ::ffff:172.31.0.0/112 8
#
#    This default differs from the tables given in RFC 3484 by handling
#    (now obsolete) site-local IPv6 addresses and Unique Local Addresses.
#    The reason for this difference is that these addresses are never
#    NATed while IPv4 site-local addresses most probably are.  Given
#    the precedence of IPv6 over IPv4 (see below) on machines having only
#    site-local IPv4 and IPv6 addresses a lookup for a global address would
#    see the IPv6 be preferred.  The result is a long delay because the
#    site-local IPv6 addresses cannot be used while the IPv4 address is
#    (at least for the foreseeable future) NATed.  We also treat Teredo
#    tunnels special.
#
# precedence  <mask>   <value>
#    Add another rule to the RFC 3484 precedence table.  See section 2.1
#    and 10.3 in RFC 3484.  The default is:
#
precedence  ::1/128       50
precedence  ::/0          40
precedence  2002::/16     30
precedence ::/96          20
precedence ::ffff:0:0/96  10
precedence ::ffff:172.31.0.0/112 100
```

Puede encontrar más información disponible sobre `gai.conf` en la [página principal de Linux](https://man7.org/linux/man-pages/man5/gai.conf.5.html) 

**Hosts de Windows**

El proceso para los hosts de Windows es similar. Para los hosts de Windows puede ejecutar `netsh interface ipv6 set prefix CIDR_CONTAINING_CLUSTER_IPS PRECEDENCE LABEL`. Esto tiene el mismo efecto que modificar el archivo `gai.conf` en los hosts de Linux.

Esto actualizará las políticas de preferencias, de modo que se prefieran las conexiones IPv4 en lugar de las conexiones IPv6 para el rango de CIDR especificado. Por ejemplo, suponiendo que el clúster esté en una subred con el CIDR 172.31.0.0:0/16, ejecutar `netsh interface ipv6 set prefix ::ffff:172.31.0.0:0/112 100 15` generaría la siguiente tabla de prioridades, lo que haría que los clientes prefirieran IPv4 al conectarse al clúster. 

```
C:\Users\Administrator>netsh interface ipv6 show prefixpolicies
Querying active state...

Precedence Label Prefix
---------- ----- --------------------------------
100 15 ::ffff:172.31.0.0:0/112
20 4 ::ffff:0:0/96
50 0 ::1/128
40 1 ::/0
30 2 2002::/16
5 5 2001::/32
3 13 fc00::/7
1 11 fec0::/10
1 12 3ffe::/16
1 3 ::/96
```

# Administración de la memoria reservada para Valkey y Redis OSS
<a name="redis-memory-management"></a>

La memoria reservada es una memoria que se aparta del uso para los datos. Cuando se realiza una copia de seguridad o una conmutación por error, Valkey y Redis OSS usan la memoria disponible para registrar las operaciones de escritura en el clúster mientras los datos del clúster se escriben en el archivo .rdb. Si no dispone de suficiente memoria disponible para todas las operaciones de escritura, se produce un error en el proceso. A continuación se ofrece información sobre distintas opciones para administrar la memoria reservada para ElastiCache para Redis OSS y cómo aplicar dichas opciones.

**Topics**
+ [¿Cuánta memoria reservada necesita?](#redis-memory-management-need)
+ [Parámetros de administración de la memoria reservada](#redis-memory-management-parameters)
+ [Especificación del parámetro de administración de memoria reservada](#redis-reserved-memory-management-change)

## ¿Cuánta memoria reservada necesita?
<a name="redis-memory-management-need"></a>

Si ejecuta una versión de Redis OSS anterior a la 2.8.22, reserve más memoria para las copias de seguridad y las conmutaciones por error que si ejecuta la versión 2.8.22 de Redis OSS o posteriores. Este requisito se debe a las distintas maneras que ElastiCache para Redis OSS implementa el proceso de copia de seguridad. La norma general es reservar la mitad del valor de `maxmemory` del tipo de nodo como capacidad adicional para Redis OSS en versiones anteriores a la 2.8.22 y un cuarto de este mismo valor para Redis OSS versión 2.8.22 y posteriores. 

Debido a las diferentes formas en que ElastiCache implementa el proceso de copia de seguridad y replicación, la norma general es reservar el 25 % del valor de `maxmemory` de un tipo de nodo mediante el parámetro `reserved-memory-percent`. Este es el valor predeterminado y el valor recomendado para la mayoría de los casos.

Cuando los tipos de instancia micro y pequeñas ampliables funcionan cerca de los límites de `maxmemory`, es posible que se utilicen intercambios. Para mejorar la fiabilidad operativa en estos tipos de instancia durante las copias de seguridad, la replicación y los momentos de tráfico elevado, recomendamos aumentar el valor del parámetro `reserved-memory-percent` hasta un 30 % en los tipos de instancia pequeños y hasta un 50 % en los tipos de instancia micro.

Para cargas de trabajo con mucho volumen de escritura en clústeres de ElastiCache con organización de datos en niveles, recomendamos aumentar `reserved-memory-percent` hasta un 50 % de la memoria disponible del nodo.

Para obtener más información, consulte los siguientes temas:
+ [Forma de garantizar que dispone de memoria suficiente para crear una instantánea de Valkey o Redis OSS](BestPractices.BGSAVE.md)
+ [Cómo se implementan la sincronización y la copia de seguridad](Replication.Redis.Versions.md)
+ [Organización de datos en niveles en ElastiCache](data-tiering.md)

## Parámetros de administración de la memoria reservada
<a name="redis-memory-management-parameters"></a>

Desde el 16 de marzo de 2017, Amazon ElastiCache proporciona dos parámetros mutuamente excluyentes para administrar la memoria de Valkey o Redis OSS: `reserved-memory` y `reserved-memory-percent`. Ninguno de estos parámetros forma parte de la distribución de Valkey o Redis OSS. 

En función de cuándo haya comenzado a ser cliente de ElastiCache, uno de estos parámetros será el parámetro predeterminado de administración de la memoria. Este parámetro se aplica cuando crea un nuevo clúster o grupo de replicación de Valkey o Redis OSS y utiliza un grupo de parámetros predeterminado. 
+ Para clientes que comenzaron antes del 16 de marzo de 2017: cuando cree un clúster o grupo de replicación de Redis OSS mediante el grupo de parámetros predeterminado, el parámetro de administración de memoria es `reserved-memory`. En este caso, cero (0) bytes de memoria se encuentran reservados. 
+ Para clientes que comenzaron el 16 de marzo de 2017 o después de esa fecha: cuando cree un clúster o grupo de replicación de Valkey o Redis OSS mediante el grupo de parámetros predeterminado, el parámetro de administración de la memoria es `reserved-memory-percent`. En este caso, el 25 % del valor `maxmemory` del nodo se encuentra reservado para fines no relacionados con datos.

Después de leer sobre los dos parámetros de administración de la memoria de Valkey o Redis OSS, puede que prefiera utilizar el que no es el predeterminado o uno con valores no predeterminados. En este caso, puede cambiar al otro parámetro de administración de la memoria reservada. 

Para cambiar el valor de ese parámetro, puede crear un grupo de parámetros personalizado y modificarlo a fin de utilizar el parámetro y el valor de administración de la memoria preferidos. A continuación, podrá usar el grupo de parámetros personalizado cada vez que cree un nuevo clúster o grupo de replicación de Valkey o Redis OSS. Para los clústeres o grupos de reproducción existentes, puede modificarlos para que usen su grupo de parámetros personalizado.

 Para obtener más información, consulte los siguientes temas: 
+ [Especificación del parámetro de administración de memoria reservada](#redis-reserved-memory-management-change)
+ [Creación de un grupo de parámetros de ElastiCache](ParameterGroups.Creating.md)
+ [Modificación de un grupo de parámetros de ElastiCache](ParameterGroups.Modifying.md)
+ [Modificación de un clúster de ElastiCache](Clusters.Modify.md)
+ [Modificación de un grupo de reproducción](Replication.Modify.md)

### Parámetro reserved-memory
<a name="redis-memory-management-parameters-reserved-memory"></a>

Antes del 16 de marzo de 2017, toda la administración de la memoria reservada de ElastiCache para Redis OSS se realizaba con el parámetro `reserved-memory`. El valor predeterminado de `reserved-memory` es 0. Este valor predeterminado no reserva memoria alguna como capacidad adicional para Valkey o Redis OSS y permite que Valkey o Redis OSS consuma toda la memoria de un nodo con datos. 

La modificación del parámetro `reserved-memory` para tener suficiente memoria disponible para las copias de seguridad y las conmutaciones por error requiere crear un grupo de parámetros personalizado. En este grupo de parámetros personalizado, el parámetro `reserved-memory` se establece en un valor adecuado a la versión de Valkey o Redis OSS que ejecuta en su clúster y al tipo de nodo del clúster. Para obtener más información, consulte [¿Cuánta memoria reservada necesita?](#redis-memory-management-need)

El parámetro `reserved-memory` es específico para ElastiCache y no forma parte de la distribución general de Redis OSS.

El procedimiento siguiente muestra cómo usar `reserved-memory` para administrar la memoria en su clúster de Valkey o Redis OSS.

**Para reservar memoria mediante reserved-memory**

1. Cree un grupo de parámetros personalizado especificando la familia del grupo de parámetros que coincide con la versión del motor que está ejecutando, como, por ejemplo, la familia del grupo de parámetros `redis2.8`. Para obtener más información, consulte [Creación de un grupo de parámetros de ElastiCache](ParameterGroups.Creating.md).

   ```
   aws elasticache create-cache-parameter-group \
      --cache-parameter-group-name redis6x-m3xl \
      --description "Redis OSS 2.8.x for m3.xlarge node type" \
      --cache-parameter-group-family redis6.x
   ```

1. Calcule el número de bytes de memoria que se deben reservar para la sobrecarga de Valkey o Redis OSS. Encontrará el valor de `maxmemory` para su tipo de nodo en [Parámetros específicos de tipos de nodos de Redis OSS](ParameterGroups.Engine.md#ParameterGroups.Redis.NodeSpecific).

1. Modifique el grupo de parámetros personalizado de modo que el parámetro `reserved-memory` coincida con el número de bytes que calculó en el paso anterior. En el siguiente ejemplo de la AWS CLI, se da por sentado que ejecuta una versión de Redis OSS anterior a la 2.8.22 y que necesita reservar la mitad del valor de `maxmemory` del nodo. Para obtener más información, consulte [Modificación de un grupo de parámetros de ElastiCache](ParameterGroups.Modifying.md).

   ```
   aws elasticache modify-cache-parameter-group \
      --cache-parameter-group-name redis28-m3xl \
      --parameter-name-values "ParameterName=reserved-memory, ParameterValue=7130316800"
   ```

   Necesita un grupo de parámetros personalizado individual para cada tipo de nodo que utilice, ya que cada tipo de nodo tiene un valor de `maxmemory` distinto. Por lo tanto, cada tipo de nodo necesita un valor diferente para `reserved-memory`.

1. Modifique el clúster o grupo de replicación de Redis OSS de forma que use su grupo de parámetros personalizado.

   En el ejemplo de la CLI siguiente se modifica el clúster ` my-redis-cluster` de forma que comience a usar de inmediato el grupo de parámetros personalizado `redis28-m3xl`. Para obtener más información, consulte [Modificación de un clúster de ElastiCache](Clusters.Modify.md).

   ```
   aws elasticache modify-cache-cluster \
      --cache-cluster-id my-redis-cluster \
      --cache-parameter-group-name redis28-m3xl \
      --apply-immediately
   ```

   En el ejemplo de la CLI siguiente se modifica el grupo de reproducción `my-redis-repl-grp` de forma que comience a usar de inmediato el grupo de parámetros personalizado `redis28-m3xl`. Para obtener más información, [Modificación de un grupo de reproducción](Replication.Modify.md).

   ```
   aws elasticache modify-replication-group \
      --replication-group-id my-redis-repl-grp \
      --cache-parameter-group-name redis28-m3xl \
      --apply-immediately
   ```

### Parámetro reserved-memory-percent
<a name="redis-memory-management-parameters-reserved-memory-percent"></a>

El 16 de marzo de 2017, Amazon ElastiCache presentó el parámetro `reserved-memory-percent` y ahora se encuentra disponible en todas las versiones de ElastiCache para Redis OSS. El propósito del parámetro `reserved-memory-percent` es simplificar la administración de la memoria reservada en todos los clústeres. Esta simplificación se consigue al disponer de un único grupo de parámetros para cada familia de grupos de parámetros (como `redis2.8`) para administrar la memoria reservada de sus clústeres, sea cual sea el tipo de nodo. El valor de predeterminado para `reserved-memory-percent` es 25 (25 por ciento).

El parámetro `reserved-memory-percent` es específico para ElastiCache y no forma parte de la distribución general de Redis OSS.

Si el clúster utiliza un tipo de nodo de la familia r6gd y el uso de memoria alcanza el 75 por ciento, la organización de datos en niveles se activará automáticamente. Para obtener más información, consulte [Organización de datos en niveles en ElastiCache](data-tiering.md).

**Para reservar memoria mediante reserved-memory-percent**  
Para utilizar `reserved-memory-percent` a fin de administrar la memoria en su clúster de ElastiCache para Redis OSS, realice una de las acciones siguientes:
+ Si ejecuta Redis OSS 2.8.22 o versiones posteriores, asigne el grupo de parámetros predeterminado a su clúster. El valor predeterminado de 25 debe ser suficiente. De lo contrario, siga los pasos que se describen a continuación para cambiar el valor.
+ Si ejecuta una versión de Redis OSS anterior a la 2.8.22, probablemente tendrá que reservar más memoria que el 25 % predeterminado de `reserved-memory-percent`. Para ello, siga el procedimiento que se indica a continuación. 

**Para cambiar el valor porcentual de reserved-memory-percent**

1. Cree un grupo de parámetros personalizado especificando la familia del grupo de parámetros que coincide con la versión del motor que está ejecutando, como, por ejemplo, la familia del grupo de parámetros `redis2.8`. Necesita disponer de un grupo de parámetros personalizado porque no es posible modificar grupos de parámetros predeterminados. Para obtener más información, consulte [Creación de un grupo de parámetros de ElastiCache](ParameterGroups.Creating.md).

   ```
   aws elasticache create-cache-parameter-group \
      --cache-parameter-group-name redis28-50 \
      --description "Redis OSS 2.8.x 50% reserved" \
      --cache-parameter-group-family redis2.8
   ```

   Dado que `reserved-memory-percent` se reserva la memoria como un porcentaje del valor `maxmemory` de un nodo, no necesita un grupo de parámetros personalizado para cada tipo de nodo.

1. Modifique el grupo de parámetros personalizados de modo que el parámetro `reserved-memory-percent` tenga el valor 50 (50 %). Para obtener más información, consulte [Modificación de un grupo de parámetros de ElastiCache](ParameterGroups.Modifying.md).

   ```
   aws elasticache modify-cache-parameter-group \
      --cache-parameter-group-name redis28-50 \
      --parameter-name-values "ParameterName=reserved-memory-percent, ParameterValue=50"
   ```

1. Use este grupo de parámetros personalizado para todos los clústeres o grupos de replicación de Redis OSS que ejecuten una versión de Redis OSS anterior a la 2.8.22.

   En el ejemplo de la CLI siguiente se modifica el clúster de Redis OSS `my-redis-cluster` de forma que comience a usar de inmediato el grupo de parámetros personalizado `redis28-50`. Para obtener más información, consulte [Modificación de un clúster de ElastiCache](Clusters.Modify.md).

   ```
   aws elasticache modify-cache-cluster \
      --cache-cluster-id my-redis-cluster \
      --cache-parameter-group-name redis28-50 \
      --apply-immediately
   ```

   En el ejemplo de la CLI siguiente se modifica el grupo de replicación de Redis OSS `my-redis-repl-grp` de forma que comience a usar de inmediato el grupo de parámetros personalizado `redis28-50`. Para obtener más información, consulte [Modificación de un grupo de reproducción](Replication.Modify.md).

   ```
   aws elasticache modify-replication-group \
      --replication-group-id my-redis-repl-grp \
      --cache-parameter-group-name redis28-50 \
      --apply-immediately
   ```

## Especificación del parámetro de administración de memoria reservada
<a name="redis-reserved-memory-management-change"></a>

Si ya era un cliente de ElastiCache el 16 de marzo de 2017, su parámetro predeterminado de administración de memoria reservada es `reserved-memory` con cero (0) bytes de memoria reservada. Si comenzó a ser cliente de ElastiCache después del 16 de marzo de 2017, su parámetro predeterminado de administración de memoria reservada es `reserved-memory-percent` con un 25 % de la memoria reservada del nodo. Esto se cumple independientemente de cuándo haya creado el clúster o grupo de replicación de ElastiCache para Redis OSS. Sin embargo, puede cambiar el parámetro de administración de memoria reservada, mediante la AWS CLI o la API de ElastiCache.

Los parámetros `reserved-memory` y `reserved-memory-percent` son mutuamente excluyentes. Un grupo de parámetros siempre tiene un parámetro, pero nunca ambos. Puede cambiar el parámetro que usa el grupo de parámetros para la administración de memoria reservada modificando el grupo de parámetros. El grupo de parámetros debe ser personalizado, ya que no es posible modificar grupos de parámetros predeterminados. Para obtener más información, consulte [Creación de un grupo de parámetros de ElastiCache](ParameterGroups.Creating.md).

**Para especificar reserved-memory-percent**  
Para utilizar `reserved-memory-percent` como parámetro de administración de memoria reservada, modifique un grupo de parámetros personalizado mediante el comando `modify-cache-parameter-group`. Utilice el parámetro `parameter-name-values` para especificar `reserved-memory-percent` y un valor para ello.

El siguiente ejemplo de la CLI modifica el grupo de parámetros personalizados `redis32-cluster-on` para usar el parámetro `reserved-memory-percent` para administrar la memoria reservada. Se debe asignar un valor a `ParameterValue` para que el grupo de parámetros utilice el parámetro `ParameterName` a fin de administrar la memoria reservada. Para obtener más información, consulte [Modificación de un grupo de parámetros de ElastiCache](ParameterGroups.Modifying.md).

```
aws elasticache modify-cache-parameter-group \
   --cache-parameter-group-name redis32-cluster-on \
   --parameter-name-values "ParameterName=reserved-memory-percent, ParameterValue=25"
```

**Para especificar reserved-memory**  
Para utilizar `reserved-memory` como parámetro de administración de memoria reservada, modifique un grupo de parámetros personalizado mediante el comando `modify-cache-parameter-group`. Utilice el parámetro `parameter-name-values` para especificar `reserved-memory` y un valor para ello.

El siguiente ejemplo de la CLI modifica el grupo de parámetros personalizados `redis32-m3xl` para usar el parámetro `reserved-memory` para administrar la memoria reservada. Se debe asignar un valor a `ParameterValue` para que el grupo de parámetros utilice el parámetro `ParameterName` a fin de administrar la memoria reservada. Dado que la versión del motor es posterior a la versión 2.8.22, establecemos el valor en `3565158400`, que es el 25 % del valor de `cache.m3.xlarge` de `maxmemory`. Para obtener más información, consulte [Modificación de un grupo de parámetros de ElastiCache](ParameterGroups.Modifying.md).

```
aws elasticache modify-cache-parameter-group \
   --cache-parameter-group-name redis32-m3xl \
   --parameter-name-values "ParameterName=reserved-memory, ParameterValue=3565158400"
```

# Prácticas recomendadas al trabajar con clústeres basados en nodos de Valkey y Redis OSS
<a name="BestPractices.SelfDesigned"></a>

El uso de multi-AZ, disponer de suficiente memoria, cambiar el tamaño del clúster y minimizar el tiempo de inactividad son conceptos útiles que hay que tener en cuenta al trabajar con clústeres basados en nodos en Valkey o Redis OSS. Le recomendamos que revise y siga estos procedimientos recomendados.

**Topics**
+ [Minimización del tiempo de inactividad con Multi-AZ](multi-az.md)
+ [Forma de garantizar que dispone de memoria suficiente para crear una instantánea de Valkey o Redis OSS](BestPractices.BGSAVE.md)
+ [Cambio de tamaño de clústeres online](best-practices-online-resharding.md)
+ [Minimización del tiempo de inactividad durante el mantenimiento](BestPractices.MinimizeDowntime.md)

# Minimización del tiempo de inactividad con Multi-AZ
<a name="multi-az"></a>

Existen varias instancias en las que ElastiCache Valkey o Redis OSS podrían tener que reemplazar un nodo principal. Entre estas se incluyen determinados tipos de mantenimiento planificado y el caso poco probable de que se produzca un error en el nodo principal o en la zona de disponibilidad.

Este reemplazo produce un tiempo de inactividad para el clúster, pero si Multi-AZ se encuentra habilitado, el tiempo de inactividad es mínimo. El rol del nodo primario tendrá una conmutación por error automática en una de las réplicas de lectura. No es necesario crear ni aprovisionar un nodo primario nuevo, ya que ElastiCache se encargará de esto de forma clara. Esta conmutación por error y promoción de réplica garantizan la posibilidad de reanudar la escritura en la réplica principal tan pronto como se complete la promoción.

Consulte [Minimización del tiempo de inactividad en ElastiCache utilizando multi-AZ con Valkey y Redis OSS](AutoFailover.md) para obtener más información sobre multi-AZ y la minimización del tiempo de inactividad.

# Forma de garantizar que dispone de memoria suficiente para crear una instantánea de Valkey o Redis OSS
<a name="BestPractices.BGSAVE"></a>

**Instantáneas y sincronizaciones en Valkey 7.2 y versiones posteriores y Redis OSS versión 2.8.22 y posteriores**  
Valkey admite de forma predeterminada instantáneas y sincronizaciones. Redis OSS 2.8.22 introduce un proceso de guardado sin ramificaciones que le permite asignar más memoria para el uso de su aplicación sin tener que aumentar el uso del espacio de intercambio durante las sincronizaciones y guardados. Para obtener más información, consulte [Cómo se implementan la sincronización y la copia de seguridad](Replication.Redis.Versions.md).

**Instantáneas y sincronizaciones de Redis OSS anteriores a la versión 2.8.22**

Al trabajar con ElastiCache para Redis OSS, Redis OSS llama a un comando de escritura en segundo plano en diversos casos:
+ Al crear una instantánea para una copia de seguridad.
+ Al sincronizar réplicas con la instancia principal en un grupo de reproducción.
+ Al habilitar la característica de archivo de solo anexado (AOF) para Redis OSS.
+ Al promocionar una réplica al nodo primario (lo que produce la sincronización del nodo primario/réplica).

Siempre que Redis OSS ejecute un proceso de escritura en segundo plano, debe disponer de memoria suficiente para los procesos adicionales. Si no tiene suficiente memoria disponible, se produce un error en el proceso. Por ello, es importante elegir un tipo de instancia de nodo que tenga suficiente memoria al crear el clúster de Redis OSS.

## Proceso de escritura en segundo plano y uso de memoria con Valkey y Redis OSS
<a name="BestPractices.BGSAVE.Process"></a>

Siempre que se llame a un proceso de escritura en segundo plano, Valkey y Redis OSS ramifican su proceso (recuerde que estos motores son de un solo proceso). Una ramificación conserva sus datos en disco en un archivo de instantánea .rdb de Redis OSS. El resto de los servicios de la ramificación son todos operaciones de lectura y escritura. Para asegurarse de que la instantánea sea una instantánea puntual, todas las actualizaciones y adiciones se escriben en un área de la memoria disponible independiente del área de los datos.

Siempre que tenga suficiente memoria disponible para registrar todas las operaciones de escritura mientras se almacenan los datos en disco, no debería tener problemas de memoria insuficiente. Es probable que experimente problemas de memoria insuficiente si se da alguna de las siguientes condiciones:
+ Su aplicación realiza muchas operaciones de escritura, lo que requiere una gran cantidad de memoria disponible para aceptar los datos nuevos o actualizados.
+ Tiene muy poca memoria disponible en la que agregar datos nuevos o datos.
+ Dispone de un gran conjunto de datos que requiere mucho tiempo para guardar en disco, lo que exige un gran número de operaciones de escritura.

El siguiente diagrama ilustra el uso de memoria al ejecutar un proceso de escritura en segundo plano.

![\[Imagen: Diagrama de uso de memoria durante la escritura en segundo plano.\]](http://docs.aws.amazon.com/es_es/AmazonElastiCache/latest/dg/images/ElastiCache-bgsaveMemoryUseage.png)


Para obtener más información acerca del impacto en el rendimiento de hacer una copia de seguridad, consulte [Impacto en el rendimiento de las copias de seguridad de los clústeres basados en nodos](backups.md#backups-performance).

Para obtener más información acerca de cómo realizan Valkey y Redis OSS las instantáneas, consulte [http://valkey.io](http://valkey.io).

Para obtener más información acerca de las regiones y zonas de disponibilidad, consulte [Elección de regiones y zonas de disponibilidad para ElastiCache](RegionsAndAZs.md). 

## Evitar el agotamiento de la memoria al ejecutar una escritura en segundo plano
<a name="BestPractices.BGSAVE.memoryFix"></a>

Siempre que se llame a un proceso de escritura en segundo plano, como `BGSAVE` o `BGREWRITEAOF`, para evitar que el proceso falle, debe tener más memoria disponible que la que consumirán las operaciones de escritura durante el proceso. Lo peor que podría ocurrir es que, durante la operación de escritura en segundo plano, se actualizasen todos los registros y se añadiesen algunos registros nuevos a la caché. Por ello, recomendamos que establezca `reserved-memory-percent` en 50 (50 %) en versiones de Redis OSS anteriores a 2.8.22, o bien en 25 (25 %) en Redis OSS 2.8.22 y versiones posteriores. 

El valor `maxmemory` indica la memoria disponible para sus datos y para la carga adicional operativa. Puesto que no puede modificar el parámetro `reserved-memory` en el grupo de parámetros predeterminado, debe crear un grupo de parámetros personalizado para el clúster. El valor predeterminado para `reserved-memory` es 0, lo que permite a Redis OSS consumir la totalidad de *maxmemory* con datos, lo que posiblemente deja muy poca memoria para otros usos, como un proceso de escritura en segundo plano. Para los valores `maxmemory` por tipo de instancia de nodo, consulte [Parámetros específicos de tipos de nodos de Redis OSS](ParameterGroups.Engine.md#ParameterGroups.Redis.NodeSpecific).

También puede utilizar el parámetro `reserved-memory` para reducir la cantidad de memoria que se utiliza de forma predeterminada.

Para obtener más información sobre los parámetros específicos de Valkey y Redis en ElastiCache, consulte [Parámetros de Valkey y Redis OSS](ParameterGroups.Engine.md#ParameterGroups.Redis).

Para obtener información acerca de cómo crear y modificar grupos de parámetros, consulte [Creación de un grupo de parámetros de ElastiCache](ParameterGroups.Creating.md) y [Modificación de un grupo de parámetros de ElastiCache](ParameterGroups.Modifying.md).

# Cambio de tamaño de clústeres online
<a name="best-practices-online-resharding"></a>

El *cambio de las particiones* implica agregar y eliminar particiones o nodos del clúster y redistribuir los espacios clave. Como resultado, varios aspectos influyen en la operación de cambio de las particiones, como la carga en el clúster, la utilización de memoria y el tamaño total de los datos. Para disfrutar de la mejor experiencia, recomendamos que siga las prácticas recomendadas de clúster global para una distribución uniforme del patrón de carga de trabajo. Además, recomendamos que siga los pasos que se detallan a continuación.

Antes de iniciar el cambio de las particiones, recomendamos lo siguiente:
+ **Probar la aplicación**: si es posible, pruebe el comportamiento de la aplicación durante el cambio de las particiones en un entorno de ensayo.
+ **Recibir notificaciones anticipadas sobre problemas de escalado**: el cambio de particiones es una operación que requiere mucho procesamiento. Por ello, recomendamos que mantenga el uso de la CPU por debajo del 80 por ciento en instancias de varios núcleos y en menos del 50 por ciento en instancias de un solo núcleo durante el cambio de particiones. Supervise las métricas de ElastiCache para Redis OSS e inicie el cambio de las particiones antes de que la aplicación comience a tener problemas de escalado. Las métricas de las que se puede realizar un seguimiento son `CPUUtilization`, `NetworkBytesIn`, `NetworkBytesOut`, `CurrConnections`, `NewConnections`, `FreeableMemory`, `SwapUsage` y `BytesUsedForCacheItems`.
+ **Comprobar que hay suficiente memoria libre disponible antes de la reducción horizontal**: si va a realizar una reducción horizontal, asegúrese de que la memoria libre disponible en las particiones que se van a retener sea al menos 1,5 veces la memoria utilizada en las particiones que tiene previsto eliminar.
+ **Iniciar el cambio de las particiones durante las horas de menor actividad**: esta práctica contribuye a reducir la latencia y el impacto en el rendimiento en el cliente durante la operación de cambio de las particiones. También ayuda a completar el cambio de las particiones con mayor rapidez ya que se pueden usar más recursos para la redistribución de ranuras.
+ **Revisar el comportamiento de tiempo de espera de cliente**: es posible que algunos clientes observen una latencia más alta durante el cambio de tamaño del clúster en línea. La configuración de la biblioteca de cliente con un tiempo de espera más alto puede ayudar a conceder al sistema tiempo para conectar incluso en condiciones de carga más altas en servidor. En algunos casos, es posible que abra un gran número de conexiones al servidor. En estos casos, considere la posibilidad de agregar retardo exponencial a la lógica de reconexión. Si lo hace, puede ayudar a evitar que llegue una ráfaga de conexiones nuevas al servidor al mismo tiempo.
+ **Cargar las funciones en cada partición**: al escalar horizontalmente el clúster, ElastiCache replicará automáticamente las funciones cargadas en uno de los nodos existentes (seleccionado de forma aleatoria) en los nuevos nodos. Si el clúster tiene Valkey 7.2 o una versión posterior o Redis OSS 7.0 o una versión posterior y la aplicación usa [funciones](https://valkey.io/topics/functions-intro/), le recomendamos que cargue todas las funciones en todas las particiones antes de escalar horizontalmente para que el clúster no termine con diferentes funciones en distintas particiones.

Después del cambio de las particiones, tenga en cuenta lo siguiente:
+ La reducción horizontal se puede realizar parcialmente si no hay suficiente memoria disponible en las particiones de destino. Si se produce este resultado, revise la memoria disponible y, si es necesario, reintente la operación. Los datos de las particiones de destino no se eliminarán.
+ No se admiten los comandos `FLUSHALL` y `FLUSHDB` en los scripts Lua dentro durante una operación de cambio de particiones. En versiones anteriores a Redis OSS 6, no se admite el comando `BRPOPLPUSH` si opera en la ranura que se va a migrar.

# Minimización del tiempo de inactividad durante el mantenimiento
<a name="BestPractices.MinimizeDowntime"></a>

La configuración de modo de clúster presenta la mejor disponibilidad durante operaciones administradas y no administradas. Se recomienda utilizar un cliente compatible con modo de clúster que se conecte al punto de enlace de detección de clústeres. Para el modo de clúster deshabilitado, se recomienda utilizar el punto de enlace principal para todas las operaciones de escritura. 

Para la actividad de lectura, las aplicaciones pueden conectarse también a cualquier nodo del clúster. A diferencia del punto de conexión principal, los puntos de conexión de nodo se resuelven en puntos de enlace específicos. Si realiza un cambio en su clúster, como añadir o eliminar una réplica, debe actualizar los puntos de enlace del nodo en su aplicación. Por eso, si el modo de clúster está deshabilitado, le recomendamos que utilice el punto de conexión del lector para la actividad de lectura.

Si la conmutación por error automática está habilitada en el clúster, es posible que el nodo principal cambie. Por lo tanto, la aplicación debe confirmar el rol del nodo y actualizar todos los puntos de enlace de lectura. Esta operación ayuda a garantizar que no esté provocando una carga importante en el nodo principal. Con la conmutación por error automática desactivada, el rol del nodo no cambia. Sin embargo, el tiempo de inactividad en las operaciones administradas o no administradas es mayor en comparación con los clústeres con conmutación por error automática habilitada.

 Evite dirigir las solicitudes de lectura a un único nodo de réplica de lectura, ya que su falta de disponibilidad podría provocar una interrupción de la lectura. Opte por la lectura desde el servidor principal o asegúrese de tener al menos dos réplicas de lectura para evitar cualquier interrupción de la lectura durante el mantenimiento. 

# Estrategias de almacenamiento en caché para Memcached
<a name="Strategies"></a>

En el siguiente tema, encontrará estrategias para completar y mantener la caché de Memcached.

Las estrategias que implemente para completar y mantener su caché dependen del tipo de datos que va a almacenar en su caché, así como de los patrones de acceso a dichos datos. Por ejemplo, probablemente no quiera utilizar la misma estrategia para una tabla de clasificación de los 10 mejores jugadores de un sitio de juegos y noticias de moda. En el resto de esta sección, se analizan las distintas estrategias comunes de mantenimiento de caché, junto con sus ventajas e inconvenientes.

**Topics**
+ [Réplicas de lectura](#Strategies.ReadReplicas)
+ [Carga diferida](#Strategies.LazyLoading)
+ [Escritura indirecta](#Strategies.WriteThrough)
+ [Agregar TTL](#Strategies.WithTTL)
+ [Temas relacionados](#Strategies.SeeAlso)

## Réplicas de lectura
<a name="Strategies.ReadReplicas"></a>

A menudo, el rendimiento de las cachés sin servidor de ElastiCache se puede mejorar considerablemente creando réplicas y leyendo desde ellas en lugar de desde el nodo de caché principal. Para obtener más información consulte () [Prácticas recomendadas para utilizar réplicas de lectura](ReadReplicas.md).

## Carga diferida
<a name="Strategies.LazyLoading"></a>

Como su nombre indica, la *carga diferida* es una estrategia de almacenamiento en caché que carga los datos en la caché solo cuando es necesario. Funciona como se describe a continuación. 

Amazon ElastiCache es un almacén de valor de clave en memoria que se sitúa entre su aplicación y el almacén de datos (base de datos) al que accede. Siempre que su aplicación solicite datos, primero realizará una solicitud a la caché de ElastiCache. Si los datos existen en la caché y son actuales, ElastiCache devuelve los datos a su aplicación. Si los datos no existen en la caché o se han vencido, la aplicación solicita los datos del almacén de datos. A continuación, el almacén de datos devuelve los datos a su aplicación. Luego, su aplicación escribe los datos que recibió del almacén en la caché. De esta forma, se pueden recuperar más rápidamente la próxima vez que se los soliciten.

Un *acierto de caché* se produce cuando los datos se encuentran en la caché y no han vencido:

1. La aplicación solicita los datos a la caché.

1. La caché devuelve los datos a la aplicación.

Un *error de caché* se produce cuando los datos no se encuentran en la caché y han vencido:

1. La aplicación solicita los datos a la caché.

1. La caché no dispone de los datos solicitados, por lo que devuelve `null`.

1. La aplicación solicita los datos a la base de datos y los recibe.

1. La aplicación actualiza la caché con los datos nuevos.

### Ventajas y desventajas de la carga diferida
<a name="Strategies.LazyLoading.Evaluation"></a>

Las ventajas de la carga diferida son las siguientes:
+ Solo se almacenan en la caché los datos solicitados.

  Dado que nunca se solicita la mayoría de los datos, la carga diferida evita completar la caché con datos que no se solicitan.
+ Los errores de nodo no son fatales para su aplicación.

  Cuando se produce un error en un nodo y se reemplaza por un nodo nuevo y vacío, la aplicación sigue funcionando, aunque con mayor latencia. Cuando se realizan solicitudes al nodo nuevo, cada error de caché da como resultado una consulta de la base de datos. Al mismo tiempo, la copia de datos se agrega a la caché para que las solicitudes posteriores se recuperen de la caché.

Las desventajas de la carga diferida son las siguientes:
+ Existe una penalización de errores de caché. Cada error de caché genera tres acciones: 

  1. Solicitud inicial de los datos a la caché

  1. Consulta de los datos en la base de datos

  1. Escritura de los datos en la caché

   Estos errores pueden provocar un retraso significativo en la obtención de los datos en la aplicación.
+ Datos obsoletos.

  Si los datos se escriben en la caché solo cuando se produce un error de caché, los datos de la caché pueden quedar obsoletos. Este resultado se produce porque no hay actualizaciones en la caché cuando se cambian los datos en la base de datos. Para solucionar este problema, puede utilizar las estrategias [Escritura indirecta](#Strategies.WriteThrough) y [Agregar TTL](#Strategies.WithTTL).

### Ejemplo de seudocódigo de carga diferida
<a name="Strategies.LazyLoading.CodeExample"></a>

El siguiente ejemplo es un seudocódigo de lógica de carga diferida.

```
// *****************************************
// function that returns a customer's record.
// Attempts to retrieve the record from the cache.
// If it is retrieved, the record is returned to the application.
// If the record is not retrieved from the cache, it is
//    retrieved from the database, 
//    added to the cache, and 
//    returned to the application
// *****************************************
get_customer(customer_id)

    customer_record = cache.get(customer_id)
    if (customer_record == null)
    
        customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id)
        cache.set(customer_id, customer_record)
    
    return customer_record
```

Para este ejemplo, el código de aplicación que obtiene los datos es el siguiente.

```
customer_record = get_customer(12345)
```

## Escritura indirecta
<a name="Strategies.WriteThrough"></a>

La estrategia de escritura indirecta agrega o actualiza los datos de la caché siempre que se escriben datos en la base de datos.

### Ventajas y desventajas de la escritura indirecta
<a name="Strategies.WriteThrough.Evaluation"></a>

Las ventajas de la escritura indirecta son las siguientes:
+ Los datos de la caché nunca quedan obsoletos.

  Dado que los datos de la caché se actualizan cada vez que se escriben en la base de datos, estos siempre se mantienen actualizados.
+ Penalización de escritura frente a penalización de lectura.

  Toda operación de escritura implica dos acciones: 

  1. Una operación de escritura en la caché

  1. Una operación de escritura en la base de datos

   Estas acciones añaden latencia al proceso. Dicho esto, los usuarios finales suelen ser más tolerantes con la latencia a la hora de actualizar datos que con la latencia a la hora de recuperar datos. Existe un sentido inherente que apunta a que las actualizaciones conllevan más trabajo y, por lo tanto, requieren mayor tiempo.

Las desventajas de la escritura indirecta son las siguientes:
+ Pérdida de datos.

  Si pone en marcha un nodo nuevo, ya sea debido a un error de nodo o a una operación de escalado horizontal, existen datos que se perderán. Estos datos siguen faltando hasta que se agregan o actualizan en la base de datos. Puede minimizar esto al implementar una [carga diferida](#Strategies.LazyLoading) con escritura indirecta.
+ Pérdida de caché.

  La mayoría de los datos nunca se leen, lo cual es un desperdicio de recursos. Al [agregar un valor de periodo de vida (TTL)](#Strategies.WithTTL), puede minimizar el desperdicio de espacio.

### Ejemplo de seudocódigo de escritura indirecta
<a name="Strategies.WriteThrough.CodeExample"></a>

El siguiente ejemplo es un seudocódigo de lógica de escritura indirecta.

```
// *****************************************
// function that saves a customer's record.
// *****************************************
save_customer(customer_id, values)

    customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values)
    cache.set(customer_id, customer_record)
    return success
```

Para este ejemplo, el código de aplicación que obtiene los datos es el siguiente.

```
save_customer(12345,{"address":"123 Main"})
```

## Agregar TTL
<a name="Strategies.WithTTL"></a>

La carga diferida da lugar a que los datos queden obsoletos, pero no falla con nodos vacíos. La escritura diferida mantiene los datos siempre actualizados, pero puede fallar con nodos vacíos y puede llenar la caché con datos superfluos. Al agregar un valor de periodo de vida (TTL) a cada escritura, puede tener las ventajas de cada estrategia. Al mismo tiempo, puede evitar en gran medida saturar la memoria caché con datos adicionales.

El *periodo de vida (TTL)* es un valor entero que especifica el número de segundos hasta que caduque la clave. Valkey o Redis OSS puede especificar segundos o milisegundos para este valor. Memcached especifica este valor en segundos. Cuando una aplicación intenta leer una clave vencida, la trata como si no se encontrara la clave. La base de datos se consulta para la clave y se actualiza la caché. Este enfoque no garantiza que un valor no se encuentre obsoleto. Sin embargo, evita que los datos queden demasiado obsoletos y se actualizan los valores de la caché con frecuencia desde la base de datos.

Para obtener más información, consulte [Valkey and Redis OSS commands](https://valkey.io/commands) o los comandos de [Memcached`set`](https://www.tutorialspoint.com/memcached/memcached_set_data.htm).

### Ejemplos de seudocódigo de TTL
<a name="Strategies.WithTTL.CodeExample"></a>

El siguiente ejemplo es un seudocódigo de lógica de escritura indirecta con TTL.

```
// *****************************************
// function that saves a customer's record.
// The TTL value of 300 means that the record expires
//    300 seconds (5 minutes) after the set command 
//    and future reads will have to query the database.
// *****************************************
save_customer(customer_id, values)

    customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values)
    cache.set(customer_id, customer_record, 300)

    return success
```

El siguiente ejemplo es un seudocódigo de lógica de carga diferida con TTL.

```
// *****************************************
// function that returns a customer's record.
// Attempts to retrieve the record from the cache.
// If it is retrieved, the record is returned to the application.
// If the record is not retrieved from the cache, it is 
//    retrieved from the database, 
//    added to the cache, and 
//    returned to the application.
// The TTL value of 300 means that the record expires
//    300 seconds (5 minutes) after the set command 
//    and subsequent reads will have to query the database.
// *****************************************
get_customer(customer_id)

    customer_record = cache.get(customer_id)
    
    if (customer_record != null)
        if (customer_record.TTL < 300)
            return customer_record        // return the record and exit function
            
    // do this only if the record did not exist in the cache OR
    //    the TTL was >= 300, i.e., the record in the cache had expired.
    customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id)
    cache.set(customer_id, customer_record, 300)  // update the cache
    return customer_record                // return the newly retrieved record and exit function
```

Para este ejemplo, el código de aplicación que obtiene los datos es el siguiente.

```
save_customer(12345,{"address":"123 Main"})
```

```
customer_record = get_customer(12345)
```

## Temas relacionados
<a name="Strategies.SeeAlso"></a>
+ [Almacenamiento de datos en memoria](elasticache-use-cases.md#elasticache-use-cases-data-store)
+ [Elección de un motor y una versión](SelectEngine.md)
+ [Escalado ElastiCache](Scaling.md)