Configuración del cliente de Lettuce (Valkey y Redis OSS) - Amazon ElastiCache

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.

Configuración del cliente de Lettuce (Valkey y Redis OSS)

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

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

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 convierte un nombre de host en una dirección IP, almacena en caché la dirección IP durante un período de tiempo específico, conocido como TTL time-to-live.

La elección del valor de TTL implica un compromiso entre latencia y la capacidad de respuesta a los cambios. Con una versión más corta TTLs, 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 ElastiCache los nodos utilizan entradas de nombres DNS que pueden cambiar, le recomendamos que configure la 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.

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 la topología, consulte dynamicRefreshResourcesmás adelante en este tema.

SocketOption

Habilite KeepAlive. 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 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

Se activa AutoReconnectcuando se pierde la conexión.

Configurar CommandTimeout. Para obtener más información, consulte la sección Tiempos de espera más adelante en este tema.

Establezca nodeFilter 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 si se DynamicRefreshSources establece en true. 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 iniciales (si DynamicRefreshSources es cierto) reduce la probabilidad de que se produzca este problema, ya que al menos algunos de los nodos iniciales deberían tener una vista de topología actualizada tras 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 con el modo de clúster activado

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 el de Lettuce. MasterSlaveTopologyRefresh 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).

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. 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. Esto permite actualizar la topología adaptativa y utilizar todos los disparadores: MOVED_REDIRECT, ASK_REDIRECT, PERSISTENT_RECONNECTS, UNCOVERED_SLOT, UNKNOWN_NODE. 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. Esto permite cerrar las conexiones obsoletas al actualizar la topología del clúster. Solo entra en vigor si ClusterTopologyRefreshOptions. 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. Recomendamos habilitarlo dynamicRefreshResources para clústeres pequeños y deshabilitarlo para clústeres grandes. dynamicRefreshResourcespermite descubrir los nodos del clúster desde el nodo inicial proporcionado (por ejemplo, el punto final 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 cierto, 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

Configurar DnsResolver con DirContextDnsResolver El solucionador de DNS se basa en com.sun.jndi.dns de Java. DnsContextFactory.

Configure reconnectDelay 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 en el AWS blog de arquitectura. Para obtener más información sobre la importancia de contar con una estrategia de retroceso de los reintentos, consulte las secciones de lógica de retroceso de la entrada del blog sobre mejores prácticas en el blog de bases de datos. 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();