本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
Lettuce 用戶端組態 (Valkey 和 RedisOSS)
本節說明建議的 Java 和 Lettuce 組態選項,以及這些選項如何套用至 ElastiCache 叢集。
本節中的建議已使用 Lettuce 版本 6.2.2 進行測試。
Java DNS快取 TTL
Java 虛擬機器 (JVM) 會快取DNS名稱查詢。當 將主機名稱JVM解析為 IP 地址時,它會快取 IP 地址一段時間,稱為 time-to-live(TTL)。
TTL 值的選擇是在延遲和對變更的回應能力之間取得權衡。透過較短的 TTLs,DNS解決者會DNS更快地通知叢集中的更新。這可讓您的應用程式更快回應叢集所經歷的替換或其他工作流程。不過,如果 TTL 太低,則會增加查詢磁碟區,進而增加應用程式的延遲。雖然沒有正確的TTL值,但建議您考慮在設定TTL值時,等待變更生效的時間長度。
由於 ElastiCache 節點使用可能會變更DNS的名稱項目,建議您JVM將 設定為 5 到 10 秒TTL的低點。這可確保當節點的 IP 地址變更時,您的應用程式將能夠透過重新查詢DNS項目來接收和使用資源的新 IP 地址。
在某些 Java 組態上,TTL會設定JVM預設值,因此在JVM重新啟動 之前,永遠不會重新整理DNS項目。
如需如何設定 JVM 的詳細資訊TTL,請參閱如何設定 JVM TTL。
Lettuce 版本
建議使用 Lettuce 6.2.2 或更新版本。
端點
當您使用已啟用叢集模式的叢集時,請將 redisUri
設為叢集組態端點。此DNS查詢會URI傳回叢集中所有可用節點的清單,並在叢集初始化期間隨機解析為其中一個節點。如需拓撲重新整理運作方式的詳細資訊,請參閱本主題dynamicRefreshResources稍後的 。
SocketOption
啟用 KeepAlive
請務必根據應用程式需求和工作負載設定連線逾時
ClusterClientOption:啟用叢集模式的用戶端選項
連線中斷AutoReconnect
設定 CommandTimeout
nodeFilter
例如,在容錯移轉完成且叢集啟動復原程序後,當 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);
注意
節點篩選最好搭配 DynamicRefreshSources 設定為 true 使用。否則,如果拓撲檢視是從單一有問題的種子節點中取得,並將某些碎片的主節點視為故障,則它將篩除此主節點,這將導致槽不被涵蓋。擁有多個種子節點 (當 DynamicRefreshSources 為 true) 可降低此問題的可能性,因為至少一些種子節點在新升級的主要節點容錯移轉之後,應該具有更新的拓撲檢視。
ClusterTopologyRefreshOptions:用於控制叢集拓撲的選項,以重新整理已啟用叢集模式的用戶端
注意
已停用叢集模式的叢集不支援叢集探索命令,也不相容於所有用戶端動態拓撲探索功能。
與 停用的叢集模式與 Lettuce 的 ElastiCache 不相容MasterSlaveTopologyRefresh
。相反地,對於停用的叢集模式,您可以設定 StaticMasterReplicaTopologyProvider
並提供叢集讀取和寫入端點。
如需連接至已停用叢集模式之叢集的詳細資訊,請參閱 尋找 Valkey 或 Redis OSS(停用叢集模式) 叢集的端點 (主控台)。
如果您想要使用 Lettuce 的動態拓撲探索功能,可以使用與現有叢集相同的碎片組態來建立已啟用叢集模式的叢集。不過,對於已啟用叢集模式的叢集,建議至少設定 3 個具有至少 1 個複本的碎片,以支援快速容錯移轉。
啟用 enablePeriodicRefresh
啟用此選項後,您可以將此工作新增至背景任務,以減少與重新整理叢集拓撲相關的延遲。雖然拓撲重新整理是在背景工作中執行,但對於具有許多節點的叢集而言,可能會有些慢。這是因為所有節點都在查詢其檢視以取得最新的叢集檢視。如果您執行的是大型叢集,則可能需要增加期間。
啟用 enableAllAdaptiveRefreshTriggers
啟用 closeStaleConnections
啟用 dynamicRefreshResources
使用動態重新整理查詢所有探索到的叢集拓撲節點,並嘗試選擇最準確的叢集檢視。如果其設定為 false,則只會使用初始種子節點做為拓撲探索的來源,而且只會取得初始種子節點的用戶端數量。在停用時,如果叢集配置端點解析為故障的節點,則嘗試重新整理叢集檢視會失敗,並導致例外狀況。這種情況可能會發生,因為從叢集組態端點移除故障節點的項目需要一些時間。因此,組態端點仍可在短時間內隨機解析為故障的節點。
但是,在其啟用後,我們會使用從叢集檢視接收到的所有叢集節點,來查詢其目前的檢視。因為我們會從該檢視中篩選出故障的節點,所以拓撲重新整理將會成功。但是,如果 dynamicRefreshSources 為 true,Letce 會查詢所有節點以取得叢集檢視,然後比較結果。因此,對於具有大量節點的叢集來說,它可能很昂貴。建議您在多節點的叢集時關閉此功能。
final ClusterTopologyRefreshOptions topologyOptions = ClusterTopologyRefreshOptions.builder() .enableAllAdaptiveRefreshTriggers() .enablePeriodicRefresh() .dynamicRefreshSources(true) .build();
ClientResources
DnsResolver
reconnectDelay
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、、KEYS、 SMEMBERS或 Lua FLUSHALL指令碼。針對單一金鑰命令使用較短的逾時,例如 GET、 SET和 HSET。
注意
下列範例中設定的逾時,適用於執行 SET/GET 命令的測試,其金鑰和值的長度上限為 20 位元組。在指令很複雜或金鑰和值較大時,處理時間可能會更長。您應該根據應用程式的使用案例設定逾時。
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();