

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

# ElastiCache のベストプラクティスとキャッシュ戦略
<a name="BestPractices"></a>

Amazon ElastiCache の推奨されるベストプラクティスを以下に紹介します。これらに従うと、キャッシュのパフォーマンスと信頼性が向上します。

**Topics**
+ [全般的なベストプラクティス](WorkingWithRedis.md)
+ [リードレプリカの使用に関するベストプラクティス](ReadReplicas.md)
+ [サポートおよび制限されている Valkey、Memcached および Redis OSS のコマンド](SupportedCommands.md)
+ [Valkey と Redis OSS の設定と制限](RedisConfiguration.md)
+ [Valkey、Memcached、および Redis OSS の IPv6 クライアント例](network-type-best-practices.md)
+ [クライアントのベストプラクティス (Valkey および Redis OSS)](BestPractices.Clients.redis.md)
+ [クライアントのベストプラクティス (Memcached)](BestPractices.Clients.memcached.md)
+ [TLS が有効なデュアルスタック ElastiCache クラスター](#network-type-configuring-tls-enabled-dual-stack)
+ [Valkey および Redis OSS の予約済みメモリを管理する](redis-memory-management.md)
+ [Valkey および Redis OSS のノードベースのクラスターを使用する場合のベストプラクティス](BestPractices.SelfDesigned.md)
+ [Memcached のキャッシュ戦略](Strategies.md)

# 全般的なベストプラクティス
<a name="WorkingWithRedis"></a>

以下に、ElastiCache 内で Valkey、Memcached、および Redis OSS のインターフェースを使用するためのベスト プラクティスに関する情報を示します。
+ **クラスターモード対応の構成を使用する** — クラスターモードを有効にすると、キャッシュを水平方向にスケールして、クラスターモードを無効にした構成よりもストレージとスループットを向上できます。ElastiCache サーバーレスは、クラスターモードが有効な構成でのみ使用できます。
+ **存続期間の長い接続を使用する** — 新しい接続の作成にはコストと時間がかかり、キャッシュの CPU リソースが消費されます。できれば (接続プーリングなどで) 接続を再利用して、こうしたコストを多くのコマンドで分担します。
+ **レプリカから読み取る** — ElastiCache サーバーレスを使用している場合や、リードレプリカ (ノードベースのクラスター) をプロビジョニングしている場合は、読み取りをレプリカに転送してスケーラビリティを向上し、レイテンシーを軽減させます。レプリカからの読み取りには、プライマリとの結果整合性があります。

  ノードベースのクラスターでは、読み取りリクエストの転送先を単一のリードレプリカに限定しないでください。そのノードで障害が起きると、一時的に読み取りができなくなる可能性があります。読み取りリクエストを少なくとも 2 つのリードレプリカに転送するか、1 つのレプリカとプライマリに転送するようにクライアントを設定してください。

  ElastiCache サーバーレスでは、レプリカポート (6380) からの読み取りは、可能な限りクライアントのローカルアベイラビリティーゾーンに転送されるため、取得レイテンシーが軽減されます。障害発生時には、自動的に他のノードにフォールバックします。
+ **コストの高いコマンドを避ける** – `KEYS` や `SMEMBERS` コマンドのような、計算コストが高いオペレーションや入出力量の多いオペレーションを避けてください。これらのオペレーションでは、クラスターへの負荷が増えてクラスターのパフォーマンスに影響するため、これらを避けるアプローチをお勧めします。代わりに、`SCAN` コマンドおよび `SSCAN` コマンドを使用します。
+ **Lua のベストプラクティスに従う** – 長時間実行する Lua スクリプトを避け、常に Lua スクリプトで使用されているキーを前に宣言します。Lua スクリプトがクロススロットコマンドを使用していないことを確認するために、この方法をお勧めします。Lua スクリプトで使用されるキーが同じスロットに属していることを確認します。
+ **シャードされた pub/sub を使用する** — Redis OSS を使用して高スループットの Pub/Sub ワークロードをサポートする場合は、[シャードされた Pub/Sub](https://valkey.io/topics/pubsub/) (Valkey、Redis OSS 7 以降で利用可能) の使用をお勧めします。クラスターモードが有効なクラスターにおける従来の Pub/Sub は、クラスター内のすべてのノードにメッセージをブロードキャストするため、`EngineCPUUtilization` が高くなる可能性があります。ElastiCache サーバーレスでは、従来の Pub/Sub コマンドは内部的には、シャードされた Pub/Sub コマンドを使用する点に注意してください。

**Topics**

# リードレプリカの使用に関するベストプラクティス
<a name="ReadReplicas"></a>

セッションストア、リーダーボード、レコメンデーションエンジンなど多くのアプリケーションは、高可用性を必要とし、書き込みオペレーションよりも大幅に多くの読み取りオペレーションを処理します。これらのアプリケーションでは、多少古いデータ (結果整合性) が許容されることがよくあります。つまり、異なるユーザーが同じデータのわずかに異なるバージョンを一時的に表示しても許容されるということです。例えば、次のようになります。
+ キャッシュされたクエリ結果は、特に信頼できるソースが外部にあるキャッシュアサイドパターンの場合、多少古いデータを許容できることがよくあります。
+ ゲームリーダーボードでは、更新されたスコアに数秒の遅延があっても、ユーザーエクスペリエンスには大きな影響が及ばないことがよくあります。
+ セッションストアの場合、レプリカ間でのセッションデータの伝播にわずかな遅延が生じても、アプリケーションの機能にはほとんど影響しません。
+ レコメンデーションエンジンは通常、履歴データ分析を使用するため、リアルタイムの一貫性はそれほど重要ではありません。

結果整合性とは、レプリケーションプロセスが完了すると、通常はミリ秒以内に、すべてのレプリカノードが最終的に同じデータを返すことを意味します。このようなユースケースの場合、リードレプリカを実装することは、ElastiCache インスタンスから読み取る際のレイテンシーを低減する効果的な戦略です。

Amazon ElastiCache でリードレプリカを使用すると、次を通じて大幅なパフォーマンス向上が期待できます。

**読み取りスケーラビリティの拡張**
+ 読み取りオペレーションを複数のレプリカノードに分散する
+ プライマリノードからの読み取りトラフィックをオフロードする
+ 地理的により近いレプリカからのリクエストを処理して読み取りレイテンシーを削減する

**プライマリノードのパフォーマンスの最適化**
+ プライマリノードリソースを書き込みオペレーション専用にする
+ プライマリノードの接続オーバーヘッドを削減する
+ 書き込みパフォーマンスを向上させ、トラフィックのピーク時もより優れた応答時間を維持する

## ElastiCache サーバーレスでのレプリカからの読み取りの使用
<a name="ReadReplicas.serverless"></a>

ElastiCache サーバーレスは、異なる整合性要件に対して 2 つの異なるエンドポイントを提供します。2 つのエンドポイントは同じ DNS 名を使用しますが、ポートは異なります。レプリカからの読み取りポートを使用するには、[VPC のセキュリティグループとネットワークアクセスコントロールリストを設定](set-up.md#elasticache-install-grant-access-VPN)して、クライアントアプリケーションから両方のポートへのアクセスを許可する必要があります。

**プライマリエンドポイント (ポート 6379)**
+ 即時整合性を必要とするオペレーションに使用する
+ 最新データの読み取りを保証する
+ 重要なトランザクションと書き込みオペレーションに最適
+ 書き込みオペレーションに必要
+ 例: `test-12345.serverless.use1.cache.amazonaws.com:6379`

**レイテンシー最適化エンドポイント (ポート 6380)**
+ 結果整合性を許容できる読み取りオペレーション用に最適化
+ 可能な場合、ElastiCache サーバーレスは読み取りリクエストをクライアントのローカルのアベイラビリティーゾーン内にあるレプリカノードに自動的にルーティングします。この最適化により、異なるアベイラビリティーゾーンのノードからデータを取得する際に発生する追加のネットワーク遅延を回避し、レイテンシーを低減することができます。
+ ElastiCache サーバーレスは、ローカルノードが利用できない場合、他のゾーンの利用可能なノードを自動的に選択します。
+ 例: `test-12345.serverless.use1.cache.amazonaws.com:6380`
+ Glide や Lettuce などのクライアントは、レプリカからの読み取り設定が指定された場合、自動的に読み取りを検出して、レイテンシー最適化エンドポイントにルーティングします。クライアントがルーティング設定をサポートしていない場合 (例: valkey-java や古いバージョンの jedis)、レプリカから読み取るための適切なポートとクライアント設定を定義する必要があります。

## ElastiCache サーバーレスでのリードレプリカへの接続 - Valkey と Glide
<a name="ReadReplicas.connecting-primary"></a>

次のコードスニペットは、Valkey glide ライブラリで ElastiCache サーバーレスのレプリカからの読み取りを設定する方法を示しています。レプリカからの読み取りにポートを指定する必要はありませんが、ルーティング設定 `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());
                }
            }
        }
    }
}
```

# サポートおよび制限されている Valkey、Memcached および Redis OSS のコマンド
<a name="SupportedCommands"></a>

## サポートされている Valkey および Redis OSS のコマンド
<a name="SupportedCommandsRedis"></a>

**サポートされている Valkey および Redis OSS のコマンド**

次の Valkey および Redis OSS のコマンドはサーバーレスキャッシュでサポートされています。これらのコマンドに加えて、これらの [サポートされている Valkey および Redis OSS のコマンドJSON コマンド](json-list-commands.md) もサポートされています。

Bloom フィルターコマンドについては、「[Bloom フィルターコマンド](BloomFilters.md#SupportedCommandsBloom)」を参照してください

**ビットマップコマンド**
+ `BITCOUNT`

  文字列内の設定されているビット数をカウントします (母集団計数)。

  [詳細はこちら](https://valkey.io/commands/bitcount/)
+ `BITFIELD`

  文字列に対して任意のビットフィールド整数演算を実行します。

  [詳細はこちら](https://valkey.io/commands/bitfield/)
+ `BITFIELD_RO`

  文字列に対して任意の読み取り専用ビットフィールド整数演算を実行します。

  [詳細はこちら](https://valkey.io/commands/bitfield_ro/)
+ `BITOP`

  複数の文字列に対してビット演算を行い、結果を格納します。

  [詳細はこちら](https://valkey.io/commands/bitop/)
+ `BITPOS`

  文字列の最初の設定されている (1) ビットまたはクリア (0) ビットを検索します。

  [詳細はこちら](https://valkey.io/commands/bitpos/)
+ `GETBIT`

  ビット値をオフセットで返します。

  [詳細はこちら](https://valkey.io/commands/getbit/)
+ `SETBIT`

  文字列値のオフセットのビットを設定またはクリアします。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/setbit/)

**クラスター管理コマンド**
+ `CLUSTER COUNTKEYSINSLOT`

  ハッシュスロット内のキーの数を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-countkeysinslot/)
+ `CLUSTER GETKEYSINSLOT`

  ハッシュスロット内のキーの名前を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-getkeysinslot/)
+ `CLUSTER INFO`

  ノードの状態に関する情報を返します。サーバーレスキャッシュでは、クライアントに公開されている 1 つの仮想「シャード」に関する状態を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-info/)
+ `CLUSTER KEYSLOT`

  キーのハッシュスロットを返します。

  [詳細はこちら](https://valkey.io/commands/cluster-keyslot/)
+ `CLUSTER MYID`

  ノードの ID を返します。サーバーレスキャッシュでは、クライアントに公開されている 1 つの仮想「シャード」に関する状態を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-myid/)
+ `CLUSTER NODES`

  ノードのクラスター構成を返します。サーバーレスキャッシュでは、クライアントに公開されている 1 つの仮想「シャード」に関する状態を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-nodes/)
+ `CLUSTER REPLICAS`

  マスターノードのレプリカノードを一覧表示します。サーバーレスキャッシュでは、クライアントに公開されている 1 つの仮想「シャード」に関する状態を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-replicas/)
+ `CLUSTER SHARDS`

  クラスタースロットとシャードのマッピングを返します。サーバーレスキャッシュでは、クライアントに公開されている 1 つの仮想「シャード」に関する状態を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-shards/)
+ `CLUSTER SLOTS`

  クラスタースロットとノードのマッピングを返します。サーバーレスキャッシュでは、クライアントに公開されている 1 つの仮想「シャード」に関する状態を返します。

  [詳細はこちら](https://valkey.io/commands/cluster-slots/)
+ `CLUSTER SLOT-STATS`

  キー数、CPU 使用率、ネットワーク入力バイト数、ネットワーク出力バイト数のスロットごとのメトリクスの追跡を許可します。

  [詳細はこちら](https://valkey.io/commands/cluster-slot-stats/)
+ `READONLY`

  Valkey または Redis OSS クラスターレプリカノードへの接続に対する読み取り専用クエリを有効にします。

  [詳細はこちら](https://valkey.io/commands/readonly/)
+ `READWRITE`

  Valkey または Redis OSS クラスターレプリカノードへの接続に対する読み取り/書き込みクエリを有効にします。

  [詳細はこちら](https://valkey.io/commands/readwrite/)
+ `SCRIPT SHOW`

  スクリプトキャッシュ内のスクリプトの元のソースコードを返します。

  [詳細はこちら](https://valkey.io/commands/script-show/)

**接続管理コマンド**
+ `AUTH`

  接続を認証します。

  [詳細はこちら](https://valkey.io/commands/auth/)
+ `CLIENT GETNAME`

  接続の名前を返します。

  [詳細はこちら](https://valkey.io/commands/client-getname/)
+ `CLIENT REPLY`

  コマンドに応答するかどうかをサーバーに指示します。

  [詳細はこちら](https://valkey.io/commands/client-reply/)
+ `CLIENT SETNAME`

  接続名を設定します。

  [詳細はこちら](https://valkey.io/commands/client-setname/)
+ `ECHO`

  指定された文字列を返します。

  [詳細はこちら](https://valkey.io/commands/echo/)
+ `HELLO`

  Valkey または Redis OSS サーバーとハンドシェイクします。

  [詳細はこちら](https://valkey.io/commands/hello/)
+ `PING`

  サーバーのライブネスレスポンスを返します。

  [詳細はこちら](https://valkey.io/commands/ping/)
+ `QUIT`

  接続を閉じます。

  [詳細はこちら](https://valkey.io/commands/quit/)
+ `RESET`

  接続をリセットします。

  [詳細はこちら](https://valkey.io/commands/reset/)
+ `SELECT`

  選択したデータベースを変更します。

  [詳細はこちら](https://valkey.io/commands/select/)

**汎用コマンド**
+ `COPY`

  キーの値を新しいキーにコピーします。

  [詳細はこちら](https://valkey.io/commands/copy/)
+ `DEL`

  1 つまたは複数のキーを削除します。

  [詳細はこちら](https://valkey.io/commands/del/)
+ `DUMP`

  キーに格納されている値をシリアル化して返します。

  [詳細はこちら](https://valkey.io/commands/dump/)
+ `EXISTS`

  1 つまたは複数のキーが存在するかどうかを判定します。

  [詳細はこちら](https://valkey.io/commands/exists/)
+ `EXPIRE`

  キーの有効期限を秒単位で設定します。

  [詳細はこちら](https://valkey.io/commands/expire/)
+ `EXPIREAT`

  キーの有効期限を Unix タイムスタンプに設定します。

  [詳細はこちら](https://valkey.io/commands/expireat/)
+ `EXPIRETIME`

  キーの有効期限を Unix タイムスタンプとして返します。

  [詳細はこちら](https://valkey.io/commands/expiretime/)
+ `PERSIST`

  キーの有効期限を削除します。

  [詳細はこちら](https://valkey.io/commands/persist/)
+ `PEXPIRE`

  キーの有効期限をミリ秒単位で設定します。

  [詳細はこちら](https://valkey.io/commands/pexpire/)
+ `PEXPIREAT`

  キーの有効期限を Unix タイムスタンプに設定します。

  [詳細はこちら](https://valkey.io/commands/pexpireat/)
+ `PEXPIRETIME`

  キーの有効期限を Unix ミリ秒タイムスタンプとして返します。

  [詳細はこちら](https://valkey.io/commands/pexpiretime/)
+ `PTTL`

  キーのミリ秒単位の有効期限を返します。

  [詳細はこちら](https://valkey.io/commands/pttl/)
+ `RANDOMKEY`

  データベースからランダムなキー名を返します。

  [詳細はこちら](https://valkey.io/commands/randomkey/)
+ `RENAME`

  キーの名前を変更し、変更先を上書きします。

  [詳細はこちら](https://valkey.io/commands/rename/)
+ `RENAMENX`

  ターゲットのキー名が存在しない場合にのみキーの名前を変更します。

  [詳細はこちら](https://valkey.io/commands/renamenx/)
+ `RESTORE`

  シリアル化された値の表現からキーを作成します。

  [詳細はこちら](https://valkey.io/commands/restore/)
+ `SCAN`

  データベース内のキー名を繰り返し処理します。

  [詳細はこちら](https://valkey.io/commands/scan/)
+ `SORT`

  リスト、セット、またはソートセット内の要素をソートし、オプションで結果を格納します。

  [詳細はこちら](https://valkey.io/commands/sort/)
+ `SORT_RO`

  リスト、セット、またはソートされたセットのソートされた要素を返します。

  [詳細はこちら](https://valkey.io/commands/sort_ro/)
+ `TOUCH`

  指定したキーのうち、最後にアクセスされた時刻を更新したキーの数を返します。

  [詳細はこちら](https://valkey.io/commands/touch/)
+ `TTL`

  キーの秒単位の有効期限を返します。

  [詳細はこちら](https://valkey.io/commands/ttl/)
+ `TYPE`

  キーに格納されている値のタイプを決定します。

  [詳細はこちら](https://valkey.io/commands/type/)
+ `UNLINK`

  1 つまたは複数のキーを非同期的に削除します。

  [詳細はこちら](https://valkey.io/commands/unlink/)

**地理空間コマンド**
+ `GEOADD`

  地理空間インデックスに 1 つまたは複数のメンバーを追加します。キーが存在しない場合はキーが作成されます。

  [詳細はこちら](https://valkey.io/commands/geoadd/)
+ `GEODIST`

  地理空間インデックスの 2 つのメンバー間の距離を返します。

  [詳細はこちら](https://valkey.io/commands/geodist/)
+ `GEOHASH`

  地理空間インデックスのメンバーをジオハッシュ文字列として返します。

  [詳細はこちら](https://valkey.io/commands/geohash/)
+ `GEOPOS`

  地理空間インデックスからメンバーの経度と緯度を返します。

  [詳細はこちら](https://valkey.io/commands/geopos/)
+ `GEORADIUS`

  指定した座標から特定の距離内にあるメンバーの地理空間インデックスを照会し、オプションで結果を格納します。

  [詳細はこちら](https://valkey.io/commands/georadius/)
+ `GEORADIUS_RO`

  地理空間インデックスから、指定した座標から特定の距離内にあるメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/georadius_ro/)
+ `GEORADIUSBYMEMBER`

  指定したメンバーから特定の距離内にあるメンバーの地理空間インデックスを照会し、オプションで結果を格納します。

  [詳細はこちら](https://valkey.io/commands/georadiusbymember/)
+ `GEORADIUSBYMEMBER_RO`

  地理空間インデックスから、指定したメンバーから特定の距離内にあるメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/georadiusbymember_ro/)
+ `GEOSEARCH`

  ボックスまたは円の領域内のメンバーの地理空間インデックスを照会します。

  [詳細はこちら](https://valkey.io/commands/geosearch/)
+ `GEOSEARCHSTORE`

  ボックスまたは円の領域内のメンバーの地理空間インデックスを照会し、オプションで結果を格納します。

  [詳細はこちら](https://valkey.io/commands/geosearchstore/)

**ハッシュコマンド**
+ `HDEL`

  1 つまたは複数のフィールドとその値をハッシュから削除します。フィールドが残っていない場合はハッシュを削除します。

  [詳細はこちら](https://valkey.io/commands/hdel/)
+ `HEXISTS`

  ハッシュにフィールドが存在するかどうかを判定します。

  [詳細はこちら](https://valkey.io/commands/hexists/)
+ `HGET`

  ハッシュ内のフィールドの値を返します。

  [詳細はこちら](https://valkey.io/commands/hget/)
+ `HGETALL`

  ハッシュ内のすべてのフィールドと値を返します。

  [詳細はこちら](https://valkey.io/commands/hgetall/)
+ `HINCRBY`

  ハッシュ内のフィールドの整数値を数値分増やします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/hincrby/)
+ `HINCRBYFLOAT`

  ハッシュ内のフィールドの浮動小数点値を数値分増やします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/hincrbyfloat/)
+ `HKEYS`

  ハッシュ内のすべてのフィールドを返します。

  [詳細はこちら](https://valkey.io/commands/hkeys/)
+ `HLEN`

  ハッシュ内のフィールドの数を返します。

  [詳細はこちら](https://valkey.io/commands/hlen/)
+ `HMGET`

  ハッシュ内のすべてのフィールドを返します。

  [詳細はこちら](https://valkey.io/commands/hmget/)
+ `HMSET`

  複数のフィールドの値を設定します。

  [詳細はこちら](https://valkey.io/commands/hmset/)
+ `HRANDFIELD`

  ハッシュから 1 つまたは複数のランダムフィールドを返します。

  [詳細はこちら](https://valkey.io/commands/hrandfield/)
+ `HSCAN`

  ハッシュのフィールドと値を反復処理します。

  [詳細はこちら](https://valkey.io/commands/hscan/)
+ `HSET`

  ハッシュ内のフィールドの値を作成または変更します。

  [詳細はこちら](https://valkey.io/commands/hset/)
+ `HSETNX`

  フィールドが存在しない場合にのみ、ハッシュ内のフィールドの値を設定します。

  [詳細はこちら](https://valkey.io/commands/hsetnx/)
+ `HSTRLEN`

  フィールドの値の長さを返します。

  [詳細はこちら](https://valkey.io/commands/hstrlen/)
+ `HVALS`

  ハッシュ内のすべての値を返します。

  [詳細はこちら](https://valkey.io/commands/hvals/)

**HyperLogLog コマンド**
+ `PFADD`

  HyperLogLog キーに要素を追加します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/pfadd/)
+ `PFCOUNT`

  HyperLogLog キーで観測されたセットのおおよそのカーディナリティを返します。

  [詳細はこちら](https://valkey.io/commands/pfcount/)
+ `PFMERGE`

  1 つまたは複数の HyperLogLog 値を 1 つのキーにマージします。

  [詳細はこちら](https://valkey.io/commands/pfmerge/)

**リストコマンド**
+ `BLMOVE`

  リストから要素を取り出し、別のリストにプッシュして返します。要素が利用可能になるまでブロックします。最後の要素を移動した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/blmove/)
+ `BLMPOP`

  複数のリストのうちの 1 つから最初の要素を取り出します。要素が利用可能になるまでブロックします。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/blmpop/)
+ `BLPOP`

  リストの最初の要素を削除して返します。要素が利用可能になるまでブロックします。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/blpop/)
+ `BRPOP`

  リストの最後の要素を削除して返します。要素が利用可能になるまでブロックします。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/brpop/)
+ `BRPOPLPUSH`

  リストから要素を取り出し、別のリストにプッシュして返します。要素が利用可能になるまでブロックします。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/brpoplpush/)
+ `LINDEX`

  リストの要素をインデックスで返します。

  [詳細はこちら](https://valkey.io/commands/lindex/)
+ `LINSERT`

  リスト内の別の要素の前または後に要素を挿入します。

  [詳細はこちら](https://valkey.io/commands/linsert/)
+ `LLEN`

  リストの長さを返します。

  [詳細はこちら](https://valkey.io/commands/llen/)
+ `LMOVE`

  あるリストから取り出して別のリストにプッシュした要素を返します。最後の要素を移動した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/lmove/)
+ `LMPOP`

  リストから複数の要素を削除して返します。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/lmpop/)
+ `LPOP`

  リストの最初の要素を削除して返します。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/lpop/)
+ `LPOS`

  リスト内の一致する要素のインデックスを返します。

  [詳細はこちら](https://valkey.io/commands/lpos/)
+ `LPUSH`

  1 つまたは複数の要素をリストの先頭に追加します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/lpush/)
+ `LPUSHX`

  リストが存在する場合のみ、1 つまたは複数の要素をリストの先頭に追加します。

  [詳細はこちら](https://valkey.io/commands/lpushx/)
+ `LRANGE`

  リストから一定範囲の要素を返します。

  [詳細はこちら](https://valkey.io/commands/lrange/)
+ `LREM`

  リストから要素を削除します。最後の要素を削除した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/lrem/)
+ `LSET`

  リスト内の要素の値をインデックスで設定します。

  [詳細はこちら](https://valkey.io/commands/lset/)
+ `LTRIM`

  リストの両端から要素を削除します。すべての要素をトリムした場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/ltrim/)
+ `RPOP`

  リストの最後の要素を削除して返します。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/rpop/)
+ `RPOPLPUSH`

  リストの最後の要素を削除して別のリストにプッシュした後、その要素を返します。最後の要素を取り出した場合はリストを削除します。

  [詳細はこちら](https://valkey.io/commands/rpoplpush/)
+ `RPUSH`

  1 つまたは複数の要素をリストに追加します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/rpush/)
+ `RPUSHX`

  リストが存在する場合のみ、リストに要素を追加します。

  [詳細はこちら](https://valkey.io/commands/rpushx/)

**Pub/Sub コマンド**

**注記**  
PUBSUB コマンドはシャード化された PUBSUB を内部的に使用するため、チャンネル名は混在することになります。
+ `PUBLISH`

  チャネルにメッセージを投稿します。

  [詳細はこちら](https://valkey.io/commands/publish/)
+ `PUBSUB CHANNELS`

  アクティブなチャネルを返します。

  [詳細はこちら](https://valkey.io/commands/pubsub-channels/)
+ `PUBSUB NUMSUB`

  チャネルのサブスクライバーを返します。

  [詳細はこちら](https://valkey.io/commands/pubsub-numsub/)
+ `PUBSUB SHARDCHANNELS`

  アクティブなシャードチャネルを返します。

  [詳細はこちら](https://valkey.io/commands/pubsub-shardchannels/)
+ `PUBSUB SHARDNUMSUB`

  シャードチャネルのサブスクライバー数を返します。

  [詳細はこちら](https://valkey.io/commands/pubsub-shardnumsub/)
+ `SPUBLISH`

  シャードチャネルにメッセージを投稿します。

  [詳細はこちら](https://valkey.io/commands/spublish/)
+ `SSUBSCRIBE`

  シャードチャネルに公開されたメッセージをリスニングします。

  [詳細はこちら](https://valkey.io/commands/ssubscribe/)
+ `SUBSCRIBE`

  チャネルに公開されたメッセージをリスニングします。

  [詳細はこちら](https://valkey.io/commands/subscribe/)
+ `SUNSUBSCRIBE`

  シャードチャンネルに投稿されたメッセージのリスニングを停止します。

  [詳細はこちら](https://valkey.io/commands/sunsubscribe/)
+ `UNSUBSCRIBE`

  チャンネルに投稿されたメッセージのリスニングを停止します。

  [詳細はこちら](https://valkey.io/commands/unsubscribe/)

**スクリプトコマンド**
+ `EVAL`

  サーバー側 Lua スクリプトを実行します。

  [詳細はこちら](https://valkey.io/commands/eval/)
+ `EVAL_RO`

  読み取り専用のサーバー側 Lua スクリプトを実行します。

  [詳細はこちら](https://valkey.io/commands/eval_ro/)
+ `EVALSHA`

  サーバー側 Lua スクリプトを SHA1 ダイジェストで実行します。

  [詳細はこちら](https://valkey.io/commands/evalsha/)
+ `EVALSHA_RO`

  読み取り専用のサーバー側 Lua スクリプトを SHA1 ダイジェストで実行します。

  [詳細はこちら](https://valkey.io/commands/evalsha_ro/)
+ `SCRIPT EXISTS`

  サーバー側 Lua スクリプトがスクリプトキャッシュに存在するかどうかを判定します。

  [詳細はこちら](https://valkey.io/commands/script-exists/)
+ `SCRIPT FLUSH`

  現在、運用は不要のスクリプトキャッシュがサービスによって管理されています。

  [詳細はこちら](https://valkey.io/commands/script-flush/)
+ `SCRIPT LOAD`

  サーバー側の Lua スクリプトをスクリプトキャッシュに読み込みます。

  [詳細はこちら](https://valkey.io/commands/script-load/)

**サーバー管理コマンド**

**注記**  
Valkey および Redis OSS でノードベースの ElastiCache クラスターを使用する場合、すべてのキーをフラッシュするには、クライアントがすべてのプライマリにフラッシュコマンドを送信する必要があります。ElastiCache Serverless for Valkey と ElastiCache Serverless for Redis OSS は、基盤となるクラスタートポロジを抽象化するため、動作が異なります。その結果、ElastiCache Serverless では、`FLUSHDB` コマンドと `FLUSHALL` コマンドは常にクラスター全体ですべてのキーをフラッシュします。このため、フラッシュコマンドをサーバーレストランザクションに含めることはできません。
+ `ACL CAT`

  ACL カテゴリ、またはカテゴリ内のコマンドを一覧表示します。

  [詳細はこちら](https://valkey.io/commands/acl-cat/)
+ `ACL GENPASS`

  ACL ユーザーの識別に使用できる疑似ランダムで安全なパスワードを生成します。

  [詳細はこちら](https://valkey.io/commands/acl-genpass/)
+ `ACL GETUSER`

  ユーザーの ACL ルールを一覧表示します。

  [詳細はこちら](https://valkey.io/commands/acl-getuser/)
+ `ACL LIST`

  有効なルールを ACL ファイル形式でダンプします。

  [詳細はこちら](https://valkey.io/commands/acl-list/)
+ `ACL USERS`

  すべての ACL ユーザーを一覧表示します。

  [詳細はこちら](https://valkey.io/commands/acl-users/)
+ `ACL WHOAMI`

  現在の接続の認証済みユーザー名を返します。

  [詳細はこちら](https://valkey.io/commands/acl-whoami/)
+ `DBSIZE`

  現在選択されているデータベース内のキーの数を返します。この操作がすべてのスロットでアトミックになるとは限りません。

  [詳細はこちら](https://valkey.io/commands/dbsize/)
+ `COMMAND`

  すべてのコマンドに関する詳細情報を返します。

  [詳細はこちら](https://valkey.io/commands/command/)
+ `COMMAND COUNT`

  コマンドの数を返します。

  [詳細はこちら](https://valkey.io/commands/command-count/)
+ `COMMAND DOCS`

  1 つ、複数、またはすべてのコマンドに関するドキュメンタリー情報を返します。

  [詳細はこちら](https://valkey.io/commands/command-docs/)
+ `COMMAND GETKEYS`

  任意のコマンドからキー名を抽出します。

  [詳細はこちら](https://valkey.io/commands/command-getkeys/)
+ `COMMAND GETKEYSANDFLAGS`

  任意のコマンドのキー名とアクセスフラグを抽出します。

  [詳細はこちら](https://valkey.io/commands/command-getkeysandflags/)
+ `COMMAND INFO`

  1 つ、複数、またはすべてのコマンドに関する情報を返します。

  [詳細はこちら](https://valkey.io/commands/command-info/)
+ `COMMAND LIST`

  コマンド名のリストを返します。

  [詳細はこちら](https://valkey.io/commands/command-list/)
+ `COMMANDLOG`

  コマンドログコマンドのコンテナ。

  [詳細はこちら](https://valkey.io/commands/commandlog/)
+ `COMMANDLOG GET`

  指定されたコマンドログのエントリを返します。

  [詳細はこちら](https://valkey.io/commands/commandlog-get/)
+ `COMMANDLOG HELP`

  さまざまなサブコマンドに関する有益なテキストを表示します。

  [詳細はこちら](https://valkey.io/commands/commandlog-help/)
+ `COMMANDLOG LEN`

  指定されたタイプのコマンドログのエントリ数を返します。

  [詳細はこちら](https://valkey.io/commands/commandlog-len/)
+ `COMMANDLOG RESET`

  指定されたタイプのコマンドログからすべてのエントリをクリアします。

  [詳細はこちら](https://valkey.io/commands/commandlog-reset/)
+ `FLUSHALL`

  すべてのデータベースからすべてのキーを削除します。この操作がすべてのスロットでアトミックになるとは限りません。

  [詳細はこちら](https://valkey.io/commands/flushall/)
+ `FLUSHDB`

  現在のデータベースからすべてのキーを削除します。この操作がすべてのスロットでアトミックになるとは限りません。

  [詳細はこちら](https://valkey.io/commands/flushdb/)
+ `INFO`

  サーバーに関する情報と統計を返します。

  [詳細はこちら](https://valkey.io/commands/info/)
+ `LOLWUT`

  コンピューターアートと Valkey または Redis OSS バージョンを表示します。

  [詳細はこちら](https://valkey.io/commands/lolwut/)
+ `ROLE`

  レプリケーションロールを返します。

  [詳細はこちら](https://valkey.io/commands/role/)
+ `TIME`

  サーバー時間を返します。

  [詳細はこちら](https://valkey.io/commands/time/)

**集合コマンド**
+ `SADD`

  集合に 1 つまたは複数のメンバーを追加します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/sadd/)
+ `SCARD`

  集合内のメンバー数を返します。

  [詳細はこちら](https://valkey.io/commands/scard/)
+ `SDIFF`

  複数の集合の差を返します。

  [詳細はこちら](https://valkey.io/commands/sdiff/)
+ `SDIFFSTORE`

  複数の集合の差をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/sdiffstore/)
+ `SINTER`

  複数の集合の交差を返します。

  [詳細はこちら](https://valkey.io/commands/sinter/)
+ `SINTERCARD`

  複数の集合の交差のメンバー数を返します。

  [詳細はこちら](https://valkey.io/commands/sintercard/)
+ `SINTERSTORE`

  複数の集合の交差をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/sinterstore/)
+ `SISMEMBER`

  メンバーが集合に属しているかどうかを判定します。

  [詳細はこちら](https://valkey.io/commands/sismember/)
+ `SMEMBERS`

  集合のすべてのメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/smembers/)
+ `SMISMEMBER`

  複数のメンバーが集合に属しているかどうかを判定します。

  [詳細はこちら](https://valkey.io/commands/smismember/)
+ `SMOVE`

  メンバーをある集合から別の集合に移動します。

  [詳細はこちら](https://valkey.io/commands/smove/)
+ `SPOP`

  集合か 1 つまたは複数のメンバーをランダムに削除して返します。最後のメンバーを取り出した場合は集合を削除します。

  [詳細はこちら](https://valkey.io/commands/spop/)
+ `SRANDMEMBER`

  集合から 1 つまたは複数のメンバーをランダムに取得します。

  [詳細はこちら](https://valkey.io/commands/srandmember/)
+ `SREM`

  集合から 1 つまたは複数のメンバーを削除します。最後のメンバーを削除した場合は集合を削除します。

  [詳細はこちら](https://valkey.io/commands/srem/)
+ `SSCAN`

  集合のメンバーを反復処理します。

  [詳細はこちら](https://valkey.io/commands/sscan/)
+ `SUNION`

  複数の集合の和を返します。

  [詳細はこちら](https://valkey.io/commands/sunion/)
+ `SUNIONSTORE`

  複数の集合の和をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/sunionstore/)

**ソート対象集合コマンド**
+ `BZMPOP`

  1 つまたは複数のソート対象集合からメンバーをスコアによって削除して返します。メンバーが使用可能になるまでブロックします。最後の要素を取り出した場合はソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/bzmpop/)
+ `BZPOPMAX`

  1 つまたは複数のソート対象集合からスコアの最も高いメンバーを削除して返します。メンバーが使用可能になるまでブロックします。最後の要素を取り出した場合はソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/bzpopmax/)
+ `BZPOPMIN`

  1 つまたは複数のソート対象集合からスコアの最も低いメンバーを削除して返します。メンバーが使用可能になるまでブロックします。最後の要素を取り出した場合はソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/bzpopmin/)
+ `ZADD`

  ソート対象集合に 1 つまたは複数のメンバーを追加するか、メンバーのスコアを更新します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/zadd/)
+ `ZCARD`

  ソート対象集合内のメンバー数を返します。

  [詳細はこちら](https://valkey.io/commands/zcard/)
+ `ZCOUNT`

  ソート対象集合の中で、スコアが範囲内にあるメンバーの数を返します。

  [詳細はこちら](https://valkey.io/commands/zcount/)
+ `ZDIFF`

  複数のソート対象集合間の差を返します。

  [詳細はこちら](https://valkey.io/commands/zdiff/)
+ `ZDIFFSTORE`

  複数のソート対象集合の差をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/zdiffstore/)
+ `ZINCRBY`

  ソート対象集合内のメンバーのスコアをインクリメントします。

  [詳細はこちら](https://valkey.io/commands/zincrby/)
+ `ZINTER`

  複数のソート対象集合の交差を返します。

  [詳細はこちら](https://valkey.io/commands/zinter/)
+ `ZINTERCARD`

  複数のソート対象集合の交差のメンバー数を返します。

  [詳細はこちら](https://valkey.io/commands/zintercard/)
+ `ZINTERSTORE`

  複数のソート対象集合の交差をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/zinterstore/)
+ `ZLEXCOUNT`

  ソート対象集合の辞書的範囲内のメンバー数を返します。

  [詳細はこちら](https://valkey.io/commands/zlexcount/)
+ `ZMPOP`

  1 つまたは複数のソート対象集合から最高スコアまたは最低スコアのメンバーを削除して返します。最後のメンバーを取り出した場合はソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zmpop/)
+ `ZMSCORE`

  ソート対象集合内の 1 つまたは複数のメンバーのスコアを返します。

  [詳細はこちら](https://valkey.io/commands/zmscore/)
+ `ZPOPMAX`

  1 つまたは複数のソート対象集合から最高スコアのメンバーを削除して返します。最後のメンバーを取り出した場合はソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zpopmax/)
+ `ZPOPMIN`

  1 つまたは複数のソート対象集合から最低スコアのメンバーを削除して返します。最後のメンバーを取り出した場合はソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zpopmin/)
+ `ZRANDMEMBER`

  ソート対象集合から 1 つまたは複数のランダムなメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/zrandmember/)
+ `ZRANGE`

  ソート対象集合のインデックス範囲内のメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/zrange/)
+ `ZRANGEBYLEX`

  ソート対象集合の辞書的範囲内のメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/zrangebylex/)
+ `ZRANGEBYSCORE`

  スコアの範囲内にあるソート対象集合のメンバーを返します。

  [詳細はこちら](https://valkey.io/commands/zrangebyscore/)
+ `ZRANGESTORE`

  ソート対象集合のメンバーの範囲をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/zrangestore/)
+ `ZRANK`

  ソート対象集合内のメンバーのインデックスをスコアの昇順で返します。

  [詳細はこちら](https://valkey.io/commands/zrank/)
+ `ZREM`

  ソート対象集合から 1 つまたは複数のメンバーを削除します。すべてのメンバーを削除した場合、ソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zrem/)
+ `ZREMRANGEBYLEX`

  ソート対象集合の辞書的範囲内のメンバーを削除します。すべてのメンバーを削除した場合、ソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zremrangebylex/)
+ `ZREMRANGEBYRANK`

  ソート対象集合のインデックス範囲内のメンバーを削除します。すべてのメンバーを削除した場合、ソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zremrangebyrank/)
+ `ZREMRANGEBYSCORE`

  スコアの範囲内にあるソート対象集合のメンバーを削除します。すべてのメンバーを削除した場合、ソート対象集合を削除します。

  [詳細はこちら](https://valkey.io/commands/zremrangebyscore/)
+ `ZREVRANGE`

  ソート対象集合のインデックス範囲内のメンバーを逆の順序で返します。

  [詳細はこちら](https://valkey.io/commands/zrevrange/)
+ `ZREVRANGEBYLEX`

  ソート対象集合の辞書的範囲内のメンバーを逆の順序で返します。

  [詳細はこちら](https://valkey.io/commands/zrevrangebylex/)
+ `ZREVRANGEBYSCORE`

  ソート対象集合のスコア範囲内のメンバーを逆の順序で返します。

  [詳細はこちら](https://valkey.io/commands/zrevrangebyscore/)
+ `ZREVRANK`

  ソート対象集合内のメンバーのインデックスをスコアの降順で返します。

  [詳細はこちら](https://valkey.io/commands/zrevrank/)
+ `ZSCAN`

  ソート対象集合のメンバーとスコアを反復処理します。

  [詳細はこちら](https://valkey.io/commands/zscan/)
+ `ZSCORE`

  ソート対象集合内のメンバーのスコアを返します。

  [詳細はこちら](https://valkey.io/commands/zscore/)
+ `ZUNION`

  複数のソート対象集合の和を返します。

  [詳細はこちら](https://valkey.io/commands/zunion/)
+ `ZUNIONSTORE`

  複数のソート対象集合の和をキーに格納します。

  [詳細はこちら](https://valkey.io/commands/zunionstore/)

**ストリームコマンド**
+ `XACK`

  ストリームのコンシューマーグループメンバーによって正常に承認されたメッセージの数を返します。

  [詳細はこちら](https://valkey.io/commands/xack/)
+ `XADD`

  ストリームに新しいメッセージを追加します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/xadd/)
+ `XAUTOCLAIM`

  メッセージがコンシューマーグループメンバーに配信されたかのように、コンシューマーグループ内のメッセージの所有権を変更または取得します。

  [詳細はこちら](https://valkey.io/commands/xautoclaim/)
+ `XCLAIM`

  メッセージがコンシューマーグループメンバーに配信されたかのように、コンシューマーグループ内のメッセージの所有権を変更または取得します。

  [詳細はこちら](https://valkey.io/commands/xclaim/)
+ `XDEL`

  ストリームからメッセージを削除し、メッセージ数を返します。

  [詳細はこちら](https://valkey.io/commands/xdel/)
+ `XGROUP CREATE`

  コンシューマーグループを作成します。

  [詳細はこちら](https://valkey.io/commands/xgroup-create/)
+ `XGROUP CREATECONSUMER`

  コンシューマーグループにコンシューマーを作成します。

  [詳細はこちら](https://valkey.io/commands/xgroup-createconsumer/)
+ `XGROUP DELCONSUMER`

  コンシューマーグループからコンシューマーを削除します。

  [詳細はこちら](https://valkey.io/commands/xgroup-delconsumer/)
+ `XGROUP DESTROY`

  コンシューマーグループを破棄します。

  [詳細はこちら](https://valkey.io/commands/xgroup-destroy/)
+ `XGROUP SETID`

  コンシューマーグループの最後に配信された ID を設定します。

  [詳細はこちら](https://valkey.io/commands/xgroup-setid/)
+ `XINFO CONSUMERS`

  コンシューマーグループ内のコンシューマーのリストを返します。

  [詳細はこちら](https://valkey.io/commands/xinfo-consumers/)
+ `XINFO GROUPS`

  ストリームのコンシューマーグループのリストを返します。

  [詳細はこちら](https://valkey.io/commands/xinfo-groups/)
+ `XINFO STREAM`

  ディスクに関する情報を返します。

  [詳細はこちら](https://valkey.io/commands/xinfo-stream/)
+ `XLEN`

  ストリーム内のメッセージ数を返します。

  [詳細はこちら](https://valkey.io/commands/xlen/)
+ `XPENDING`

  ストリームコンシューマーグループの保留中のエントリリストから情報とエントリを返します。

  [詳細はこちら](https://valkey.io/commands/xpending/)
+ `XRANGE`

  ID の範囲内のストリームからのメッセージを返します。

  [詳細はこちら](https://valkey.io/commands/xrange/)
+ `XREAD`

  複数のストリームから、リクエストされた ID よりも大きい ID のメッセージを返します。メッセージが使用可能になるまでブロックします。

  [詳細はこちら](https://valkey.io/commands/xread/)
+ `XREADGROUP`

  グループ内のコンシューマのストリームから新規または過去のメッセージを返します。メッセージが使用可能になるまでブロックします。

  [詳細はこちら](https://valkey.io/commands/xreadgroup/)
+ `XREVRANGE`

  ID の範囲内のストリームからのメッセージを逆の順序で返します。

  [詳細はこちら](https://valkey.io/commands/xrevrange/)
+ `XTRIM`

  ストリームの先頭からメッセージを削除します。

  [詳細はこちら](https://valkey.io/commands/xtrim/)

**文字列コマンド**
+ `APPEND`

  キーの値に文字列を追加します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/append/)
+ `DECR`

  キーの整数値を 1 ずつ減らします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/decr/)
+ `DECRBY`

  キーの整数値から数値を減らします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/decrby/)
+ `GET`

  キーの文字列値を返します。

  [詳細はこちら](https://valkey.io/commands/get/)
+ `GETDEL`

  キーを削除した後にキーの文字列値を返します。

  [詳細はこちら](https://valkey.io/commands/getdel/)
+ `GETEX`

  キーの有効期限を設定した後にキーの文字列値を返します。

  [詳細はこちら](https://valkey.io/commands/getex/)
+ `GETRANGE`

  キーに格納されている文字列の部分文字列を返します。

  [詳細はこちら](https://valkey.io/commands/getrange/)
+ `GETSET`

  キーを新しい値に設定した後に、そのキーの以前の文字列値を返します。

  [詳細はこちら](https://valkey.io/commands/getset/)
+ `INCR`

  キーの整数値を 1 ずつ増やします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/incr/)
+ `INCRBY`

  キーの整数値を数値分増やします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/incrby/)
+ `INCRBYFLOAT`

  ハッシュ内のキーの浮動小数点値を数値分増やします。フィールドが存在しない場合、0 を初期値として使用します。

  [詳細はこちら](https://valkey.io/commands/incrbyfloat/)
+ `LCS`

  最も長い共通部分文字列を検索します。

  [詳細はこちら](https://valkey.io/commands/lcs/)
+ `MGET`

  1 つまたは複数のキーの文字列値をアトミックに返します。

  [詳細はこちら](https://valkey.io/commands/mget/)
+ `MSET`

  1 つまたは複数のキーの文字列値をアトミックに作成または変更します。

  [詳細はこちら](https://valkey.io/commands/mset/)
+ `MSETNX`

  1 つまたは複数のキーについて、どのキーも存在しない場合にのみ、その文字列値をアトミックに変更します。

  [詳細はこちら](https://valkey.io/commands/msetnx/)
+ `PSETEX`

  キーの文字列値とミリ秒単位の有効期限の両方を設定します。キーが存在しない場合はキーが作成されます。

  [詳細はこちら](https://valkey.io/commands/psetex/)
+ `SET`

  タイプを無視して、キーの文字列値を設定します。キーが存在しない場合はキーが作成されます。

  [詳細はこちら](https://valkey.io/commands/set/)
+ `SETEX`

  キーの文字列値と有効期限を設定します。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/setex/)
+ `SETNX`

  キーが存在しない場合にのみ、キーの文字列値を設定します。

  [詳細はこちら](https://valkey.io/commands/setnx/)
+ `SETRANGE`

  文字列値の一部をオフセットにより別の文字列で上書きします。キーが存在しない場合は、キーを作成します。

  [詳細はこちら](https://valkey.io/commands/setrange/)
+ `STRLEN`

  文字列値の長さをを返します。

  [詳細はこちら](https://valkey.io/commands/strlen/)
+ `SUBSTR`

  文字列値から部分文字列を返します。

  [詳細はこちら](https://valkey.io/commands/substr/)

**トランザクションコマンド**
+ `DISCARD`

  トランザクションを破棄します。

  [詳細はこちら](https://valkey.io/commands/discard/)
+ `EXEC`

  トランザクション内のすべてのコマンドを実行します。

  [詳細はこちら](https://valkey.io/commands/exec/)
+ `MULTI`

  トランザクションをスタートします。

  [詳細はこちら](https://valkey.io/commands/multi/)

## 制限付き Valkey および Redis OSS コマンド
<a name="RestrictedCommandsRedis"></a>

マネージドサービス操作性を実現するため、ElastiCache では高度な特権を必要とする特定のキャッシュエンジン固有のコマンドへのアクセスが制限されます。Redis OSS を実行するキャッシュの場合、以下のコマンドは使用できせん。
+ `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`

また、以下のコマンドはサーバーレスキャッシュでは使用できません。
+ `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`

## サポートされている Memcached のコマンド
<a name="SupportedCommandsMem"></a>

ElastiCache Serverless for Memcached は、オープンソースの memcached 1.6 に含まれる memcached [コマンド](https://github.com/memcached/memcached/wiki/Commands)のうち、以下を除くすべてのコマンドをサポートしています 
+ クライアント接続には TLS が必要なため、UDP プロトコルはサポートされていません。
+ バイナリプロトコルは memcached 1.6 で正式に[廃止](https://github.com/memcached/memcached/wiki/ReleaseNotes160)されたため、サポートされていません。
+ 大量のキーを取得することによるサーバーへの DoS 攻撃の可能性を回避するため、`GET/GETS` コマンドは 16KB に制限されています。
+ 遅延した `flush_all` コマンドは `CLIENT_ERROR` で拒否されます。
+ エンジンを設定したり、エンジンの状態やログに関する内部情報を公開したりする次のようなコマンドはサポートされていません。
  + `STATS` コマンドでは、`stats` と `stats reset` がサポートされます。他のバリエーションは `ERROR` を返します。
  + `lru / lru_crawler` - LRU および LRU クローラー設定の変更
  + `watch` - memcached のサーバーログをモニタリングします
  + `verbosity` - サーバーログレベルを設定します
  + `me` - メタデバッグ (me) コマンドはサポートされていません

# Valkey と Redis OSS の設定と制限
<a name="RedisConfiguration"></a>

Valkey エンジンおよび Redis OSS エンジンには多数の設定パラメータがあり、その中には ElastiCache for Redis OSS で変更可能なものもあれば、安定したパフォーマンスと信頼性を提供するために変更できないものもあります。

## サーバーレスキャッシュ
<a name="RedisConfiguration.Serverless"></a>

サーバーレスキャッシュでは、パラメータグループは使用されず、変更できる Valkey または Redis OSS 設定はありません。次の Valkey または Redis OSS パラメータが設定されています。


****  

|  名前  |  Details  |  説明  | 
| --- | --- | --- | 
| acl-pubsub-default | `allchannels` | キャッシュ上の ACL ユーザーの、デフォルトの Pubsub チャネルのアクセス許可。 | 
| client-output-buffer-limit | `normal 0 0 0` `pubsub 32mb 8mb 60` | 通常のクライアントにはバッファ制限はありません。PUB/SUB クライアントが 32 MiB のバックログに違反したり、8MiB のバックログに 60 秒間違反したりすると、接続が切断されます。 | 
| client-query-buffer-limit | 1 GiB | 単一のクライアントクエリバッファのサイズ上限。さらに、クライアントは 3,999 個を超える引数でリクエストを発行することはできません。 | 
| cluster-allow-pubsubshard-when-down | yes | これにより、キャッシュが部分的にダウンしていても、キャッシュは Pubsub トラフィックを処理できます。 | 
| cluster-allow-reads-when-down | yes | これにより、キャッシュが部分的にダウンしていても、キャッシュは read トラフィックを処理できます。 | 
| cluster-enabled | yes | サーバーレスキャッシュはすべてクラスターモードが有効になっているため、データを複数のバックエンドシャードに透過的にパーティション化できます。すべてのスロットは、単一の仮想ノードが所有するものとしてクライアントに表示されます。 | 
| cluster-require-full-coverage | no | キースペースが部分的にダウンした場合 (つまり、少なくとも 1 つのハッシュスロットにアクセスできなくなった場合)、キャッシュはキースペースのうちまだカバーされている部分のクエリを受け付け続けます。キースペース全体は常に cluster slots 内の 1 つの仮想ノードによって「カバー」されます。 | 
| lua-time-limit | 5000 | ElastiCache がスクリプトを停止するアクションを実行までの Lua スクリプトの最大実行時間 (ミリ秒単位)。`lua-time-limit` を超過した場合、すべての Valkey または Redis OSS コマンドは *\$1\$1\$1\$1-BUSY* の形式のエラーを返す可能性があります。この状態により、多くの必須の Valkey または Redis OSS オペレーションとの干渉が発生する可能性があるため、ElastiCache はまず *SCRIPT KILL* コマンドを発行します。これに失敗すると、ElastiCache は強制的に Valkey または Redis OSS を再起動します。 | 
| maxclients | 65000 | キャッシュに一度に接続できるクライアントの最大数。それ以上接続を確立すると、成功することもあれば、失敗することもあります。 | 
| maxmemory-policy | volatile-lru | TTL が設定されているアイテムは、キャッシュのメモリ制限に達すると、least-recently-used (LRU) の推定に従って削除されます。 | 
| notify-keyspace-events | (空の文字列) | キースペースイベントは現在、サーバーレスキャッシュではサポートされていません。 | 
| port | プライマリポート: 6379 読み取りポート: 6380 | サーバーレスキャッシュは、同じホスト名の 2 つのポートをアドバタイズします。プライマリポートは書き込みと読み取りを許可し、読み取りポートは READONLY コマンドを使用して低レイテンシーで最終的に一貫性のある読み取りを可能にします。 | 
| proto-max-bulk-len | 512 MiB | 1 つの要素リクエストのサイズ上限。 | 
| timeout | 0 | クライアントは特定のアイドル時に強制的に切断されることはありませんが、負荷分散のために定常状態では切断される場合があります。 | 

さらに、次の制限があります。


****  

|  名前  |  Details  |  説明  | 
| --- | --- | --- | 
| キャッシュあたりのサイズ | 5,000 GiB | サーバーレスキャッシュごとに保存できるデータの最大量。 | 
| スロットあたりのサイズ | 32 GiB | 単一の Valkey または Redis OSS ハッシュスロットのサイズ上限。クライアントが 1 つの Valkey または Redis OSS スロットにこれよりも多くのデータを設定しようとすると、そのスロットのエビクションポリシーがトリガーされ、削除可能なキーがない場合はメモリ不足 (OOM) エラーが表示されます。 | 
| キャッシュあたりの ECPU | 15,000,000 ECPU/秒 | ElastiCache 処理ユニット (ECPU) メトリクス。リクエストによって消費される ECPU の数は、要した vCPU 時間と転送されるデータの量によって異なります。 | 
| スロットあたりの ECPU | 30,000～90,000 ECPU/秒 | READONLY 接続を使用してレプリカからの読み取りを使用する場合、スロットあたり最大 30,000 ECPU/秒または 90,000 ECPU/秒。 | 
| リクエストあたりの引数 | 3,999 | リクエストあたりの引数の最大数。リクエストごとにこれ以上の引数を送信するクライアントはエラーを受け取ります。 | 
| キー名の長さ | 4 KiB | 単一の Valkey または Redis OSS キーまたはチャネル名のサイズ上限。クライアントがこれよりも大きいキーを参照すると、エラーが発生します。 | 
| Lua スクリプトのサイズ | 4 MiB | 単一の Valkey または Redis OSS Lua スクリプトのサイズ上限。これよりも大きい Lua スクリプトを読み込もうとすると、エラーが発生します。 | 

## ノードベースのクラスター
<a name="RedisConfiguration.SelfDesigned"></a>

ノードベースのクラスターの場合、設定パラメータのデフォルト値と設定可能な値については、「[Valkey および Redis OSS パラメータ](ParameterGroups.Engine.md#ParameterGroups.Redis)」を参照してください。オーバーライドが必要な特定のユースケースがない限り、通常はデフォルト値を推奨します。

# Valkey、Memcached、および Redis OSS の IPv6 クライアント例
<a name="network-type-best-practices"></a>

ElastiCache は、Valkey、Memcached、および Redis OSS と互換性があります。つまり、IPv6 接続をサポートするクライアントは、IPv6 対応の ElastiCache for Memcached クラスターに接続できます。IPv6 対応リソースを操作する際には、注意すべき点がいくつかあります。

AWS Database Blog のブログ記事「[Best practices for Valkey and Redis clients](https://aws.amazon.com/blogs/database/best-practices-redis-clients-and-amazon-elasticache-for-redis/)」を参照してください。この記事では、ElastiCache リソース用に Valkey および Redis OSS クライアントを設定するための推奨事項が紹介されています。

以下は、一般的に使用されているオープンソースのクライアントライブラリで IPv6 対応の ElastiCache リソースを操作するためのベストプラクティスです。

## Valkey および Redis OSS での検証済みクライアント
<a name="network-type-validated-clients-redis"></a>

ElastiCache は Valkey およびオープンソースの Redis OSS と互換性があります。つまり、IPv6 接続をサポートする Valkey およびオープンソースの Redis OSS クライアントは、IPv6 対応の ElastiCache for Redis OSS クラスターに接続できます。さらに、最も一般的な Python および Java クライアントのいくつかは、サポートされているすべてのネットワークタイプ設定 (IPv4 のみ、IPv6 のみ、およびデュアルスタック) で動作するように特別にテストおよび検証されています。

以下のクライアントは、Valkey および Redis OSS のすべてのサポートされているネットワークタイプ設定で動作することが具体的に検証されています。

検証済みクライアント:
+ [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/) – [バージョン: 6.1.6.リリース](https://github.com/lettuce-io/lettuce-core/tree/6.1.6.RELEASE)
+ [Jedis](https://github.com/redis/jedis) – [バージョン: 3.6.0](https://github.com/redis/jedis/tree/jedis-3.6.0)

# クライアントのベストプラクティス (Valkey および Redis OSS)
<a name="BestPractices.Clients.redis"></a>

一般的なシナリオのベストプラクティスを説明し、最も一般的なオープンソースの Valkey および Redis OSS クライアントライブラリ (redis-py、PHPRedis、Lettuce) のコード例、よく使用されるオープンソースの Memcached クライアントライブラリで ElastiCache リソースを操作するためのベストプラクティスについて説明します。

**Topics**
+ [多数の接続 (Valkey および Redis OSS)](BestPractices.Clients.Redis.Connections.md)
+ [クラスターのクライアント検出とエクスポネンシャルバックオフ (Valkey および Redis OSS)](BestPractices.Clients.Redis.Discovery.md)
+ [クライアント側のタイムアウトを設定する (Valkey および Redis OSS)](BestPractices.Clients.Redis.ClientTimeout.md)
+ [サーバー側のアイドルタイムアウトの設定 (Valkey および Redis OSS)](BestPractices.Clients.Redis.ServerTimeout.md)
+ [Lua スクリプト](BestPractices.Clients.Redis.LuaScripts.md)
+ [大きな複合アイテムの保存 (Valkey および Redis OSS)](BestPractices.Clients.Redis.LargeItems.md)
+ [Lettuce クライアント設定 (Valkey および Redis OSS)](BestPractices.Clients-lettuce.md)
+ [デュアルスタッククラスターの優先プロトコルの設定 (Valkey および Redis OSS)](#network-type-configuring-dual-stack-redis)

# 多数の接続 (Valkey および Redis OSS)
<a name="BestPractices.Clients.Redis.Connections"></a>

サーバーレスキャッシュと個々の ElastiCache for Redis OSS ノードは、最大 65,000 の同時クライアント接続をサポートしています。ただし、パフォーマンスを最適化するために、クライアントアプリケーションが常にはそのレベルの接続で動作しないことをお勧めします。Valkey および Redis OSS にはそれぞれ、クライアントからの受信リクエストが順番に処理されるイベントループに基づくシングルスレッドのプロセスがあります。つまり、接続しているクライアントの数が増えると、特定のクライアントの応答時間が長くなります。

Valkey または Redis OSS サーバーで接続のボトルネックを回避するために、以下の対策を実行します。
+ リードレプリカからの読み取り操作を実行する。これは、クラスターモードを無効にした状態で ElastiCache リーダーエンドポイントを使用するか、サーバーレスキャッシュを含め、クラスターモードを有効にした状態で読み取り用のレプリカを使用することで実行できます。
+ 書き込みトラフィックを複数のプライマリノードに分散する。これには 2 つの方法があります。マルチシャード Valkey または Redis OSS クラスターは、クラスターモード対応のクライアントで使用できます。また、クライアント側のシャーディングで無効になっているクラスターモードで、複数のプライマリノードに書き込むこともできます。これはサーバーレスキャッシュで自動的に行われます。
+ クライアントライブラリで利用可能な場合は、接続プールを使用する。

一般に、TCP 接続の作成は、一般的な Valkey または Redis OSS コマンドに比べて計算コストが高いオペレーションです。例えば、既存の接続を再利用すると、SET/GET リクエストの処理が桁違いに速くなります。有限サイズのクライアント接続プールを使用すると、接続管理のオーバーヘッドが軽減されます。また、クライアントアプリケーションからの同時着信接続数も制限されます。

次の PHPRedis のコード例は、新しいユーザーのリクエストごとに新しい接続が作成されることを示しています。

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

このコードは、Graviton2 (m6g.2xlarge) ElastiCache for Redis OSS ノードに接続された Amazon Elastic Compute Cloud (Amazon EC2) インスタンス上のループでベンチマークされています。クライアントとサーバーは同じアベイラビリティーゾーンに配置されています。オペレーション全体の平均レイテンシーは 2.82 ミリ秒でした。

コードを更新して永続的な接続と接続プールを使用した場合、オペレーション全体の平均レイテンシーは 0.21 ミリ秒でした。

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

必要な redis.ini の設定:
+ `redis.pconnect.pooling_enabled=1`
+ `redis.pconnect.connection_limit=10`

以下のコードは [Redis-py 接続プール](https://redis.readthedocs.io/en/stable/)の例です。

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

以下のコードは [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);
}
```

# クラスターのクライアント検出とエクスポネンシャルバックオフ (Valkey および Redis OSS)
<a name="BestPractices.Clients.Redis.Discovery"></a>

クラスターモードを有効にして ElastiCache Valkey または Redis OSS クラスターに接続する場合、該当するクライアントライブラリがクラスター対応であることが必要です。クライアントは、適切なノードにリクエストを送信し、クラスターのリダイレクト処理によるパフォーマンスのオーバーヘッドを回避できるように、ハッシュスロットとクラスター内のノードを対応付けたマップを取得する必要があります。そのため、クライアントは以下の 2 つの異なる状況下で、スロットとマッピング先のノードを網羅したリストを検出する必要があります。
+ クライアントが初期化され、初期スロット構成を読み込む必要がある。
+ MOVED リダイレクトをサーバーから受信した。例えば、フェイルオーバー時に元のプライマリノードのスロットをすべてレプリカに引き継ぐ場合や、リシャーディング時にスロットがソースプライマリノードからターゲットプライマリノードに移動される場合が該当します。

クライアント検出は通常、Valkey または Redis OSS サーバーに CLUSTER SLOT コマンドまたは CLUSTER NODE コマンドを発行することで行われます。CLUSTER SLOT メソッドを推奨します。その理由は、一連のスロット範囲と、関連するプライマリノードとレプリカノードをクライアントに返すからです。その場合、クライアント側で別途解析を行う必要がなく、効率が向上します。

クラスタートポロジーによっては、CLUSTER SLOT コマンドの応答のサイズがクラスターのサイズに応じて変わる場合があります。ノード数が多い大きなクラスターは、応答も大きくなります。したがって、クラスタートポロジー検出を行うクライアントの数が、際限なく増えないようにすることが重要です。例えば、クライアントアプリケーションの起動時やサーバーとの接続の切断時にクラスター検出を実行しなければならない場合に、クライアントアプリケーションで再接続や検出のリクエストを複数回行い、再試行時のエクスポネンシャルバックオフが実装されていないという間違いがよく見受けられます。そのせいで CPU 使用率が 100% になり、そのまま Valkey または Redis OSS サーバーが長時間応答しなくなる可能性があります。各 CLUSTER SLOT コマンドでクラスターバス内の多数のノードを処理しなければならない場合は、こうした停止状態が長引きます。このような動作が原因でクライアントが停止する事態は、これまでも、Python (redis-py-cluster) や Java (Lettuce と Redisson) などのさまざまな言語でいくつも確認されています。

サーバーレスキャッシュでは、アドバタイズされるクラスタートポロジが静的であり、書き込みエンドポイントと読み取りエンドポイントの 2 つのエントリで構成されるため、こうした問題の多くは自動的に軽減されます。また、キャッシュエンドポイントを使用する場合、クラスター検出が自動的に複数のノードに分散されます。ただし、以下の推奨事項は引き続き有効です。

接続リクエストや検出リクエストが殺到した場合の影響を軽減するために、以下の対応を推奨します。
+ クライアントアプリケーションからの同時着信接続数を制限するために、有限サイズのクライアント接続プールを実装する。
+ タイムアウトによりクライアントがサーバーから切断された場合は、エクスポネンシャルバックオフとジッター(揺らぎ) を加えて再試行する。これにより、複数のクライアントが同時にサーバーに負荷をかける事態を阻止できます。
+ 「[ElastiCache での接続エンドポイントの検索](Endpoints.md)」のガイドを参考にして、クラスターエンドポイントを検索し、クラスター検出を実行する。これにより、クラスター内のハードコーディングされたいくつかのシードノードにアクセスする代わりに、検出の負荷をクラスター内のすべてのノード (最大 90 個) 間で分散できます。

redis-py、PHPRedis、Lettuce におけるエクスポネンシャルバックオフの再試行ロジックのコード例を以下に紹介します。

**バックオフロジックのサンプル 1: redis-py**

redis-py には、障害の発生直後に 1 回再試行する再試行メカニズムが組み込まれています。このメカニズムは、[Redis OSS](https://redis.readthedocs.io/en/stable/examples/connection_examples.html#redis.Redis) オブジェクトの作成時に渡される `retry_on_timeout` 引数で有効にすることができます。ここでは、エクスポネンシャルバックオフとジッターを加えたカスタムの再試行メカニズムを紹介します。[redis-py (\$11494)](https://github.com/andymccurdy/redis-py/pull/1494) で、エクスポネンシャルバックオフをネイティブに実装するプルリクエストを送信しました。今後は、手動で実装する必要がなくなる可能性があります。

```
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
```

その後、以下のコードを使用して値を設定できます。

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

ワークロードに応じて、例えば、レイテンシーの影響を受けやすいワークロードについては、バックオフの基準値を 1 秒から数十ミリ秒または数百ミリ秒に変更することができます。

**バックオフロジックのサンプル 2: PHPRedis**

PHPRedis には、最大 10 回 (回数設定は不可) 再試行する再試行メカニズムが組み込まれています。試行間隔の遅延を設定できます (2 回目以降にジッターを加えます)。詳細については、[こちらのサンプルコード](https://github.com/phpredis/phpredis/blob/b0b9dd78ef7c15af936144c1b17df1a9273d72ab/library.c#L335-L368)を参照してください。[PHPRedis (\$11986)](https://github.com/phpredis/phpredis/pull/1986) で、エクスポネンシャルバックオフをネイティブに実装するプルリクエストを送信しました。このリクエストはその後統合され、[文書化](https://github.com/phpredis/phpredis/blob/develop/README.md#retry-and-backoff)されています。PHPRedis の最新リリースを使用している場合は、手動で実装する必要はありませんが、以前のバージョンを使用している場合の参考資料として、ここで紹介しておきます。差し当たり、再試行メカニズムの遅延を設定するコード例を以下に紹介します。

```
$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);
```

**バックオフロジックのサンプル 3: Lettuce**

Lettuce には、[エクスポネンシャルバックオフとジッター](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)の投稿で説明したエクスポネンシャルバックオフ戦略に基づく再試行メカニズムが組み込まれています。以下は、フルジッターのアプローチを示すコードの抜粋です。

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

	}
}
```

# クライアント側のタイムアウトを設定する (Valkey および Redis OSS)
<a name="BestPractices.Clients.Redis.ClientTimeout"></a>

**クライアント側のタイムアウトを設定する**

サーバーがリクエストを処理してレスポンスを生成するのに十分な時間を確保できるように、クライアント側のタイムアウトを適切に設定します。また、これにより、サーバーへの接続を確立できない場合でも、フェイルファストが可能です。Valkey または Redis OSS コマンドの中には、他のコマンドよりも計算コストが高いものがあります。例えば、アトミックに実行する必要のある複数のコマンドを含む Lua スクリプトや MULTI/EXEC トランザクションなどです。一般的には、以下を含むサーバーからレスポンスを受け取る前にクライアントがタイムアウトするのを避けるため、クライアント側のタイムアウト時間を長くすることが推奨されます。
+ 複数のキーにまたがるコマンドの実行
+ 複数の個別の Valkey または Redis OSS コマンドで構成される MULTI/EXEC トランザクションまたは Lua スクリプトの実行
+ 大きな値の読み取り
+ BLPOP などのブロッキング操作の実行

BLPOP のようなブロッキング操作の場合、ベストプラクティスとして、コマンドのタイムアウトをソケットのタイムアウトよりも小さい数値に設定します。

redis-py、PHPRedis、および Lettuce でクライアント側のタイムアウトを実装するコード例を以下に示します。

**タイムアウトの設定例 1: redis-py**

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)
```

**タイムアウトの設定例 2: PHPRedis**

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
```

**タイムアウトの設定例 3: Lettuce**

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

# サーバー側のアイドルタイムアウトの設定 (Valkey および Redis OSS)
<a name="BestPractices.Clients.Redis.ServerTimeout"></a>

お客様のアプリケーションにアイドル状態のクライアントが多数接続されていて、コマンドを活発に送信しているわけではないケースが散見されています。このような場合、多数のアイドル状態のクライアントで 65,000 の接続数を使い果たしてしまう可能性があります。こうした状況を回避するには、[Valkey および Redis OSS パラメータ](ParameterGroups.Engine.md#ParameterGroups.Redis) を使用してサーバーのタイムアウトを適切に設定してください。そうすれば、サーバーがアイドル状態のクライアントの接続を積極的に切断するため、接続数の上昇を防ぐことができます。この設定は、サーバーレスキャッシュでは使用できません。

# Lua スクリプト
<a name="BestPractices.Clients.Redis.LuaScripts"></a>

Valkey および Redis OSS は 200 超のコマンドをサポートしており、その中には、Lua スクリプトを実行するコマンドもあります。ただし、Lua スクリプトに関しては、Valkey または Redis OSS のメモリと可用性に影響しかねない注意点がいくつかあります。

**パラメータ化されていない Lua スクリプト**

各 Lua スクリプトは、実行前に Valkey または Redis OSS サーバーにキャッシュされます。パラメータ化されていない Lua スクリプトはそれぞれ異なるため、Valkey または Redis OSS サーバーで大量の Lua スクリプトが保存され、メモリ消費量が増える可能性があります。これを軽減するには、すべての Lua スクリプトを確実にパラメータ化し、SCRIPT FLUSH を定期的に実行して、キャッシュされている Lua スクリプトを適宜クリーンアップします。

キーを提供する必要があることにも注意してください。KEY パラメータの値が指定されていない場合、スクリプトは失敗します。例えば、次の場合は機能しません。

```
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.
```

次の場合は機能します。

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

次のコード例では、パラメータ化したスクリプトの使い方を紹介します。まず、パラメータ化しない場合の例を紹介します。この場合、3 つの異なる Lua スクリプトがキャッシュされるため、推奨されません。

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

代わりに、以下のパターンを使用して、渡されたパラメータを受け入れることができる単一のスクリプトを作成してください。

```
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
```

**実行時間の長い Lua スクリプト**

Lua スクリプトは複数のコマンドをアトミックに実行できるため、通常の Valkey または Redis OSS コマンドよりも所要時間が長くなる場合があります。Lua スクリプトが読み取り専用のオペレーションのみを実行する場合は、途中で停止できます。ただし、Lua スクリプトが書き込みオペレーションを実行した時点で強制終了できなくなり、最後まで実行しなければなりません。変更処理を行う Lua スクリプトの実行時間が長引くと、Valkey または Redis OSS サーバーが長時間応答しなくなる可能性があります。この問題を軽減するには、実行時間の長い Lua スクリプトを避け、実稼働前の環境でスクリプトをテストしてください。

**ステルス書き込みを行う Lua スクリプト**

Valkey または Redis OSS が `maxmemory` を上回っても、Lua スクリプトが引き続き Valkey または Redis OSS に新しいデータを書き込むケースがいくつかあります。
+ Valkey または Redis OSS サーバーが `maxmemory` を下回っている場合にスクリプトが開始し、そのスクリプト内に複数の書き込みオペレーションが含まれている。
+ スクリプトの最初の書き込みコマンドはメモリを消費しないが (DEL など)、後続の複数の書き込みオペレーションがメモリを消費する。
+ Valkey または Redis OSS サーバーで `noeviction` 以外の適切なエビクションポリシーを設定することで、この問題を軽減できます。これにより、Redis OSS は Lua スクリプトの合間にアイテムを削除し、メモリを解放できます。

# 大きな複合アイテムの保存 (Valkey および Redis OSS)
<a name="BestPractices.Clients.Redis.LargeItems"></a>

状況によっては、アプリケーションが大きな複合アイテム (マルチ GB のハッシュデータセットなど) を Valkey または Redis OSS に保存することがあります。これは、Valkey または Redis OSS でパフォーマンスの問題が生じやすくなるため、原則としては推奨されません。例えば、クライアントは HGETALL コマンドを実行して、マルチ GB のハッシュコレクション全体を取得できます。この場合、クライアントの出力バッファに大きなアイテムがバッファリングされ、Valkey または Redis OSS サーバーに多大なメモリ負荷がかかる可能性があります。また、クラスターモードでのスロット移行では、ElastiCache はシリアル化されたサイズが 256 MB を超えるアイテムを含むスロットを移行しません。

大きいアイテムの問題を解決するために、以下の点を推奨します。
+ 大きな複合アイテムは複数の小さなアイテムに分割する。例えば、大きなハッシュコレクションを、そのコレクションを適切に反映したキー名スキームを使用して (アイテムのコレクションを識別する共通のプレフィックスをキー名に付けるなど)、個々のキーと値のフィールドに分割します。同じコレクション内の複数のフィールドにアトミックにアクセスする必要がある場合は、MGET コマンドを使用して、同一コマンドで複数のキーと値のペアを取得できます。
+ どの方法を検討しても大きなコレクションデータセットを分割できない場合は、コレクション全体ではなく、コレクション内のデータのサブセットを操作するコマンドを使用してみる。マルチ GB のコレクション全体を同一コマンドでアトミックに取得しなければならないようなユースケースは避けてください。ハッシュコレクションに対して HGETALL の代わりに HGET コマンドや HMGET コマンドを使用することが、その一例です。

# Lettuce クライアント設定 (Valkey および Redis OSS)
<a name="BestPractices.Clients-lettuce"></a>

このセクションでは、推奨される Java と Lettuce の設定オプションと、それらを ElastiCache クラスターに適用する方法について説明します。

このセクションの推奨事項は、Lettuce バージョン 6.2.2 でテスト済みです。

**Topics**
+ [例: TLS が有効な場合のクラスターモードの Lettuce の設定](BestPractices.Clients-lettuce-cme.md)
+ [例: TLS が有効でクラスターモードが無効な場合の Lettuce の設定](BestPractices.Clients-lettuce-cmd.md)

**Java DNS キャッシュ TTL**

Java 仮想マシン (JVM) は DNS 名参照をキャッシュします。JVM がホスト名を IP アドレスに変換するとき、*time-to-live* (TTL) と呼ばれる指定期間 IP アドレスをキャッシュします。

TTL 値の選択は、レイテンシーおよび変化に対する応答性と間のトレードオフです。TTL を短くすると、DNS リゾルバーはクラスターの DNS の更新をより早く認識します。これにより、クラスターで実行される置換やその他のワークフローにアプリケーションがより迅速に応答できるようになります。ただし、TTL が低すぎると、クエリの量が増え、それによってアプリケーションのレイテンシーが増加する可能性があります。絶対的に正しい TTL 値は存在しませんが、TTL 値を設定するときは、変更が有効になるまで待つことができる時間の長さについて検討する必要があります。

ElastiCache ノードは、変更される可能性がある DNS 名を使用するため、5～10 秒の低い TTL 値で JVM を設定することをお勧めします。これにより、ノードの IP アドレスが変更されたときに、アプリケーションは DNS エントリに対して再度クエリを実行することで、リソースの新しい IP アドレスを取得し、使用できるようになります。

一部の Java 設定では JVM のデフォルトの TTL が設定されるため、JVM が再起動されるまで、DNS エントリが更新されることはありません。

JVM TTL を設定する方法の詳細については、「[JVM TTL を設定する方法](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-jvm-ttl.html#how-to-set-the-jvm-ttl)」を参照してください。

**Lettuce のバージョン**

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

**エンドポイント**。

クラスターモードが有効なクラスターを使用している場合は、`redisUri` をクラスター設定エンドポイントに設定します。この URI の DNS ルックアップは、クラスターで使用可能なすべてのノードのリストを返し、クラスターの初期化中にそれらのノードの 1 つにランダムに解決されます。トポロジ更新の仕組みの詳細については、このトピックで後述する「*DynamicRefreshResources*」を参照してください。

**SocketOption**

[KeepAlive](https://lettuce.io/core/release/api/io/lettuce/core/SocketOptions.KeepAliveOptions.html) を有効にします。このオプションを有効にすると、コマンドのランタイムに失敗した接続を処理する必要が減ります。

[接続タイムアウトは](https://lettuce.io/core/release/api/io/lettuce/core/SocketOptions.Builder.html#connectTimeout-java.time.Duration-)、アプリケーションの要件とワークロードに基づいて設定してください。詳細については、このトピックで後述する「タイムアウト」のセクションを参照してください。

**ClusterClientOption:クラスターモードが有効なクライアントオプション**

接続が失われたときは [AutoReconnect](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterClientOptions.Builder.html#autoReconnect-boolean-) を有効にします。

[CommandTimeout](https://lettuce.io/core/release/api/io/lettuPrce/core/RedisURI.html#getTimeout--) を設定します。詳細については、このトピックで後述する「タイムアウト」のセクションを参照してください。

[NodeFilter](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterClientOptions.Builder.html#nodeFilter-java.util.function.Predicate-) を設定すると、障害が発生したノードをトポロジから除外できます。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);
```

**注記**  
ノードフィルタリングは、DynamicRefreshSources を true に設定して使用するのが最適です。そうしないと、1 つの問題のあるシードノードからトポロジビューを取得すると、一部のシャードのプライマリノードに障害が発生していると見なされ、このプライマリノードは除外され、スロットがカバーされなくなります。(DynamicRefreshSources が true の場合に) 複数のシードノードが存在すると、この問題が発生する可能性が低くなります。これは、新しく昇格したプライマリとのフェイルオーバー後に、少なくとも一部のシードノードでトポロジビューを更新する必要があるためです。

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

**注記**  
クラスターモードが無効なクラスターは、クラスター検出コマンドをサポートしていないため、すべてのクライアントの動的トポロジー検出機能と互換性があるわけではありません。  
ElastiCache で無効になっているクラスターモードは Lettuce の `MasterSlaveTopologyRefresh` と互換性がありません。代わりに、クラスタモードが無効になっている場合は、`StaticMasterReplicaTopologyProvider` を設定し、クラスターの読み取りと書き込みのエンドポイントを提供します。  
クラスターモードが無効なクラスターとの接続の詳細については、「[Valkey または Redis OSS (クラスターモードが無効) クラスターのエンドポイントを検索する (コンソール)](Endpoints.md#Endpoints.Find.Redis)」を参照してください。  
Lettuce の動的トポロジー検出機能を使いたい場合は、既存のクラスターと同じシャード構成でクラスターモードが有効なクラスターを作成できます。ただし、クラスターモードが有効なクラスターでは、高速フェールオーバーをサポートするために、少なくとも 3 つのシャードと 1 つのレプリカを構成することをお勧めします。

[enablePeriodicRefresh](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#enablePeriodicRefresh-java.time.Duration-) を有効にします。これにより、クラスタートポロジを定期的に更新できるため、クライアントは refreshPeriod の間隔 (デフォルト:60 秒) でクラスタートポロジを更新できます。無効にすると、クライアントはクラスターに対してコマンドの実行を試みたときにエラーが発生した場合にのみ、クラスタートポロジを更新します。

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

[enableAllAdaptiveRefreshTriggers](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#enableAllAdaptiveRefreshTriggers--) を有効にします。これにより、MOVED\$1REDIRECT、ASK\$1REDIRECT、PERSISTENT\$1RECONNECTS、UNCOVERED\$1SLOT、UNKNOWN\$1NODE のすべての[トリガー](https://lettuce.io/core/6.1.6.RELEASE/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.RefreshTrigger.html)を使用する適応型トポロジ更新が可能になります。適応型更新トリガーは、Valkey または Redis OSS クラスター操作中に発生したイベントに基づいてトポロジビューの更新を開始します。このオプションを有効にすると、前述のトリガーのいずれかが発生すると、トポロジがすぐに更新されます。適応型更新トリガーは、イベントが大規模で発生する可能性があるため (更新間のデフォルトタイムアウトは 30)、タイムアウトを使用してレート制限されます。

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

[dynamicRefreshResources](https://lettuce.io/core/release/api/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.Builder.html#dynamicRefreshSources-boolean-) を有効にします。小規模なクラスターでは DynamicRefreshResources を有効にし、大規模なクラスターでは無効にすることをお勧めします。DynamicRefreshResources を使用すると、提供されたシードノード (クラスター構成エンドポイントなど) からクラスターノードを検出できます。検出されたすべてのノードを、クラスタートポロジを更新するためのソースとして使用します。

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

ただし、有効にすると、クラスタービューから受信したすべてのクラスターノードを使用して、現在のビューについてクエリを実行します。障害が発生したノードをそのビューから除外するので、トポロジ更新は成功します。ただし、dynamicRefreshSources が true の場合、Lettuce はすべてのノードにクエリを実行してクラスタービューを取得し、結果を比較します。そのため、多数のノードを持つクラスターではコストがかかる可能性があります。多数のノードがあるクラスターでは、この機能をオフにすることをお勧めします。

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

**ClientResources**

[DnsResolver](https://lettuce.io/core/release/api/io/lettuce/core/resource/DefaultClientResources.Builder.html#dnsResolver-io.lettuce.core.resource.DnsResolver-) を [DirContextDnsResolver](https://lettuce.io/core/release/api/io/lettuce/core/resource/DirContextDnsResolver.html) で設定します。DNS リゾルバーは Java の com.sun.jndi.dns.DnsContextFactory をベースにしています。

[reconnectDelay](https://lettuce.io/core/release/api/io/lettuce/core/resource/DefaultClientResources.Builder.html#reconnectDelay-io.lettuce.core.resource.Delay-) をエクスポネンシャルバックオフとフルジッターで設定します。Lettuce には、エクスポネンシャルバックオフ戦略に基づく再試行メカニズムが組み込まれています。詳細については、AWS アーキテクチャブログの「[エクスポネンシャルバックオフとジッター](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter)」を参照してください。再試行バックオフ戦略の重要性に関する詳細については、AWS データベースブログの[ベストプラクティスブログ投稿](https://aws.amazon.com/blogs/database/best-practices-redis-clients-and-amazon-elasticache-for-redis/)のバックオフロジックのセクションを参照してください。

```
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、FLUSHALL、KEYS、SMEMBERS、Lua スクリプトなど、複数のキーを反復処理するコマンドにはタイムアウトを長く設定します。SET、GET、HSET など、1 つのキーコマンドではタイムアウトを短くします。

**注記**  
次の例で設定されているタイムアウトは、最大 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();
```

# 例: TLS が有効な場合のクラスターモードの Lettuce の設定
<a name="BestPractices.Clients-lettuce-cme"></a>

**注記**  
次の例のタイムアウトは、最大 20 バイトの長さのキーと値で SET/GET コマンドを実行したテスト用です。コマンドが複雑な場合や、キーと値が大きい場合は、処理時間が長くなる可能性があります。タイムアウトは、アプリケーションのユースケースに基づいて設定する必要があります。

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

# 例: TLS が有効でクラスターモードが無効な場合の Lettuce の設定
<a name="BestPractices.Clients-lettuce-cmd"></a>

**注記**  
次の例のタイムアウトは、最大 20 バイトの長さのキーと値で SET/GET コマンドを実行したテスト用です。コマンドが複雑な場合や、キーと値が大きい場合は、処理時間が長くなる可能性があります。タイムアウトは、アプリケーションのユースケースに基づいて設定する必要があります。

```
// 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);
```

## デュアルスタッククラスターの優先プロトコルの設定 (Valkey および Redis OSS)
<a name="network-type-configuring-dual-stack-redis"></a>

クラスターモードが有効な Valkey または Redis クラスターでは、IP 検出パラメータを使用して、クライアントがクラスター内のノードに接続するために使用するプロトコルを制御できます。IP 検出パラメータは、IPv4 または IPv6 に設定できます。

Valkey または Redis クラスターの場合、IP 検出パラメータは、[クラスタースロット ()](https://valkey.io/commands/cluster-slots/)、[クラスターシャード ()](https://valkey.io/commands/cluster-shards/)、[クラスターノード ()](https://valkey.io/commands/cluster-nodes/) の出力で使用される IP プロトコルを設定します。これらのコマンドは、クライアントがクラスタートポロジを検出するために使用されます。クライアントは、これらのコマンドの IP を使用して、クラスター内の他のノードに接続します。

IP 検出を変更しても、接続しているクライアントのダウンタイムは発生しません。ただし、変更が反映されるまで時間がかかる場合があります。Valkey または Redis クラスターに変更が完全に伝播されたかどうかを判断するには、`cluster slots` の出力をモニタリングします。cluster slots コマンドによって返されたすべてのノードが新しいプロトコルの IP を報告すると、変更の反映が完了します。

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)
```

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;
}));
```

# クライアントのベストプラクティス (Memcached)
<a name="BestPractices.Clients.memcached"></a>

ElastiCache for Memcached クラスターを使用した一般的なシナリオのベストプラクティスについて説明します。

**Topics**
+ [効率的な負荷分散のための ElastiCache クライアントの設定 (Memcached)](BestPractices.LoadBalancing.md)
+ [Memcached での検証済みクライアント](network-type-validated-clients-memcached.md)
+ [デュアルスタッククラスターの優先プロトコルの設定 (Memcached)](network-type-configuring-dual-stack-memcached.md)

# 効率的な負荷分散のための ElastiCache クライアントの設定 (Memcached)
<a name="BestPractices.LoadBalancing"></a>

**注記**  
このセクションは、ノードベースのマルチノードの Memcached クラスターに適用されます。

複数の ElastiCache Memcached ノードを効果的に使用するには、ノード間でキャッシュキーを分散できる必要があります。*n* ノードを持つクラスターの負荷を分散する簡単な方法は、オブジェクトのキーのハッシュを計算し、その結果を *n*: `hash(key) mod n` で除算して剰余を求めることです。結果の値（0～*n*–1）が、オブジェクトを配置するノードの数になります。

この手法は単純で、ノードの数（*n*）が一定である限り有効です。ただし、クラスターからノードを追加または削除する場合、移動する必要があるキーの数は *(n - 1) / n* (*n* は新しいノード数) です。したがって、この手法では多数のキーが移動され、特にノード数が大きくなると、初期のキャッシュミスが多数発生します。1 ノードから 2 ノードへのスケーリングでは、キーの (2-1)/2 (50 パーセント) が移動されます。9 ノードから 10 ノードへのスケーリングでは、キーの (10–1)/10 (90 パーセント) が移動されます。トラフィックのスパイクの理由からスケールアップする場合、多数のキャッシュミスが発生することは避けたいものです。多数のキャッシュミスは、トラフィックのスパイクにより既に過負荷になっているデータベースのヒットとなります。

このジレンマには、整合性のあるハッシュがソリューションとなります。整合性のあるハッシュではアルゴリズムを使用し、ノードがクラスターから追加または削除されるたびに、移動する必要のあるキーの数は約 *1/n* となります (*n* は新しいノード数)。1 ノードから 2 ノードへのスケーリングでは、キーの 1/2 (50 パーセント) が移動され、最悪のケースとなります。9 ノードから 10 ノードへのスケーリングでは、キーの 1/10 (10 パーセント) が移動されます。

ユーザーとして、複数ノードのクラスターに使用されるハッシュアルゴリズムを制御します。整合性のあるハッシュを使用するようにクライアントを設定することをお勧めします。さいわい、整合性のあるハッシュを実装する Memcached クライアントライブラリは数多くあり、ほとんどの一般的な言語で提供されています。使用中のライブラリのドキュメントを参照し、整合性のあるハッシュをサポートするかどうかと、その実装方法について確認してください。

Java、PHP、または .NET を使用している場合は、いずれかの Amazon ElastiCache クライアントライブラリを使用することをお勧めします。

## Java を使用した整合性のあるハッシュ
<a name="BestPractices.LoadBalancing.Java"></a>

ElastiCache Memcached Java クライアントは、整合性のあるハッシュ機能が組み込まれたオープンソースの spymemcached Java クライアントに基づいています。このライブラリには、整合性のあるハッシュを実装する KetamaConnectionFactory クラスが含まれています。デフォルトでは、整合性のあるハッシュは spymemcached では無効になっています。

詳細については、[KetamaConnectionFactory](https://github.com/RTBHOUSE/spymemcached/blob/master/src/main/java/net/spy/memcached/KetamaConnectionFactory.java) で KetamaConnectionFactory ドキュメントを参照してください。

## Memcached で PHP を使用したコンシステントハッシュ
<a name="BestPractices.LoadBalancing.PHP"></a>

ElastiCache Memcached PHP クライアントは、組み込みの Memcached PHP ライブラリのラッパーです。デフォルトでは、整合性のあるハッシュは Memcached PHP ライブラリによって無効になっています。

整合性のあるハッシュを有効にするには、以下のコードを使用します。

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

また、先ほどのコードに加えて、php.ini ファイルで `memcached.sess_consistent_hash` を有効にすることをお勧めします。

 詳細については、Memcached PHP の実行時設定に関するドキュメント ([http://php.net/manual/en/memcached.configuration.php](http://php.net/manual/en/memcached.configuration.php)) を参照してください。特に、`memcached.sess_consistent_hash` パラメータについて参照してください。

## Memcached で .NET を使用したコンシステントハッシュ
<a name="BestPractices.LoadBalancing.dotNET"></a>

ElastiCache Memcached .NET クライアントは、Enyim Memcached のラッパーです。デフォルトでは、Enyim Memcached クライアントによって、整合性のあるハッシュが有効になります。

 詳細については、`memcached/locator` のドキュメント ([https://github.com/enyim/EnyimMemcached/wiki/MemcachedClient-Configuration\$1user-content-memcachedlocator](https://github.com/enyim/EnyimMemcached/wiki/MemcachedClient-Configuration#user-content-memcachedlocator)) を参照してください。

# Memcached での検証済みクライアント
<a name="network-type-validated-clients-memcached"></a>

以下のクライアントは、Memcached のすべてのサポートされているネットワークタイプ設定で動作することが具体的に検証されています。

検証済みクライアント:
+ [AWS ElastiCache Cluster Client Memcached for Php](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-php) – [バージョン \$13.6.2](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-php/tree/v3.2.0)
+ [AWS ElastiCache Cluster Client Memcached for Java](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-java) – Github の最新マスター

# デュアルスタッククラスターの優先プロトコルの設定 (Memcached)
<a name="network-type-configuring-dual-stack-memcached"></a>

Memcached クラスターでは、IP 検出パラメータを使用して、クライアントがクラスター内のノードに接続するために使用するプロトコルを制御できます。IP 検出パラメータは、IPv4 または IPv6 に設定できます。

IP 検出パラメータは、config get クラスター出力で使用される IP プロトコルを制御します。これにより、ElastiCache for Memcached クラスターの自動検出をサポートするクライアントで使用される IP プロトコルが決まります。

IP 検出を変更しても、接続しているクライアントのダウンタイムは発生しません。ただし、変更が反映されるまで時間がかかる場合があります。

Java の場合は `getAvailableNodeEndPoints` の出力をモニタリングし、PHP の場合は `getServerList` の出力をモニタリングします。これらの関数の出力で、更新されたプロトコルを使用するクラスター内のすべてのノードの IP が報告されると、変更の反映が完了します。

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;
        }));
```

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

IP 検出が更新される前に作成された既存のクライアント接続は、引き続き古いプロトコルを使用して接続されます。クラスター検出コマンドの出力で変更が検出されると、検証されたすべてのクライアントは新しい IP プロトコルを使用してクラスターに自動的に再接続します。ただし、これはクライアントの実装によって異なります。

## TLS が有効なデュアルスタック ElastiCache クラスター
<a name="network-type-configuring-tls-enabled-dual-stack"></a>

ElastiCache クラスターで TLS が有効になっている場合、クラスター検出関数 (Redis の場合は `cluster slots`、`cluster shards`、`cluster nodes`) または Memcached の場合は `config get cluster` は、IP ではなくホスト名を返します。次に、IP の代わりにホスト名を使用して ElastiCache クラスターに接続し、TLS ハンドシェイクを実行します。つまり、クライアントは IP 検出パラメータの影響を受けません。TLS が有効なクラスターでは、IP 検出パラメータは優先 IP プロトコルに影響しません。代わりに、使用する IP プロトコルは、DNS ホスト名を解決する際にクライアントがどの IP プロトコルを使用するかによって決まります。

**Java クライアント**

IPv4 と IPv6 の両方をサポートする Java 環境から接続する場合、後方互換性のために Java はデフォルトで IPv6 よりも IPv4 を優先します。ただし、IP プロトコルプリファレンスは JVM 引数を使用して設定できます。IPv4 を優先するには、JVM は `-Djava.net.preferIPv4Stack=true` を受け入れ、IPv6 セット `-Djava.net.preferIPv6Stack=true` を優先します。`-Djava.net.preferIPv4Stack=true` を設定すると、JVM は IPv6 接続を行わなくなります。**Valkey または Redis OSS の場合、これには他の非 Valkey アプリケーションや非 Redis OSS アプリケーションへの接続も含まれます。**

**ホストレベルの設定**

一般に、クライアントまたはクライアントランタイムに IP プロトコルプリファレンスを設定するための構成オプションが提供されていない場合、DNS 解決を実行するとき、IP プロトコルはホストの設定に依存します。デフォルトでは、ほとんどのホストは IPv4 よりも IPv6 を優先しますが、この優先度はホストレベルで設定できます。これは、ElastiCache クラスターへのリクエストだけでなく、そのホストからのすべての DNS リクエストに影響します。

**Linux ホスト**

Linux では、`gai.conf` ファイルを変更して IP プロトコルプリファレンスを設定できます。`gai.conf` ファイルは `/etc/gai.conf` の下にあります。`gai.conf` の指定がない場合は、`/usr/share/doc/glibc-common-x.xx/gai.conf` に `/etc/gai.conf` にコピーできるサンプルを用意し、デフォルトの設定をコメント解除する必要があります。ElastiCache クラスターに接続するときに IPv4 を優先するように設定を更新するには、クラスター IP を含む CIDR 範囲の優先順位をデフォルトの IPv6 接続の優先順位よりも高く更新します。デフォルトでは、IPv6 接続の優先順位は 40 です。例えば、クラスターが CIDR 172.31.0.0:0/16 のサブネットにあると仮定すると、以下の設定では、クライアントはそのクラスターへの IPv4 接続を優先することになります。

```
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
```

`gai.conf` の詳細については、[Linux のメインページ](https://man7.org/linux/man-pages/man5/gai.conf.5.html)を参照してください。

**Windows ホスト**

Windows ホストのプロセスも同様です。Windows ホストの場合は `netsh interface ipv6 set prefix CIDR_CONTAINING_CLUSTER_IPS PRECEDENCE LABEL` を実行できます。これは Linux ホストで `gai.conf` ファイルを変更するのと同じ効果があります。

これにより、指定された CIDR 範囲の IPv6 接続よりも IPv4 接続を優先するように優先設定ポリシーが更新されます。例えば、クラスターが 172.31.0.0:0/16 CIDR のサブネット内にあると仮定した場合、`netsh interface ipv6 set prefix ::ffff:172.31.0.0:0/112 100 15` を実行すると、次の優先順位表になり、クライアントがクラスターに接続する際に IPv4 を優先することになります。

```
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
```

# Valkey および Redis OSS の予約済みメモリを管理する
<a name="redis-memory-management"></a>

予約メモリは、nondata 用に確保されるメモリです。バックアップまたはフェイルオーバーを実行すると、Valkey および Redis OSS は、クラスターのデータが .rdb ファイルに書き込まれている間、クラスターへの書き込みオペレーションを記録するために使用可能なメモリを使用します。すべての書き込みに十分なメモリが使用可能できない場合、プロセスは失敗します。以下では、ElastiCache for Redis OSS の予約メモリを管理するためのオプションと、それらのオプションを適用する方法について説明します。

**Topics**
+ [予約メモリはどれくらい必要ですか。](#redis-memory-management-need)
+ [予約メモリを管理するパラメータ](#redis-memory-management-parameters)
+ [予約メモリ管理パラメータの指定](#redis-reserved-memory-management-change)

## 予約メモリはどれくらい必要ですか。
<a name="redis-memory-management-need"></a>

2.8.22 より前の Redis OSS バージョンを実行している場合、Redis OSS 2.8.22 以降を実行する場合より多くのメモリをバックアップとフェイルオーバーのために確保します。この要件は、ElastiCache for Redis OSS がバックアッププロセスを実装する方法の違いによるものです。目安として、2.8.22 より前のバージョンの Redis OSS オーバーヘッドではノードタイプの `maxmemory` 値の半分を、Redis OSS バージョン 2.8.22 以降では 4 分の 1 を確保します。

ElastiCache がバックアップとレプリケーションプロセスを実装する方法が異なるため、目安は `reserved-memory-percent` パラメータを使用してノードタイプの `maxmemory` 値の 25% を予約することです。これはデフォルト値であり、ほとんどのケースで推奨されます。

バースト可能なマイクロインスタンスタイプと小さいインスタンスタイプが `maxmemory` 制限近くで動作している場合、スワップの使用が発生する可能性があります。バックアップ、レプリケーション、高トラフィック時にこれらのインスタンスタイプの運用上の信頼性を向上させるには、`reserved-memory-percent` パラメータの値を小さいインスタンスタイプでは最大 30%、マイクロインスタンスタイプでは最大 50% に増やすことをお勧めします。

データ階層化を使用する ElastiCache クラスターの書き込み負荷の高いワークロードでは、`reserved-memory-percent` をノードの使用可能なメモリの最大 50%まで増やすことをお勧めします。

詳細については次を参照してください:
+ [Valkey または Redis OSS スナップショットを作成するのに十分なメモリがあることを確認する](BestPractices.BGSAVE.md)
+ [同期とバックアップの実装方法](Replication.Redis.Versions.md)
+ [ElastiCache のデータ階層化](data-tiering.md)

## 予約メモリを管理するパラメータ
<a name="redis-memory-management-parameters"></a>

2017 年 3 月 16 日以降、Amazon ElastiCache には `reserved-memory` と `reserved-memory-percent` という、Valkey または Redis OSS メモリを管理するための 2 つの相互に排他的なパラメータがあります。これらのパラメータのいずれも Valkey または Redis OSS ディストリビューションには含まれていません。

ElastiCache ユーザーになった時期に応じて、これらのパラメータのいずれか一方がデフォルトのメモリ管理パラメータになります。このパラメータは、新しい Valkey または Redis OSS クラスターまたはレプリケーショングループを作成し、デフォルトのパラメータグループを使用する場合に適用されます。
+ 2017 年 3 月 16 日より前に開始したユーザーの場合 — デフォルトのパラメータグループを使用して Redis OSS クラスターまたはレプリケーショングループを作成する場合、メモリ管理パラメータは `reserved-memory` になります。この場合、0 バイトのメモリが予約されます。
+ 2017 年 3 月 16 日以降に開始したユーザーの場合 — デフォルトのパラメータグループを使用して Valkey または Redis OSS クラスターまたはレプリケーショングループを作成する場合、メモリ管理パラメータは `reserved-memory-percent` になります。この場合、ノードの `maxmemory` 値の 25% がデータ以外の目的で予約されます。

2 つの Valkey または Redis OSS メモリ管理パラメータの説明を確認した後で、デフォルトではないもの、またはデフォルト以外の値を使用するものを選択することができます。その場合は、他の予約メモリ管理パラメータに変更できます。

そのパラメータの値を変更するには、カスタムパラメータグループを作成し、希望のメモリ管理パラメータと値を使用するように変更します。そうすると、新しい Valkey または Redis OSS クラスターまたはレプリケーショングループを作成するたびに、そのカスタムパラメータグループを使用できるようになります。既存のクラスターまたはレプリケーショングループの場合は、カスタムパラメータグループを使用するように変更できます。

 詳細については次を参照してください: 
+ [予約メモリ管理パラメータの指定](#redis-reserved-memory-management-change)
+ [ElastiCache パラメータグループを作成する](ParameterGroups.Creating.md)
+ [ElastiCache パラメータグループを変更する](ParameterGroups.Modifying.md)
+ [ElastiCache クラスターの変更](Clusters.Modify.md)
+ [レプリケーショングループの変更](Replication.Modify.md)

### 予約メモリのパラメータ
<a name="redis-memory-management-parameters-reserved-memory"></a>

2017 年 3 月 16 日までは、ElastiCache for Redis OSS の予約済みメモリの管理はすべて、パラメータ `reserved-memory` を使用して行われていました。`reserved-memory` のデフォルト値は 0 です。このデフォルトは Valkey または Redis OSS のオーバーヘッド用にメモリを確保せず、Valkey または Redis OSS はノードのメモリすべてをデータ用に消費できます。

バックアップ用およびフェイルオーバー用に使用できる十分なメモリを持てるように `reserved-memory` を変更するには、カスタムパラメータグループを作成する必要があります。このカスタムパラメータグループで、`reserved-memory` を、クラスターおよびクラスターのノードタイプで実行している Valkey または Redis OSS のバージョンに適切な値に設定します。詳細については、[予約メモリはどれくらい必要ですか。](#redis-memory-management-need)を参照してください。

パラメータ `reserved-memory` は ElastiCache に固有であり、Redis OSS のディストリビューションには含まれていません。

次の手順では、`reserved-memory` を使用して Valkey または Redis OSS クラスターのメモリを管理する方法を示します。

**予約メモリを使用してメモリを予約するには**

1. 実行中のエンジンバージョンに一致するパラメータグループファミリーを指定するカスタムパラメータグループを作成します。たとえば、`redis2.8` パラメータグループファミリーを指定します。詳細については、「[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. Valkey または Redis OSS のオーバーヘッドのために予約するメモリのバイト数を計算します。ノードタイプに対する `maxmemory` 値を [Redis OSS のノードタイプに固有のパラメータ](ParameterGroups.Engine.md#ParameterGroups.Redis.NodeSpecific) で確認できます。

1. パラメータ `reserved-memory` が前の手順で計算したバイト数であるように、カスタムパラメータグループを変更します。次の AWS CLI の例では、2.8.22 より前の Redis OSS のバージョンを実行しており、ノードの `maxmemory` の半分を予約する必要があることを前提としています。詳細については、「[ElastiCache パラメータグループを変更する](ParameterGroups.Modifying.md)」を参照してください。

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

   各ノードタイプには異なる `maxmemory` 値があるため、使用する各ノードタイプに対して個別のカスタムパラメータグループが必要です。したがって、各ノードタイプには `reserved-memory` に対して異なる値が必要です。

1. カスタムパラメータグループを使用するように Redis OSS クラスターまたはレプリケーショングループを変更します。

   次の CLI の例では、カスタムパラメータグループ ` my-redis-cluster` をすぐに使用するようにクラスター `redis28-m3xl` を変更しています。詳細については、「[ElastiCache クラスターの変更](Clusters.Modify.md)」を参照してください。

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

   次の CLI の例では、カスタムパラメータグループ `my-redis-repl-grp` をすぐに使用するようにレプリケーショングループ `redis28-m3xl` を変更しています。詳細については、「[レプリケーショングループの変更](Replication.Modify.md)」。

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

### 予約メモリパーセントパラメータ
<a name="redis-memory-management-parameters-reserved-memory-percent"></a>

2017 年 3 月 16 日に、Amazon ElastiCache では、パラメータ `reserved-memory-percent` が導入され、ElastiCache for Redis OSS のすべてのバージョンで利用できるようになりました。`reserved-memory-percent` の目的は、すべてのクラスターに対して予約メモリ管理を簡易化することです。ノードタイプにかかわらずクラスターの予約メモリを管理するために、各パラメータグループファミリー (`redis2.8` など) に対して単一のパラメータグループを持てるようにすることによって実行します。`reserved-memory-percent` のデフォルト値は 25 (25 パーセント) です。

パラメータ `reserved-memory-percent` は ElastiCache に固有であり、Redis OSS のディストリビューションには含まれていません。

r6gd ファミリーのノードを使用しているクラスターでメモリ使用量が 75% に達すると、データ階層化が自動的にトリガーされます。詳細については、「[ElastiCache のデータ階層化](data-tiering.md)」を参照してください。

**reserved-memory-percent を使用してメモリを予約するには**  
`reserved-memory-percent` を使用して、ElastiCache for Redis OSS クラスターでメモリを管理するには、以下のいずれかを実行します。
+ Redis OSS 2.8.22 以降を実行している場合は、クラスターに、デフォルトのパラメータグループを割り当てます。デフォルトの 25 パーセントで十分です。そうでない場合、次のステップを実行して、値を変更します。
+ 2.8.22 より前の Redis OSS のバージョンを実行している場合、`reserved-memory-percent` のデフォルトの 25 パーセントよりも多くのメモリを確保する必要があると考えられます。そのためには、次の手順を使用します。

**reserved-memory-percent の値を変更するには**

1. 実行中のエンジンバージョンに一致するパラメータグループファミリーを指定するカスタムパラメータグループを作成します。たとえば、`redis2.8` パラメータグループファミリーを指定します。カスタムパラメータグループは、デフォルトのパラメータグループを変更できないため必要です。詳細については、「[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
   ```

   `reserved-memory-percent` は、ノードの `maxmemory` に対する割合としてメモリを予約するため、各ノードタイプに対応するカスタムパラメータグループは必要ありません。

1. `reserved-memory-percent` が 50 (50 パーセント) であるようにカスタムパラメータグループを変更します。詳細については、「[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. 2.8.22 より前の Redis OSS のバージョンを実行している Redis OSS クラスターまたはレプリケーショングループに対して、このカスタムパラメータグループを使用します。

   次の CLI の例では、カスタムパラメータグループ `redis28-50` をすぐに使用するように Redis OSS クラスター `my-redis-cluster` を変更します。詳細については、「[ElastiCache クラスターの変更](Clusters.Modify.md)」を参照してください。

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

   次の CLI の例では、カスタムパラメータグループ `redis28-50` をすぐに使用するように Redis OSS レプリケーショングループ `my-redis-repl-grp` を変更します。詳細については、「[レプリケーショングループの変更](Replication.Modify.md)」を参照してください。

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

## 予約メモリ管理パラメータの指定
<a name="redis-reserved-memory-management-change"></a>

2017 年 3 月 16 日時点で ElastiCache ユーザーだった場合、デフォルトの予約済みメモリ管理パラメータは `reserved-memory` であり、予約されるメモリはゼロ (0) バイトです。2017 年 3 月 16 日よりも後に ElastiCache ユーザーになった場合、デフォルトの予約済みメモリ管理パラメータは `reserved-memory-percent` であり、ノードのメモリの 25 パーセントが予約されます。これは、ElastiCache for Redis OSS クラスターまたはレプリケーショングループの作成時期に関係なく当てはまります。ただし、AWS CLI または ElastiCache API を使用して、必要に応じて予約メモリ管理パラメータを変更できます。

パラメータ `reserved-memory` および `reserved-memory-percent` は相互に排他的です。パラメータグループには、常にどちらかがありますが、両方があることはありません。パラメータグループを変更することによって、パラメータグループが予約メモリ管理のためにどちらのパラメータを使用するかを変更できます。デフォルトのパラメータグループは変更できないため、パラメータグループはカスタムパラメータグループである必要があります。詳細については、「[ElastiCache パラメータグループを作成する](ParameterGroups.Creating.md)」を参照してください。

**reserved-memory-percent を指定するには**  
予約メモリ管理パラメータとして `reserved-memory-percent` を使用するには、`modify-cache-parameter-group` コマンドを使用してカスタムパラメータグループを変更します。`parameter-name-values` パラメータを使用して、`reserved-memory-percent` とそれの値を指定します。

次の CLI の例では、`redis32-cluster-on` を使用して予約メモリを管理するように、カスタムパラメータグループ `reserved-memory-percent` を変更します。パラメータグループが予約メモリ管理に `ParameterName` パラメータを使用するには、`ParameterValue` に値を割り当てる必要があります。詳細については、「[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"
```

**reserved-memory を指定するには**  
予約メモリ管理パラメータとして `reserved-memory` を使用するには、`modify-cache-parameter-group` コマンドを使用してカスタムパラメータグループを変更します。`parameter-name-values` パラメータを使用して、`reserved-memory` とそれの値を指定します。

次の CLI の例では、`redis32-m3xl` を使用して予約メモリを管理するように、カスタムパラメータグループ `reserved-memory` を変更します。パラメータグループが予約メモリ管理に `ParameterName` パラメータを使用するには、`ParameterValue` に値を割り当てる必要があります。エンジンバージョンは 2.8.22 より新しいため、値を `3565158400` の `cache.m3.xlarge` の 25% である `maxmemory` に設定します。詳細については、「[ElastiCache パラメータグループを変更する](ParameterGroups.Modifying.md)」を参照してください。

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

# Valkey および Redis OSS のノードベースのクラスターを使用する場合のベストプラクティス
<a name="BestPractices.SelfDesigned"></a>

マルチ AZ の使用、十分なメモリの確保、クラスターのサイズ変更、ダウンタイムの最小化はすべて、Valkey または Redis OSS でノードベースのクラスターを使用する際に留意すべき有用な概念です。以下のベストプラクティスを確認し、参考にすることをお勧めします。

**Topics**
+ [マルチ AZ によるダウンタイムの最小化](multi-az.md)
+ [Valkey または Redis OSS スナップショットを作成するのに十分なメモリがあることを確認する](BestPractices.BGSAVE.md)
+ [オンラインクラスターのサイズ変更](best-practices-online-resharding.md)
+ [メンテナンス中のダウンタイムを最小限に抑える](BestPractices.MinimizeDowntime.md)

# マルチ AZ によるダウンタイムの最小化
<a name="multi-az"></a>

ElastiCache Valkey または Redis OSS では、プライマリノードを置き換える必要がある状況がいくつかあります。これには、特定のタイプの計画的メンテナンスや、プライマリノードまたはアベイラビリティーゾーンで予期しない障害などが含まれます。

この置き換えにより、クラスターのダウンタイムが発生しますが、マルチ AZ が有効になっている場合、ダウンタイムは最小限に抑えられます。プライマリノードのロールは、いずれかのリードレプリカに自動的にフェイルオーバーされます。ElastiCache ではこれを透過的に処理するため、新しいプライマリノードを作成してプロビジョニングする必要はありません。このフェイルオーバーとレプリカの昇格により、昇格が完了したらすぐに新しいプライマリへの書き込みを再開できます。

マルチ AZ とダウンタイムの最小化の詳細については、「[Valkey および Redis OSS でマルチ AZ を使用して ElastiCache のダウンタイムを最小限に抑える](AutoFailover.md)」を参照してください。

# Valkey または Redis OSS スナップショットを作成するのに十分なメモリがあることを確認する
<a name="BestPractices.BGSAVE"></a>

**Valkey 7.2 以降、および Redis OSS バージョン 2.8.22 以降のスナップショットと同期**  
Valkey は、スナップショットと同期のデフォルトサポートを提供します。Redis OSS 2.8.22 で分岐なしの保存プロセスが導入されました。これにより、同期および保存中にスワップを使用することなく、アプリケーションにより多くのメモリを割り当てて使用することができます。詳細については、「[同期とバックアップの実装方法](Replication.Redis.Versions.md)」を参照してください。

**バージョン 2.8.22 より前の Redis OSS のスナップショットおよび同期**

ElastiCache for Redis OSS を使用する場合、Redis OSS は次のような多くのケースでバックグラウンドの書き込みコマンドを呼び出します。
+ バックアップのためのスナップショットを作成するとき。
+ レプリカとレプリケーショングループ内のプライマリを同期させるとき。
+ Redis OSS の AOF (Append-Only File) 機能を有効にするとき。
+ レプリカをプライマリに昇格するとき (プライマリ/レプリカの同期が実行される)。

Redis OSS がバックグラウンドの書き込みプロセスを実行するときは、常に、このプロセスのオーバーヘッドに対応するのに十分なメモリが利用できる必要があります。十分なメモリを利用できない場合、このプロセスは失敗します。このため、Redis OSS クラスターの作成時には、十分なメモリがあるノードインスタンスタイプを選択することが重要です。

## Valkey および Redis OSS でのバックグラウンド書き込みプロセスとメモリ使用量
<a name="BestPractices.BGSAVE.Process"></a>

バックグラウンド書き込みプロセスが呼び出されると、Valkey および Redis OSS は常にそのプロセスを生成 (フォーク) します (これらのエンジンはシングルスレッドであることを思い出してください)。1 つのフォークがデータをディスクの Redis OSS .rdb スナップショットファイルに永続化します。もう 1 つのフォークは、すべての読み取りと書き込みのオペレーションを処理します。スナップショットがポイントインタイムスナップショットであることを保証するために、すべてのデータの更新と追加が、データ領域とは別の使用可能なメモリ領域に書き込まれます。

データをディスクに保持しながら、すべての書き込みオペレーションを記録するのに十分なメモリが使用できる限り、メモリ不足の問題は発生しません。次のいずれかに該当する場合は、メモリ不足の問題が発生する可能性があります。
+ アプリケーションで頻繁に書き込みオペレーションが実行され、新しいデータや更新されたデータを受け入れるために使用可能なメモリが大量に必要になる。
+ 新しいデータや更新されたデータを書き込むために使用できるメモリが少なすぎる。
+ ディスクに永続化するのに長時間かかる大規模なデータセットがあり、大量の書き込みオペレーションが必要になる。

次の図は、バックグラウンド書き込みプロセス実行時のメモリの使用を示しています。

![\[イメージ: バックグラウンド書き込み中のメモリ使用の図。\]](http://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/dg/images/ElastiCache-bgsaveMemoryUseage.png)


バックアップを実行する際のパフォーマンスへの影響については、「[ノードベースのクラスターのバックアップがパフォーマンスに与える影響](backups.md#backups-performance)」を参照してください。

Valkey および Redis OSS がスナップショットを実行する方法の詳細については、[http://valkey.io](http://valkey.io) を参照してください。

リージョンとアベイラビリティーゾーンの詳細については、「[ElastiCache のリージョンとアベイラビリティーゾーンの選択](RegionsAndAZs.md)」を参照してください。

## バックグラウンド書き込み実行中のメモリ不足の回避
<a name="BestPractices.BGSAVE.memoryFix"></a>

`BGSAVE` または `BGREWRITEAOF` のようなバックグラウンド書き込みプロセスが呼び出されると、プロセスの失敗を防ぐためには、処理中の書き込みオペレーションが消費する量以上のメモリが必要となります。最悪のシナリオでは、バックグラウンド書き込みオペレーション中にすべてのレコードが更新され、新しいレコードがキャッシュに追加されます。そのため、Redis OSS バージョン 2.8.22 より前の場合は、`reserved-memory-percent` を 50 (50 パーセント) に設定し、Valkey および Redis OSS バージョン 2.8.22 以降の場合は 25 (25 パーセント) に設定することをお勧めします。

`maxmemory` 値は、データとオペレーションのオーバーヘッドで使用できるメモリを示します。デフォルトのパラメータグループの `reserved-memory` パラメータを変更することはできないため、クラスター用のカスタムパラメータグループを作成する必要があります。`reserved-memory` のデフォルト値は 0 です。この場合、Redis OSS はすべての *maxmemory* をデータ用に消費でき、バックグラウンド書き込みプロセスなどの他の用途に使用できるメモリがほとんど残されない可能性があります。ノードインスタンスタイプごとの `maxmemory` 値については、「[Redis OSS のノードタイプに固有のパラメータ](ParameterGroups.Engine.md#ParameterGroups.Redis.NodeSpecific)」を参照してください。

`reserved-memory` パラメータを使用して、ボックスで使用されるメモリ量を抑えることができます。

ElastiCache での Valkey および Redis 固有のパラメータの詳細については、「[Valkey および Redis OSS パラメータ](ParameterGroups.Engine.md#ParameterGroups.Redis)」を参照してください。

パラメータグループの作成と変更については、「[ElastiCache パラメータグループを作成する](ParameterGroups.Creating.md)」と「[ElastiCache パラメータグループを変更する](ParameterGroups.Modifying.md)」を参照してください。

# オンラインクラスターのサイズ変更
<a name="best-practices-online-resharding"></a>

*リシャーディング*には、クラスターへのシャードまたはノードの追加と削除、およびキースペースの再分散が含まれます。したがって、クラスターの負荷、メモリ使用率、データ全体のサイズなど、シャーディングオペレーションには複数のものが影響します。最適なエクスペリエンスを得るには、均一なワークロードパターンディストリビューションのクラスターベストプラクティス全体に従うことをお勧めします。さらに、次のステップを実行することをお勧めします。

リシャーディングを開始する前に、次のことをお勧めします:
+ **アプリケーションをテストする** – 可能であれば、ステージング環境でリシャーディング中にアプリケーションの動作をテストします。
+ **スケーリング問題の早期通知の取得** – リシャーディングは計算処理能力を集中的に使用するオペレーションです。このため、リシャーディング中は CPU 使用率をマルチコアインスタンスで 80% 未満、シングルコアインスタンスで 50% 未満にすることをお勧めします。ElastiCache for Redis OSS メトリックスをモニタリングして、アプリケーションでスケーリングの問題が発生する前にリシャーディングを開始します。追跡すると有用なメトリックスは、`CPUUtilization`、`NetworkBytesIn`、`NetworkBytesOut`、`CurrConnections`、`NewConnections`、`FreeableMemory`、`SwapUsage`、`BytesUsedForCacheItems` です。
+ **スケーリングする前に、空きメモリが十分に確保されていることを確認する** – スケーリングする場合、保持するシャードの空きメモリが、削除するシャードに使用されているメモリの 1.5 倍以上であることを確認します。
+ **オフピーク時にリシャーディングを開始する** – このプラクティスは、リシャーディングオペレーションがクライアントのレイテンシーとスループットに与える影響を軽減するのに役立ちます。また、スロット再分散に多くのリソースを使用できるため、リシャーディングをより迅速に完了できます。
+ **クライアントのタイムアウト動作を確認する** – オンラインクラスターのサイズ変更中に、一部のクライアントでレイテンシーが長くなる場合があります。より大きなタイムアウトでクライアントライブラリを設定すると、サーバーがより高い負荷条件でもシステムが接続する時間を与えることができます。場合によっては、サーバーへの接続を多数開く必要があります。この場合、エクスポネンシャルバックオフを追加してロジックを再接続することを検討してください。こうすると、サーバーに対して大量の新しい接続が同時に行われるのを防ぐことができます。
+ **すべてのシャードに関数を読み込む** – クラスターをスケールアウトすると、ElastiCache は (ランダムに選択された) 既存のノードのいずれかにロードされた関数を新しいノードに自動的にレプリケートします。クラスターに Valkey 7.2 以上または Redis OSS 7.0 以上があり、アプリケーションで[関数](https://valkey.io/topics/functions-intro/)を使用している場合は、スケールアウトする前に、クラスターがシャードにより異なる関数定義にならないように、すべての関数をすべてのシャードに読み込むことをお勧めします。

リシャーディング後は、以下の点に注意してください:
+ ターゲットのシャードで十分なメモリが利用できない場合、スケールインが部分的に成功している可能性があります。そのような結果が生じた場合、必要に応じて使用可能なメモリを確認し、オペレーションを再試行してください。ターゲットのシャードのデータは削除されません。
+ `FLUSHALL` および `FLUSHDB` コマンドは、リシャーディング操作中の Lua スクリプト内ではサポートされません。Redis OSS 6 より前では、移行中のスロットで動作する `BRPOPLPUSH` コマンドはサポートされていません。

# メンテナンス中のダウンタイムを最小限に抑える
<a name="BestPractices.MinimizeDowntime"></a>

クラスターモード設定を使用して、マネージド型またはアンマネージド型のオペレーション中に可用性を最大限に高めることができます。クラスター検出エンドポイントに接続するクラスターモードがサポートされるクライアントを使用することをお勧めします。クラスターモードを無効にした場合は、すべての書き込みオペレーションにプライマリエンドポイントを使用することをお勧めします。

読み取りアクティビティの場合、アプリケーションはクラスター内のいずれのノードにも接続できます。プライマリエンドポイントとは異なり、ノードエンドポイントは特定のエンドポイントに解決されます。レプリカの追加または削除など、クラスターに変更を加えた場合は、アプリケーションでノードエンドポイントを更新する必要があります。このため、クラスターモードを無効にする場合は、読み取りアクティビティにリーダーエンドポイントを使用することをお勧めします。

クラスターで自動フェイルオーバーが有効になっている場合、プライマリノードが変更される可能性があります。したがって、アプリケーションでノードのロールを確認し、すべての読み取りエンドポイントを更新する必要があります。これにより、プライマリに大きな負荷がかかっていないことを確認できます。自動フェイルオーバーを無効にしても、ノードのロールは変わりません。ただし、自動フェイルオーバーが有効になっているクラスターと比較して、マネージド型またはアンマネージド型のオペレーションのダウンタイムは長くなります。

 読み取りリクエストの転送先を単一のリードレプリカノードに限定しないでください。そのノードが使用できなくなると、読み取りが停止する可能性があります。メンテナンス中の読み取り中断を回避するには、プライマリからの読み取れるようにフォールバックするか、少なくとも 2 つのリードレプリカを用意してください。

# Memcached のキャッシュ戦略
<a name="Strategies"></a>

以下のトピックでは、Memcached キャッシュを設定および維持するための戦略について説明します。

キャッシュするデータとデータへのアクセスパターンに基づいて、キャッシュを入力し維持するために実装する戦略とは何か。たとえば、ゲームサイトやトレンドのニュースのランキングトップ 10 で同じ同じ戦略は使用したくないでしょう。このセクションの後半では、一般的なキャッシュのメンテナンス戦略、利点および欠点について説明します。

**Topics**
+ [リードレプリカ](#Strategies.ReadReplicas)
+ [遅延読み込み](#Strategies.LazyLoading)
+ [書き込みスルー](#Strategies.WriteThrough)
+ [TTL の追加](#Strategies.WithTTL)
+ [関連トピック](#Strategies.SeeAlso)

## リードレプリカ
<a name="Strategies.ReadReplicas"></a>

多くの場合、レプリカを作成し、プライマリキャッシュノードの代わりにそこから読み取ることで、ElastiCache サーバーレスキャッシュのパフォーマンスを大幅に向上させることができます。詳細については、「[リードレプリカの使用に関するベストプラクティス](ReadReplicas.md)」を参照してください。

## 遅延読み込み
<a name="Strategies.LazyLoading"></a>

その名前が示すようため、[*遅延読み込み*] は、必要なときにのみキャッシュにデータを読み込むキャッシュ戦略です。これは、以下で説明するように動作します。

Amazon ElastiCacheは、インメモリ key-value ストアで、アプリケーションとアプリケーションがアクセスするデータストア (データベース) 間にあります。アプリケーションがデータをリクエストする場合は、常に ElastiCache キャッシュに最初にリクエストを行います。データがキャッシュにあり最新である場合、ElastiCache はアプリケーションにデータを返します。データがキャッシュにない場合、または期限が切れている場合は、アプリケーションはデータストアからのデータをリクエストします。その後、データストアはアプリケーションにデータを返します。次に、アプリケーションは、ストアから受信したデータをキャッシュに書き込みます。このようにして、次回リクエストされたときに、より迅速に取得できます。

[*キャッシュヒット*] は、データがキャッシュにあり、期限切れでない場合に発生します。

1. アプリケーションは、キャッシュに対してデータをリクエストします。

1. キャッシュはアプリケーションにデータを返します。

[*キャッシュミス*] は、データがキャッシュにないか、期限切れの場合に発生します。

1. アプリケーションは、キャッシュに対してデータをリクエストします。

1. キャッシュにはリクエストされたデータがないため、`null` を返します。

1. アプリケーションはデータベースに対してデータをリクエストし、取得します。

1. アプリケーションは、新しいデータでキャッシュを更新します。

### 遅延読み込みの利点と欠点
<a name="Strategies.LazyLoading.Evaluation"></a>

遅延読み込みの利点は次のとおりです。
+ リクエストされたデータのみをキャッシュします。

  ほとんどのデータがリクエストされないため、遅延読み込みではデータでキャッシュがいっぱいになることを回避できます。
+ ノード障害は、アプリケーションにとって致命的ではありません。

  ノードで障害が発生して新しい空のノードに置き換えられた場合、アプリケーションはレイテンシーが長くなっても機能し続けます。新規ノードへのリクエストが行われると、それぞれのキャッシュミスにより、データベースのクエリが行われます。同時に、後続のリクエストがキャッシュからデータを取得できるように、データコピーがキャッシュに追加されます。

遅延読み込みの欠点は次のとおりです。
+ キャッシュミスのペナルティがあります。1 回のキャッシュのミスで 3 回のトリップ: 

  1. キャッシュに対する最初のデータリクエスト

  1. データベースへのデータクエリ

  1. キャッシュにデータを書き込む

   これらのミスにより、アプリケーションによるデータの取得に相当な遅延が発生する可能性があります。
+ 古いデータ。

  キャッシュミスがある場合にのみデータがキャッシュに書き込まれる場合は、キャッシュ内のデータが古くなる可能性があります。この結果は、データベースのデータが変更されたときに、キャッシュへの更新がないために発生します。この問題に対処するには、[書き込みスルー](#Strategies.WriteThrough) および [TTL の追加](#Strategies.WithTTL) 戦略を使用できます。

### 遅延読み込み擬似コードの例
<a name="Strategies.LazyLoading.CodeExample"></a>

次のコードは、遅延読み込みロジックの擬似コードの例です。

```
// *****************************************
// 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
```

この例では、データを取得するアプリケーションコードは次のとおりです。

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

## 書き込みスルー
<a name="Strategies.WriteThrough"></a>

書き込みスルー戦略では、データがデータベースに書き込まれると常にデータを追加するか、キャッシュのデータを更新します。

### 書き込みスルーの利点と欠点
<a name="Strategies.WriteThrough.Evaluation"></a>

書き込みスルーの利点は次のとおりです。
+ キャッシュのデータが古くなりません。

  キャッシュにデータベースにデータが書き込まれるたびにキャッシュのデータが更新されるため、キャッシュのデータが常に最新の状態になります。
+ 書き込みペナルティ対読み取りペナルティ。

  1 回の書き込みで 2 回のトリップ: 

  1. キャッシュへの書き込み

  1. データベースへの書き込み

   レイテンシーをプロセスに追加します。つまり、エンドユーザーは一般的に、データの取得時よりもデータの更新時のレイテンシーに対して寛容です。更新は作業量が大きく時間がかかるのが常です。

書き込みスルーの欠点は次のとおりです。
+ 欠落データ。

  ノード障害またはスケールアウトにより、新規ノードをスピンアップすると、データが欠落しています。このデータは、データベースで追加または更新されるまで失われ続けます。これを最小限に抑えるには、[[遅延読み込み](#Strategies.LazyLoading)] を書き込みスルーで指定します。
+ キャッシュの変動。

  ほとんどのデータは読み込まれないため、これはリソース浪費です。[[有効期限 (TTL) の値を追加する](#Strategies.WithTTL)] を使用すると、無駄なスペースを最小限に抑えることができます。

### 書き込みスルー擬似コードの例
<a name="Strategies.WriteThrough.CodeExample"></a>

以下は、書き込みスルーロジックの擬似コードの例です。

```
// *****************************************
// 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
```

この例では、データを取得するアプリケーションコードは次のとおりです。

```
save_customer(12345,{"address":"123 Main"})
```

## TTL の追加
<a name="Strategies.WithTTL"></a>

遅延読み取りはデータが古くなる可能性がありますが、空ノードによる障害は発生しません。書き込みスルーでは常に新しいデータとなりますが、空ノードの障害が発生して、過剰なデータがキャッシュに入力される可能性があります。それぞれの書き込みに有効期限 (TTL) の値を追加することで、それぞれの戦略のメリットが得られます。同時に、過剰なデータでキャッシュがいっぱいになる事態が避けられます。

*[有効期限 (TTL)]* は、キーの有効期限までの秒数を指定する整数値です。Valkey または Redis OSS では、この値の秒またはミリ秒を指定できます。Memcached は、この値を秒単位で指定します。アプリケーションが期限切れのキーを読み込もうとすると、キーが見つからないものとして処理されます。データベースにキーについてクエリされ、キャッシュが更新されます。このアプローチは、値が古くなっていないことを保証するものではありません。ただし、これはデータが古くなりすぎることを防ぎ、キャッシュの値がデータベースから時々更新されることを必要とします。

詳細については、「[Valkey and Redis OSS commands](https://valkey.io/commands)」または「[Memcached `set` commands](https://www.tutorialspoint.com/memcached/memcached_set_data.htm)」を参照してください。

### TTL 擬似コードの例
<a name="Strategies.WithTTL.CodeExample"></a>

以下は、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
```

以下は、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
```

この例では、データを取得するアプリケーションコードは次のとおりです。

```
save_customer(12345,{"address":"123 Main"})
```

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

## 関連トピック
<a name="Strategies.SeeAlso"></a>
+ [インメモリデータストア](elasticache-use-cases.md#elasticache-use-cases-data-store)
+ [エンジンとバージョンの選択](SelectEngine.md)
+ [ElastiCache のスケーリング](Scaling.md)