Lettuce クライアント設定 (Valkey と Redis OSS) - Amazon ElastiCache

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

Lettuce クライアント設定 (Valkey と Redis OSS)

このセクションでは、推奨される 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名前エントリを使用するため、 を 5 ~ 10 秒TTLの低さJVMに設定することをお勧めします。これにより、ノードの IP アドレスが変更されると、アプリケーションはDNSエントリを再クエリすることで、リソースの新しい IP アドレスを受信して使用できます。

一部の Java 設定では、 JVMが再起動されるまでDNSエントリが更新されないようにJVMデフォルトTTLが設定されます。

の設定方法の詳細についてはTTL、JVM「 の設定方法TTLJVM」を参照してください。

Lettuce のバージョン

Lettuce のバージョン 6.2.2 以降の使用をお勧めします。

エンドポイント

クラスターモードが有効なクラスターを使用している場合は、redisUri をクラスター設定エンドポイントに設定します。このDNSルックアップは、クラスター内で使用可能なすべてのノードのリストURIを返し、クラスターの初期化中にランダムにそのうちの 1 つに解決されます。トポロジの更新の仕組みの詳細については、このトピックの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 に設定して使用するのが最適です。そうしないと、1 つの問題のあるシードノードからトポロジビューを取得すると、一部のシャードのプライマリノードに障害が発生していると見なされ、このプライマリノードは除外され、スロットがカバーされなくなります。複数のシードノード ( DynamicRefreshSources が true の場合) があると、少なくとも一部のシードノードで、新しく昇格したプライマリでのフェイルオーバー後にトポロジビューが更新される必要があるため、この問題が発生する可能性が低くなります。

ClusterTopologyRefreshOptions: クラスターモード対応クライアントのクラスタートポロジの更新を制御するオプション

注記

クラスターモードが無効なクラスターは、クラスター検出コマンドをサポートしていないため、すべてのクライアントの動的トポロジー検出機能と互換性があるわけではありません。

で無効になっているクラスターモード ElastiCache は、Lettuce の と互換性がありませんMasterSlaveTopologyRefresh。代わりに、クラスタモードが無効になっている場合は、StaticMasterReplicaTopologyProvider を設定し、クラスターの読み取りと書き込みのエンドポイントを提供します。

クラスターモードが無効なクラスターとの接続の詳細については、「Valkey または Redis OSS (クラスターモードが無効) クラスターのエンドポイントの検索 (コンソール)」を参照してください。

Lettuce の動的トポロジー検出機能を使いたい場合は、既存のクラスターと同じシャード構成でクラスターモードが有効なクラスターを作成できます。ただし、クラスターモードが有効なクラスターでは、高速フェールオーバーをサポートするために、少なくとも 3 つのシャードと 1 つのレプリカを構成することをお勧めします。

を有効にしますenablePeriodicRefresh。これにより、クラスタートポロジーの定期的な更新が可能になり、クライアントはクラスタートポロジーを の間隔 refreshPeriod (デフォルト: 60 秒) で更新します。無効にすると、クライアントはクラスターに対してコマンドの実行を試みたときにエラーが発生した場合にのみ、クラスタートポロジを更新します。

このオプションを有効にすると、このジョブをバックグラウンドタスクに追加することで、クラスタートポロジの更新に伴うレイテンシを減らすことができます。トポロジの更新はバックグラウンドジョブで実行されますが、多数のノードがあるクラスターでは多少遅くなる可能性があります。これは、すべてのノードが最新のクラスタービューを取得するためにそれらのビューに対してクエリが実行されているためです。大規模なクラスターを実行する場合は、この時間を長くすることをお勧めします。

を有効にしますenableAllAdaptiveRefreshTriggers。これにより、_、MOVED_REDIRECT、ASK_REDIRECT、PERSISTENT_RECONNECTS、UNCOVERED_ のすべてのトリガーを使用するアダプティブトポロジの更新が可能になりますSLOTUNKNOWNNODE。アダプティブ更新トリガーは、Valkey または Redis OSSクラスターオペレーション中に発生するイベントに基づいてトポロジビューの更新を開始します。このオプションを有効にすると、前述のトリガーのいずれかが発生すると、トポロジがすぐに更新されます。適応型更新トリガーは、イベントが大規模で発生する可能性があるため (更新間のデフォルトタイムアウトは 30)、タイムアウトを使用してレート制限されます。

を有効にしますcloseStaleConnections。これにより、クラスタートポロジを更新するときに、古い接続を閉じることができます。ClusterTopologyRefreshOptions.isPeriodicRefreshEnabled() が true の場合にのみ有効になります。有効にすると、クライアントは古い接続を閉じて新しい接続をバックグラウンドで作成できます。これにより、コマンドのランタイムに失敗した接続を処理する必要が減ります。

を有効にしますdynamicRefreshResources。小さいクラスターでは を有効に dynamicRefreshResourcesし、大きいクラスターでは無効にすることをお勧めします。 dynamicRefreshResources は、提供されたシードノード (クラスター設定エンドポイントなど) からクラスターノードを検出します。検出されたすべてのノードを、クラスタートポロジを更新するためのソースとして使用します。

動的更新を使用すると、検出されたすべてのノードにクラスタートポロジを照会し、最も正確なクラスタービューを選択しようと試みます。false に設定すると、最初のシードノードのみがトポロジ検出のソースとして使用され、クライアント数は最初のシードノードについてのみ取得されます。無効になっている場合、クラスター設定エンドポイントが障害の発生したノードに解決されたとき、クラスタービューを更新しようとすると失敗し、例外が発生します。このシナリオは、障害が発生したノードのエントリがクラスター設定エンドポイントから削除されるまでに時間がかかるときに発生する可能性があります。そのため、設定エンドポイントは、障害が発生したノードに短期間ランダムに解決できます。

ただし、有効にすると、クラスタービューから受信したすべてのクラスターノードを使用して、現在のビューについてクエリを実行します。障害が発生したノードをそのビューから除外するので、トポロジ更新は成功します。ただし、 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();

Timeouts

コマンドのタイムアウトよりも低い接続タイムアウト値を使用してください。Lettuce はレイジー接続確立を使用します。そのため、接続タイムアウトがコマンドタイムアウトよりも大きい場合、Lettuce が異常なノードへの接続を試みてコマンドのタイムアウトが常に超過すると、トポロジ更新後に障害が一定期間持続する可能性があります。

異なるコマンドに対しては動的コマンドタイムアウトを使用してください。コマンドの想定期間に基づいてコマンドタイムアウトを設定することをお勧めします。例えば、FLUSHDB、、、、、または Lua スクリプトなど、複数のキーで反復するコマンドにはFLUSHALLKEYSSMEMBERS、より長いタイムアウトを使用します。、、 などの単一キーコマンドにはSETGET、短いタイムアウトを使用しますHSET。

注記

次の例で設定されているタイムアウトは、キーと値が 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();