Lettuce 클라이언트 구성(Valkey 및 RedisOSS) - Amazon ElastiCache

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Lettuce 클라이언트 구성(Valkey 및 RedisOSS)

이 섹션에서는 권장 Java 및 Lettuce 구성 옵션과 ElastiCache 클러스터에 적용하는 방법을 설명합니다.

이 섹션의 권장 사항은 Lettuce 버전 6.2.2에서 테스트되었습니다.

Java DNS 캐시 TTL

Java 가상 머신(JVM)은 DNS 이름 조회를 캐시합니다. 가 호스트 이름을 IP 주소로 JVM 확인하면 time-to-live ()라고 하는 지정된 기간 동안 IP 주소를 캐싱합니다TTL.

TTL 가치 선택은 지연 시간과 변화에 대한 대응성 간의 균형입니다. 가 짧을수록 TTLs DNS 해석자는 클러스터의 업데이트가 DNS 더 빨라집니다. 이렇게 하면 클러스터가 수행하는 교체 또는 기타 워크플로에 애플리케이션이 더 빠르게 응답할 수 있습니다. 그러나 TTL 이 너무 낮으면 쿼리 볼륨이 증가하여 애플리케이션의 지연 시간이 늘어날 수 있습니다. 올바른 TTL 값은 없지만 TTL 값을 설정할 때 변경 사항이 적용될 때까지 기다릴 수 있는 시간을 고려하는 것이 좋습니다.

ElastiCache 노드는 변경될 수 있는 DNS 이름 항목을 사용하기 때문에 를 TTL 5~10초 JVM 미만으로 구성하는 것이 좋습니다. 이렇게 하면 노드의 IP 주소가 변경되면 애플리케이션에서 DNS 항목을 다시 쿼리하여 리소스의 새 IP 주소를 수신하고 사용할 수 있습니다.

일부 Java 구성에서는 TTL가 다시 시작될 때까지 DNS 항목을 새로 고치지 않도록 JVM 기본값JVM이 설정됩니다.

를 설정하는 방법에 대한 자세한 내용은 를 설정하는 방법을 JVM TTL참조하세요. JVM TTL

Lettuce 버전

Lettuce 버전 6.2.2 이상을 사용하는 것이 좋습니다.

엔드포인트

클러스터 모드가 활성화된 클러스터를 사용하는 경우 redisUri를 클러스터 구성 엔드포인트로 설정합니다. 이를 DNS 조회하면 클러스터에서 사용 가능한 모든 노드 목록이 URI 반환되며 클러스터 초기화 중에 해당 노드 중 하나로 무작위로 확인됩니다. 토폴로지 새로 고침의 작동 방식에 대한 자세한 내용은 이 주제의 dynamicRefreshResources뒷부분을 참조하세요.

SocketOption

를 활성화합니다KeepAlive. 이 옵션을 활성화하면 명령 런타임 중에 실패한 연결을 처리할 필요가 줄어듭니다.

애플리케이션 요구 사항 및 워크로드에 따라 연결 제한 시간을 설정해야 합니다. 자세한 내용은 이 주제의 후반부에서 연결 제한 섹션을 참조하세요.

ClusterClientOption: 클러스터 모드 활성화된 클라이언트 옵션

연결이 끊AutoReconnect어지면 활성화합니다.

를 설정합니다CommandTimeout. 자세한 내용은 이 주제의 후반부에서 연결 제한 섹션을 참조하세요.

토폴로지에서 실패한 노드를 필터링nodeFilter하도록 를 설정합니다. Lettuce는 클라이언트의 '파티션'(샤드라고도 함)의 '클러스터 노드' 출력(PFAIL/FAIL 상태의 노드 포함)에 있는 모든 노드를 저장합니다. 클러스터 토폴로지를 생성하는 동안 모든 파티션 노드에 연결을 시도합니다. 장애가 발생한 노드를 추가하는 이러한 Lettuce 동작은 어떤 이유로든 노드를 교체할 때 연결 오류(또는 경고)를 유발할 수 있습니다.

예를 들어 장애 조치가 완료되고 클러스터가 복구 프로세스를 시작한 후 clusterTopology 가 새로 고쳐지는 동안 클러스터 버스 노드 맵은 다운 노드가 노드로 나열되는 시간이 짧FAIL아 토폴로지에서 완전히 제거됩니다. 이 기간 동안 Lettuce 클라이언트는 이를 정상 노드로 간주하고 지속적으로 연결합니다. 이로 인해 재시도가 모두 끝난 후 오류가 발생합니다.

예:

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);
참고

노드 필터링은 true로 DynamicRefreshSources 설정된 와 함께 사용하는 것이 가장 좋습니다. 그러지 않으면 문제가 있는 단일 시드 노드에서 토폴로지 보기를 가져와서 일부 샤드의 프라이머리 노드에 장애가 있는 것으로 간주하면 이 프라이머리 노드가 필터링되어 슬롯이 포함되지 않습니다. 시드 노드가 여러 개 있으면( true DynamicRefreshSources 인 경우) 새로 승격된 프라이머리를 사용한 장애 조치 후 시드 노드의 일부 이상이 업데이트된 토폴로지 뷰를 가져야 하므로 이 문제가 발생할 가능성이 줄어듭니다.

ClusterTopologyRefreshOptions: 클러스터 모드 활성화 클라이언트의 클러스터 토폴로지 새로 고침을 제어하는 옵션

참고

클러스터 모드가 비활성화된 클러스터는 클러스터 검색 명령을 지원하지 않으며 모든 클라이언트 동적 토폴로지 검색 기능과 호환되지 않습니다.

에서 비활성화된 클러스터 모드 ElastiCache 는 Lettuce의 와 호환되지 않습니다MasterSlaveTopologyRefresh. 대신, 비활성화된 클러스터 모드에는 StaticMasterReplicaTopologyProvider를 구성하여 클러스터 읽기 및 쓰기 엔드포인트를 제공할 수 있습니다.

클러스터 모드 비활성화 클러스터 연결에 대한 자세한 내용은 Valkey 또는 RedisOSS(클러스터 모드 비활성화됨) 클러스터의 엔드포인트 찾기(콘솔)를 참조하십시오.

Lettuce의 동적 토폴로지 검색 기능을 사용하려면 클러스터 모드 활성화 클러스터를 만들고 기존 클러스터와 샤드 구성을 동일하게 해야 합니다. 하지만 클러스터 모드 활성화 클러스터에는 최소 3개의 샤드와 1개 이상의 복제본을 구성하는 것을 권장하며, 이렇게 해야 빠른 장애 조치를 지원할 수 있습니다.

를 활성화합니다enablePeriodicRefresh. 이렇게 하면 주기적인 클러스터 토폴로지 업데이트가 활성화되어 클라이언트가 클러스터 토폴로지를 의 간격으로 업데이트합니다refreshPeriod (기본값: 60초). 비활성화된 경우 클라이언트는 클러스터에 대해 명령을 실행하려고 할 때 오류가 발생한 경우에만 클러스터 토폴로지를 업데이트합니다.

이 옵션을 활성화하면 이 작업을 백그라운드 작업에 추가하여 클러스터 토폴로지 새로 고침과 관련된 지연 시간을 줄일 수 있습니다. 토폴로지 새로 고침은 백그라운드 작업에서 수행되지만 노드가 많은 클러스터의 경우 다소 느릴 수 있습니다. 이는 가장 업데이트된 클러스터 보기를 얻기 위해 모든 노드에 보기를 쿼리하기 때문입니다. 대규모 클러스터를 실행하는 경우 기간을 늘리는 것이 좋습니다.

를 활성화합니다enableAllAdaptiveRefreshTriggers. 이렇게 하면 _REDIRECT, MOVED_, _, _, ASK_ 등의 모든 트리거를 사용하는 적응형 토폴로지 새로 고침이 활성화됩니다REDIRECTPERSISTENTRECONNECTSUNCOVEREDSLOTUNKNOWNNODE. 적응형 새로 고침 트리거는 Valkey 또는 Redis OSS 클러스터 작업 중에 발생하는 이벤트를 기반으로 토폴로지 보기 업데이트를 시작합니다. 이 옵션을 활성화하면 위 트리거 중 하나가 발생할 때 즉시 토폴로지가 새로 고쳐집니다. 이벤트가 대규모로 발생할 수 있으므로 적응형 트리거 새로 고침은 제한 시간을 사용하여 속도를 제한합니다(업데이트 간 기본 제한 시간: 30).

를 활성화합니다closeStaleConnections. 이렇게 하면 클러스터 토폴로지를 새로 고칠 때 오래된 연결을 닫을 수 있습니다. ClusterTopologyRefreshOptions.isPeriodicRefreshEnabled()가 true인 경우에만 적용됩니다. 활성화되면 클라이언트는 오래된 연결을 닫고 백그라운드에서 새 연결을 만들 수 있습니다. 그러면 명령 런타임 중에 실패한 연결을 처리할 필요가 줄어듭니다.

를 활성화합니다dynamicRefreshResources. 소형 클러스터의 경우 를 활성화 dynamicRefreshResources하고 대형 클러스터의 경우 비활성화하는 것이 좋습니다. dynamicRefreshResources 는 제공된 시드 노드(예: 클러스터 구성 엔드포인트)에서 클러스터 노드를 검색할 수 있습니다. 검색된 모든 노드를 소스로 사용하여 클러스터 토폴로지를 새로 고칩니다.

동적 새로 고침을 사용하면 클러스터 토폴로지에 대해 검색된 모든 노드를 쿼리하고 가장 정확한 클러스터 보기를 선택하려고 시도합니다. 거짓으로 설정하면 초기 시드 노드만 토폴로지 검색의 소스로 사용되고 초기 시드 노드에 대한 클라이언트 수만 가져옵니다. 비활성화된 경우 클러스터 구성 엔드포인트가 장애가 발생한 노드로 확인되면 클러스터 보기를 새로 고치려는 시도가 실패하고 예외가 발생합니다. 이 시나리오는 장애가 발생한 노드의 항목이 클러스터 구성 엔드포인트에서 제거될 때까지 어느 정도 시간이 걸리기 때문에 발생할 수 있습니다. 따라서 구성 엔드포인트는 여전히 짧은 시간 동안 장애가 발생한 노드로 무작위로 확인될 수 있습니다.

하지만 활성화되면 클러스터 보기에서 수신한 모든 클러스터 노드를 사용하여 현재 보기를 쿼리합니다. 해당 보기에서 장애가 발생한 노드를 필터링하므로 토폴로지 새로 고침이 성공적으로 이루어집니다. 하지만 dynamicRefreshSources 가 true이면 Lettuce는 모든 노드를 쿼리하여 클러스터 보기를 가져온 다음 결과를 비교합니다. 따라서 노드가 많은 클러스터의 경우 비용이 많이 들 수 있습니다. 노드가 많은 클러스터의 경우 이 기능을 끄는 것이 좋습니다.

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

ClientResources

DnsResolver 를 사용하여 를 구성합니다DirContextDnsResolver. DNS 해석기는 Java의 com.sun.jndi.dns를 기반으로 합니다DnsContextFactory.

지수 백오프 및 전체 지터reconnectDelay를 사용하여 를 구성합니다. Lettuce에는 지수 백오프 전략을 기반으로 하는 재시도 메커니즘이 내장되어 있습니다. 자세한 내용은 AWS 아키텍처 블로그의 지수 백오프 및 지터를 참조하세요. 재시도 백오프 전략의 중요성에 대한 자세한 내용은 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();

제한 시간

명령 제한 시간보다 낮은 연결 제한 시간 값을 사용합니다. Lettuce는 지연 연결 설정을 사용합니다. 따라서 연결 제한 시간이 명령 제한 시간보다 긴 경우 Lettuce가 비정상 노드에 연결하려고 시도하고 명령 제한 시간이 항상 초과하면 토폴로지 새로 고침 후에도 오류가 계속 발생하는 기간이 있을 수 있습니다.

서로 다른 명령에 동적 명령 제한 시간을 사용합니다. 명령에 기대되는 기간에 따라 명령 제한 시간을 설정하는 것이 좋습니다. 예를 들어 , , FLUSHDB, FLUSHALL KEYS SMEMBERS또는 Lua 스크립트와 같은 여러 키를 반복하는 명령에는 더 긴 제한 시간을 사용합니다. , 및 와 같은 단일 키 명령에는 더 짧은 제한 시간을 사용합니다SETGETHSET.

참고

다음 예제에서 구성된 제한 시간은 최대 20바이트 길이의 키 및 값으로 실행SET/GET명령하는 테스트에 대한 것입니다. 명령이 복잡하거나 키와 값이 크면 처리 시간이 더 오래 걸릴 수 있습니다. 애플리케이션의 사용 사례에 따라 제한 시간을 설정해야 합니다.

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