View a markdown version of this page

パフォーマンス効率の柱 - AWS 規範ガイダンス

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

パフォーマンス効率の柱

AWS Well-Architected フレームワークのパフォーマンス効率の柱は、データの取り込みまたはクエリ中にパフォーマンスを最適化する方法に焦点を当てています。パフォーマンスの最適化は、以下を段階的かつ継続的に実行するプロセスです。

  • ビジネス要件を確認する

  • ワークロードのパフォーマンスを測定する

  • パフォーマンスの低いコンポーネントを特定する

  • ビジネスニーズに合わせてコンポーネントを調整する

パフォーマンス効率の柱は、使用する適切なグラフデータモデルとクエリ言語を特定するのに役立つ、ユースケース固有のガイドラインを提供します。また、Amazon Neptune へデータを取り込み、Amazon Neptune からデータを使用する際に従うべきベストプラクティスも含まれています。

パフォーマンス効率の柱は、次の主要分野に焦点を当てています。

  • グラフモデリング

  • クエリの最適化

  • クラスターの適切なサイズ設定

  • 書き込みの最適化

グラフモデリングを理解する

Labeled Property Graph (LPG) モデルと Resource Description Framework (RDF) モデルの違いを理解します。ほとんどの場合は好みの問題ですが、あるモデルが他のモデルよりも適しているユースケースがいくつかあります。グラフ内の 2 つのノードを接続するパスに関する知識が必要な場合は、LPG を選択します。Neptune クラスターまたは他のグラフのトリプルストア間でデータをフェデレーションする場合は、RDF を選択します。

Software as a Service (SaaS) アプリケーション、またはマルチテナンシーを必要とするアプリケーションを構築する場合は、クラスターごとに 1 つのテナントを設定するのではなく、データモデルにテナントの論理的な分離を組み込むことを検討してください。このタイプの設計を実現するには、SPARQL の名前付きグラフとラベル付け戦略を使用できます。例えば、ラベルに顧客識別子を付加したり、テナント識別子を表すプロパティのキーと値のペアを追加したりできます。論理的な分離を維持するために、クライアントレイヤーがこれらの値を挿入することを確認します。マルチテナンシーの推奨事項の詳細については、Amazon Neptune データベースを実行する ISVs」を参照してください。

クエリのパフォーマンスは、クエリの処理で評価する必要があるグラフオブジェクト (ノード、エッジ、プロパティ) の数によって異なります。そのため、グラフモデルはアプリケーションのパフォーマンスに大きな影響を与える可能性があります。可能な限り細かいラベルを使用し、パスの決定またはフィルタリングに必要なプロパティのみを保存します。より高いパフォーマンスを実現するには、要約ノードの作成や共通パスを接続するより直接的なエッジの作成など、グラフの一部を事前に計算することを検討してください。

同じラベルを持つエッジの数が異常に多いノード間の移動はなるべく避けます。このようなノードには多くの場合、何千ものエッジがあります (大部分のノードのエッジカウントは数十個です)。その結果、コンピューティングとデータの複雑さがはるかに高くなります。これらのノードは、一部のクエリパターンでは問題にならない場合がありますが、特に中間ステップとしてノード間を移動する場合は、このようなノードを回避するためにデータを異なる方法でモデリングすることをお勧めします。スロークエリログを使用して、これらのノード間を移動するクエリを識別できます。特にデバッグモードを使用すると、レイテンシーとデータアクセスメトリクスが平均的なクエリパターンよりもはるかに高くなることがわかります。

Neptune を使用して ID にランダムな GUID 値を割り当てる代わりに、確定的なノード ID をノードとエッジに使用します (ユースケースでサポートされている場合)。ID によるノードへのアクセスが最も効率的な方法です。

クエリを最適化する

LPG モデルでは、openCypher 言語と Gremlin 言語を同じように使用できます。パフォーマンスが最大の懸念事項である場合は、2 つの言語を互換的に使用することを検討してください。特定のクエリパターンでは、ある言語が他の言語よりもパフォーマンスに優れる可能性があるためです。

Neptune は、代替クエリエンジン (DFE) への変換を進めています。openCypher は DFE でのみ実行されますが、オプションで、クエリ注釈を使用して Gremlin クエリと SPARQL クエリの両方を DFE で実行するように設定できます。DFE を有効にした状態でクエリをテストし、DFE を使用しない場合のクエリパターンのパフォーマンスと比較することを検討してください。

Neptune は、グラフ全体を評価する分析クエリではなく、単一ノードまたは一連のノードから開始し、そこからファンアウトするトランザクションタイプのクエリに最適化されています。分析クエリワークロードには、Neptune Analytics を使用します。Neptune Analytics は、データ、分析、アルゴリズム処理に高速反復を必要とする調査、調査、またはデータサイエンスのワークロードに最適です。また、グラフデータに対してベクトル検索を実行し、Neptune データベースインスタンスから直接データをロードすることもできます。Neptune Analytics がニーズを満たさない場合は、 AWS SDK for Pandas または と AWS Glueまたは Amazon EMR を組み合わせた neptune-export の使用を検討することもできます。

モデルとクエリの非効率やボトルネックを特定するには、各クエリ言語の profile および explain API を使用して、クエリプランとクエリメトリクスの詳細な説明を取得します。詳細については、「Gremlin profile」、「openCypher explain」、および「SPARQL explain」を参照してください。

クエリパターンを理解します。グラフ内の個別のエッジの数が多くなると、Neptune のデフォルトのアクセス方式は効率が悪くなる場合があります。以下のクエリは、非常に非効率になる可能性があります。

  • エッジラベルが指定されていない場合にエッジ間を後方に移動するクエリ。

  • Gremlin の .both() など、内部的に同じパターンを使用する句、または任意の言語でノードをドロップする句 (ラベルを認識せずに受信エッジをドロップする必要があります)。

  • プロパティラベルを指定せずにプロパティ値にアクセスするクエリ。これらのクエリは、非常に非効率になる可能性があります。これが使用パターンと一致する場合は、OSGP インデックス (目的語、主語、グラフ、述語) を有効にすることを検討してください。

スロークエリログを使用して、遅いクエリを識別します。クエリの遅延は、最適化されていないクエリプランや不必要に多いインデックスルックアップが原因で発生する可能性があり、I/O コストが増加する可能性があります。GremlinSPARQL、または openCypher 向けの Neptune の explain エンドポイントと profile エンドポイントは、これらのクエリが遅い理由を理解するのに役立ちます。句には次のものが含まれる場合があります。

  • グラフ内の平均ノードと比較してエッジ数が異常に多いノード (数十に対して数千など) は、計算の複雑さが増し、レイテンシーが長くなり、リソースの消費量が増える可能性があります。これらのノードが正しくモデル化されているかどうか、または横断する必要があるエッジの数を減らすためにアクセスパターンを改善できるかどうかを決定します。

  • 最適化されていないクエリには、特定のステップが最適化されていないという警告が含まれます。これらのクエリを書き換えて最適化されたステップを使用すると、パフォーマンスが向上する可能性があります。

  • 冗長フィルターは、不要なインデックスルックアップを引き起こす可能性があります。同様に、冗長パターンは重複したインデックスルックアップを引き起こす可能性があり、これはクエリを改善することで最適化できます (プロファイル出力の「Index Operations - Duplication ratio」を参照)。

  • Gremlin などの一部の言語には厳密に型指定された数値がなく、代わりに型の上位変換を使用します。例えば、値が 55 の場合、Neptune は、整数型、ロング型、浮動小数点型、およびその他の 55 に相当する数値型の値を検索します。これにより、追加のオペレーションが発生します。型が一致することが事前にわかっている場合は、クエリヒントを使用してこれを回避できます。

  • グラフモデルはパフォーマンスに大きな影響を与える可能性があります。より細かいラベルを使用するか、マルチホップ線形パスへのショートカットを事前に計算して、評価する必要があるオブジェクトの数を減らすことを検討してください。

クエリの最適化だけではパフォーマンス要件を満たすことができない場合は、Neptune でさまざまなキャッシュ手法を使用してこれらの要件を満たすことを検討してください。

Neptune のパフォーマンスは、バージョンごとに継続的に向上しています。リリースノートを確認して、各リリースの改善点の詳細を確認してください。最適なパフォーマンスを実現するために、Neptune DB クラスターの定期的な更新を計画することを検討してください。新しいバージョンでは、新しいインスタンスもサポートされています。r8g インスタンスを利用できるようにするには、1.4.5.0 以降にアップグレードすることを検討してください。これがワークロードのパフォーマンスを向上させる方法の詳細については、「Amazon Amazon Neptune v1.4.5 を使用した AWS Graviton4 R8g インスタンスでの書き込みクエリの料金パフォーマンスが 4.7 倍向上しました」を参照してください。

クラスターを適切なサイズにする

同時実行要件とスループット要件に合わせてクラスターのサイズを設定します。クラスター内の各インスタンスで処理できる同時クエリの数は、そのインスタンスの仮想 CPU (vCPU) の数の 2 倍です。すべてのワーカースレッドが占有されている間に到着する追加のクエリは、サーバー側のキューに入れられます。これらのクエリは、ワーカースレッドが利用可能になったときに先入れ先出し (FIFO) ベースで処理されます。MainRequestQueuePendingRequests Amazon CloudWatch メトリクスには、各インスタンスの現在のキューの深さが表示されます。この値が頻繁に 0 を超える場合は、より多くの vCPU を持つインスタンスの選択を検討してください。キューの深さが 8,192 を超えると、Neptune はThrottlingException エラーを返します。

各インスタンスの RAM の約 65% がバッファキャッシュ用に予約されています。バッファキャッシュは、データのワーキングデータセット (グラフ全体ではなく、クエリ対象のデータのみ) を保持します。ストレージではなくバッファキャッシュから取得されるデータの割合を確認するには、CloudWatch メトリクスの BufferCacheHitRatio をモニタリングします。このメトリクスが 99.9% を下回ることがよくある場合は、より多くのメモリを持つインスタンスを試して、レイテンシーと I/O コストが減少するかどうか判断することを検討してください。

リードレプリカは、ライターインスタンスと同じサイズである必要はありません。ただし、書き込みワークロードが多いと、レプリケーションに追いつくことができないため、小さいレプリカは遅くなり、再起動する可能性があります。したがって、レプリカのサイズはライターインスタンスと同じかそれ以上にすることをお勧めします。

リードレプリカに自動スケーリングを使用する場合は、新しいリードレプリカをオンラインにするのに最大 15 分かかる場合があることに注意してください。クライアントトラフィックが急に、ただし予測可能な範囲で増加する場合は、スケジュールに基づくスケーリングを使用して、その初期化時間を考慮してリードレプリカの最小数を高く設定することを検討してください。

サーバーレスインスタンスは、いくつかの異なるユースケースとワークロードをサポートしています。以下のシナリオでは、プロビジョニングインスタンスよりもサーバーレスを優先して検討します。

  • ワークロードが 1 日を通して頻繁に変動する。

  • 新しいアプリケーションを作成したが、ワークロードのサイズが不明。

  • 開発とテストを実行している。

サーバーレスインスタンスは、同等のプロビジョニングされたインスタンスよりも、GB 単位の RAM ベースでコストがかかることに注意してください。各サーバーレスインスタンスは、2 GB の RAM と関連する vCPU およびネットワークで構成されます。想外の請求を回避するため、オプションごとのコストを分析します。一般的に、大量のワークロードが発生するのは毎日数時間のみで、残りの時間はほぼゼロの場合、またはワークロードが 1 日を通して大幅に変動する場合にのみ、サーバーレスでコスト削減を達成できます。

Amazon Neptune 料金計算ツールを使用して、1 queries-per-second (QPS) 要件などの要因に基づいてクラスターの正しい設定を評価します。

書き込みの最適化

書き込みを最適化するには、次の点を考慮してください。

  • Neptune Bulk Loader は、最初にデータベースをロードしたり、既存のデータに追加したりする場合に最適な方法です。Neptune ローダーはトランザクションではなく、データを削除できないため、データの削除が要件である場合は使用しないでください。

  • トランザクションの更新は、サポートされているクエリ言語を使用して行うことができます。書き込み I/O オペレーションを最適化するには、コミットごとに 50~100 個のオブジェクトを一括でデータを書き込みます。オブジェクトとは、LPG のノード、エッジ、またはノードもしくはエッジ上のプロパティ、または RDF のトリプルストアまたはクワッドです。

  • すべてのトランザクション Neptune 書き込みオペレーションは、接続ごとにシングルスレッドになります。Neptune に大量のデータを送信するときは、それぞれがデータを書き込む複数の並列接続を設定することを検討してください。Neptune でプロビジョニングされたインスタンスを選択すると、インスタンスサイズは vCPU の数に関連付けられます。Neptune はインスタンス上の vCPU ごとに 2 つのデータベーススレッドを作成するため、最適な並列接続を決定するためにテストする際は vCPU の数の 2 倍から開始します。  サーバーレスインスタンスは、4 NCU ごとにおよそ 1 のレートで vCPU の数をスケーリングします。

    注記

    これは一括ロード API には適用されず、直接接続にのみ適用されます。

  • 任意の時間に単一の接続だけがデータを書き込んでいる場合でも、すべての書き込みプロセス中の ConcurrentModificationExceptions に備えて計画を立て、効率的に処理します。ConcurrentModificationExceptions が発生しても信頼性を損なわないようクライアントを設計します。

  • すべてのデータを削除する場合は、同時削除クエリを発行するのではなく、高速リセット API を使用することを検討してください。後者は前者に比べてはるかに時間がかかり、かなりの I/O コストが発生します。

  • ほとんどのデータを削除する場合は、neptune-export を使用して新しいクラスターにデータをロードすることで、保持するデータをエクスポートすることを検討してください。その後、元のクラスターを削除します。