クラスターのサイジング
DAX クラスターの合計キャパシティと可用性は、ノードのタイプと数によって異なります。クラスター内のノードが増えると、読み取りキャパシティは増加しますが、書き込みキャパシティは増加しません。より大きなノードタイプ (r5.8xlarge まで) では、より多くの書き込みを処理できますが、ノードが少なすぎる場合は、ノードの障害が発生した際に可用性が影響を受ける可能性があります。DAX クラスターのサイジングの詳細については、「DAX クラスターサイジングガイド」を参照してください。
以下のセクションでは、スケーラブルでコスト効率の高いクラスターを作成する際、ノードタイプとノード数のバランスを取るために考慮すべきさまざまなサイジングの側面について説明します。
このセクションの内容
可用性の計画
DAX クラスターのサイズを設定する際は、目標とする可用性にフォーカスする必要があります。DAX などのクラスター化されたサービスの可用性は、クラスター内のノードの総数のディメンションです。単一ノードクラスターには障害に対する耐性がないため、その可用性は 1 つのノードに等しくなります。10 ノードのクラスターでは、1 つのノードが失われても、クラスターの全体的なキャパシティへの影響は最小限に抑えられます。残りのノードは引き続き読み取りリクエストを処理できるため、この損失は可用性に直接影響しません。書き込みを再開するために、DAX は新しいプライマリノードをすばやく指定します。
DAX は VPC ベースです。DAX はサブネットグループを使用して、ノードを実行できるアベイラビリティーゾーン
書き込みスループットの計画
すべての DAX クラスターには、書き込みスルーリクエスト用のプライマリノードがあります。その書き込みキャパシティは、クラスターのノードタイプのサイズによって決まります。リードレプリカを追加しても、クラスターの書き込みキャパシティは増えません。したがって、クラスターの作成時に書き込みキャパシティを考慮する必要があります。これは、後でノードタイプを変更することはできないためです。
項目キャッシュを更新するためにアプリケーションで書き込みスルー DAX が必要な場合は、書き込みを容易にするためにクラスターリソースの使用を増やすことを検討してください。DAX に対する書き込みは、キャッシュヒット読み取りの約 25 倍のリソースを消費します。このため、読み取り専用クラスターよりも大きなノードタイプが必要になる場合があります。
書き込みスルーまたは書き込みアラウンドがアプリケーションに最適かどうかを判断するための追加のガイダンスについては、「書き込みの方法」を参照してください。
読み取りスループットの計画
DAX クラスターの読み取りキャパシティは、ワークロードのキャッシュヒットレートによって異なります。キャッシュミスが発生すると DAX は DynamoDB からデータを読み取るため、キャッシュヒットの約 10 倍のクラスターリソースを消費します。キャッシュヒットを増やすには、キャッシュの TTL 設定を増やして、項目がキャッシュに保存される期間を定義します。ただし、TTL 期間を長くすると、DAX を介して更新が書き込まれない限り、古い項目バージョンを読み取る可能性が高くなります。
クラスターに十分な読み込みキャパシティがあることを確認するには、「クラスターの水平スケーリング」の説明に従ってクラスターを水平方向にスケーリングします。ノードを追加すると、リソースのプールにリードレプリカが追加され、ノードを削除すると、読み取りキャパシティが減少します。クラスターのノード数とそのサイズを選択する際は、必要な読み取りキャパシティの最小量と最大量の両方を考慮します。読み取り要件を満たすために、小さいノードタイプのクラスターを水平方向にスケーリングできない場合は、より大きいノードタイプを使用してください。
データセットサイズの計画
使用可能な各ノードタイプには、DAX がデータをキャッシュするためのメモリサイズが設定されています。ノードタイプが小さすぎる場合、アプリケーションがリクエストするワーキングデータセットがメモリに収まらず、キャッシュミスが発生します。大きなノードはより大きなキャッシュをサポートしているため、キャッシュが必要な想定されるデータセットよりも大きいノードタイプを使用してください。キャッシュを大きくすることで、キャッシュヒットレートも向上します。
読み取りがほとんど繰り返されない項目をキャッシュすると、リターンが減少する可能性があります。頻繁にアクセスされる項目のメモリサイズを計算し、キャッシュがそのデータセットを保存するのに十分な大きさであることを確認します。
クラスターの概算キャパシティ要件の計算
ワークロードの合計キャパシティを見積もって、クラスターノードの適切なサイズと量を選択することができます。キャパシティを見積もるには、1 秒あたりの正規化されたリクエスト (正規化された RPS) 変数を計算します。この変数は、キャッシュヒット、キャッシュミス、書き込みなど、アプリケーションが DAX クラスターでサポートする必要がある作業の合計単位を表します。正規化された RPS を計算するには、次の入力を使用します。
-
ReadRPS_CacheHit
– キャッシュヒットが発生する 1 秒あたりの読み取り数を指定します。 -
ReadRPS_CacheMiss
– キャッシュミスが発生する 1 秒あたりの読み取り数を指定します。 -
WriteRPS
– DAX を通過する 1 秒あたりの書き込み数を指定します。 -
DaxNodeCount
- DAX クラスターのノード数を指定します。 -
Size
– 書き込みまたは読み取り中の項目のサイズを、最も近い KB に切り上げて KB 単位で指定します。 -
10x_ReadMissFactor
– 値 10 を表します。キャッシュミスが発生すると、DAX はキャッシュヒットの約 10 倍のリソースを使用します。 -
25x_WriteFactor
– 値 25 を表します。これは、DAX 書き込みスルーはキャッシュヒットの約 25 倍のリソースを使用するためです。
次の式を使用して、正規化された RPS を計算します。
Normalized RPS = (ReadRPS_CacheHit * Size) + (ReadRPS_CacheMiss * Size * 10x_ReadMissFactor) + (WriteRequestRate * 25x_WriteFactor * Size * DaxNodeCount)
例えば、以下の入力値を考えてみます。
-
ReadRPS_CacheHit
= 50,000 -
ReadRPS_CacheMiss
= 1,000 -
ReadMissFactor
= 1 -
Size
= 2 KB -
WriteRPS
= 100 -
WriteFactor
= 1 -
DaxNodeCount
= 3
これらの値を計算式で使用することで、正規化された RPS を次のように計算できます。
Normalized RPS = (50,000 Cache Hits/Sec * 2KB) + (1,000 Cache Misses/Sec * 2KB * 10) + (100 Writes/Sec * 25 * 2KB * 3)
この例では、正規化された RPS の計算値は 135,000 です。ただし、この正規化された RPS 値では、クラスター使用率を 100% 未満に抑えること、またはノード損失が考慮されていません。追加の容量を考慮することをお勧めします。これを行うには、目標使用率とノード損失耐性の 2 つの乗算係数のうち大きい方を決定します。次に、正規化された RPS に大きい方の係数を掛けて、1 秒あたりのターゲットリクエスト (ターゲット RPS) を取得します。
-
目標使用率
パフォーマンスへの影響によりキャッシュミスが増加するため、DAX クラスターを 100% の使用率で実行することはお勧めしません。理想的には、クラスター使用率を 70% 以下に維持する必要があります。これを実現するには、正規化された RPS に 1.43 を掛けます。
-
ノード損失耐性
ノードに障害が発生した場合、アプリケーションは残りのノード間でリクエストを分散処理する必要があります。ノードの使用率を 100% 未満に維持するには、障害が発生したノードがオンラインに戻るまで、障害によって増加したトラフィックを吸収するのに十分な大きさのノードタイプを選択します。ノード数が少ないクラスターの場合、1 つのノードに障害が発生した場合、各ノードはより大きなトラフィックの増加を許容する必要があります。
プライマリノードに障害が発生した場合、DAX は自動的にリードレプリカにフェイルオーバーし、新しいプライマリとして指定します。レプリカノードに障害が発生した場合、障害が発生したノードが回復するまで、DAX クラスター内の他のノードがリクエストを処理します。
例えば、ノード障害のある 3 ノード DAX クラスターでは、残りの 2 つのノードで追加の 50% の容量が必要です。これには 1.5 の乗算係数が必要です。また、障害が発生したノードを持つ 11 ノードクラスターでは、残りのノードに 10% の容量を追加するか、1.1 の乗算係数が必要です。
次の式を使用して、ターゲット RPS を計算します。
Target RPS = Normalized RPS * CEILING(TargetUtilization, NodeLossTolerance)
例えば、ターゲット RPS の計算で、以下の値を考えてみます。
-
Normalized RPS
= 135,000 -
TargetUtilization
= 1.43クラスターの最大使用率を 70% にすることをターゲットとしているため、
TargetUtilization
を 1.43 に設定します。 -
NodeLossTolerance
= 1.53 ノードクラスターを使用するため、
NodeLossTolerance
を 50% キャパシティに設定します。
これらの値を計算式に置き換えることで、ターゲット RPS を次のように計算できます。
Target RPS = 135,000 * CEILING(1.43, 1.5)
この例では、NodeLossTolerance
の値が TargetUtilization
より大きいため、NodeLossTolerance
を使用してターゲット RPS の値を計算します。計算の結果、ターゲット RPS は 202,500 になります。これが、DAX クラスターがサポートする必要があるキャパシティの合計です。クラスターで必要なノードの数を決定するには、ターゲット RPS を次の表の適切な列にマッピングします。ターゲット RPS が 202,500 の場合、3 つのノードを持つ dax.r5.large ノードタイプが必要です。
ノードタイプ別のクラスタースループットキャパシティの概算
Target RPS formula を使用すると、さまざまなノードタイプのクラスターキャパシティを見積もることができます。次の表は、1、3、5、11 のノードタイプのクラスターのおおよそのキャパシティを示しています。これらのキャパシティは、独自のデータおよびリクエストパターンを使用した DAX の負荷テストの必要性を置き換えるものではありません。さらに、固定 CPU キャパシティがないため、これらのキャパシティには t タイプインスタンスは含まれません。次の表のすべての値の単位は正規化された RPS です。
ノードタイプ (メモリ) | 1 ノード | 3 ノード | 5 ノード | 11 ノード |
---|---|---|---|---|
dax.r5.24xlarge (768GB) | +1M | 3M | 5M | 11M |
dax.r5.16xlarge (512GB) | +1M | 3M | 5M | 11M |
dax.r5.12xlarge (384GB) | +1M | 3M | 5M | 11M |
dax.r5.8xlarge (256GB) | +1M | 3M | 5M | 11M |
dax.r5.4xlarge (128GB) | 600k | 1.8M | 3M | 6.6M |
dax.r5.2xlarge (64GB) | 300k | 900k | 1.5M | 3.3M |
dax.r5.xlarge (32GB) | 150k | 450k | 750k | 1.65M |
dax.r5.large (16GB) | 75k | 225k | 375k | 825k |
各ノードの最大制限は 100 万 NPS (1 秒あたりのネットワークオペレーション) であるため、dax.r5.8xlarge 以上のノードタイプによってクラスターキャパシティが増えることはありません。8xlarge を超えるノードタイプは、クラスターの合計スループットキャパシティに影響しない可能性があります。ただし、このようなノードタイプは、より大きなワーキングデータセットをメモリに保存する場合に役立ちます。
DAX クラスターでの書き込みキャパシティのスケーリング
DAX への書き込みごとに、各ノードで 25 個の正規化されたリクエストが消費されます。各ノードには 100 万 RPS の制限があるため、DAX クラスターの書き込みは 1 秒あたり 40,000 回に制限されます (読み取り使用量は考慮されません)。
ユースケースでキャッシュに 1 秒あたり 40,000 回以上の書き込みが必要な場合は、別の DAX クラスターを使用し、クラスター間で書き込みをシャードする必要があります。DynamoDB と同様に、キャッシュに書き込むデータのパーティションキーをハッシュできます。次に、モジュラスを使用して、データを書き込むシャードを決定します。
次の例では、入力文字列のハッシュを計算します。その後、ハッシュ値のモジュラスを 10 で計算します。
def hash_modulo(input_string): # Compute the hash of the input string hash_value = hash(input_string) # Compute the modulus of the hash value with 10 bucket_number = hash_value % 10 return bucket_number #Example usage if _name_ == "_main_": input_string = input("Enter a string: ") result = hash_modulo(input_string) print(f"The hash modulo 10 of '{input_string}' is: {result}.")