Spanner の期限超過エラーのトラブルシューティング

このページでは、Spanner の期限超過エラーの概要(状況、原因、トラブルシューティングと解決方法)について説明します。

Spanner API にアクセスすると、DEADLINE_EXCEEDED エラーが原因でリクエストが失敗することがあります。このエラーは、あらかじめ構成されているタイムアウト時間内にレスポンスが取得されなかったことを示します。

期限超過エラーは、Spanner インスタンスの過負荷、最適化されていないスキーマ、最適化されていないクエリなど、さまざまな理由で発生します。このページでは、期限超過エラーになる一般的なシナリオについて説明し、これらの問題を調査して解決する方法を示します。

Spanner の期限と再試行の考え方

Spanner の期限と再試行の考え方は、他の多くのシステムと異なります。Spanner では、タイムアウト期限を、回答が有効となる最大時間として指定する必要があります。同じオペレーションを即座に再試行するためだけに期限を人為的に短くすることは推奨されていません。オペレーションがいつまでも完了しない原因となるためです。このコンテキストで、次の手法とオペレーションはおすすめしません。これらは望ましくない結果を招き、Spanner の内部再試行動作を駄目にします。

  • 短すぎる期限を設定する。これは、オペレーションが時折発生するテール レイテンシの増加に対して耐性がなく、タイムアウトする前に完了できないことを意味します。代わりに、回答が有効となる最大時間である期限を設定します。

  • 長��ぎる期限を設定し、その期限前にオペレーションをキャンセルする。これは、複数の再試行を発生させる原因となり、それぞれの試行で無駄が発生します。集計では、インスタンスの負荷がかなり大きくなる可能性があります。

期限超過エラーとは?

Spanner クライアント ライブラリのいずれかを使用すると、基盤となる gRPC レイヤが通信、マーシャリング、マーシャリング解除、期限の適用を処理します。期限を設定すると、期限超過エラーが発生してリクエストが終了する前に、リクエストが完了するまでにアプリケーションが待機する時間を指定できます。

タイムアウト構成ガイドでは、サポートされている各 Spanner クライアント ライブラリで期限(またはタイムアウト)を指定する方法が説明されています。Spanner クライアント ライブラリでは、次の構成ファイルで定義されているデフォルトのタイムアウト ポリシー設定と再試行ポリシー設定が使用されます。

gRPC の期限の詳細については、gRPC と期限をご覧ください。

一般的な期限超過エラーを調査して解決する方法

次のタイプの問題では、DEADLINE_EXCEEDED エラーが発生することがあります。

データアクセス API の問題

データアクセス API の問題を回避するには、Spanner インスタンスを特定のワークロードに合わせて適切に構成する必要があります。以下のセクションでは、さまざまなデータアクセス API の問題を調査して解決する方法について説明します。

Spanner インスタンスの CPU 負荷を確認する

CPU 使用率が推奨されている正常なしきい値を超えると、リクエストのレイテンシが大幅に増加することがあります。Spanner の CPU 使用率は、 Google Cloud コンソールに用意されているモニタリング コンソールで確認できます。インスタンスの CPU 使用率に基づいてアラートを作成することもできます。

解決策

インスタンスの CPU 使用率を下げる手順については、CPU 使用率を減少させるをご覧ください。

リクエストのエンドツーエンド レイテンシの内訳の確認

リクエストがクライアントから Spanner サーバーへ、そし��再びクライアントへ送信される際には、クライアント ライブラリから Google Front End(GFE)へ、GFE から Spanner API フロントエンドへ、そして最後に Spanner API フロントエンドから Spanner データベースへというように、複数のネットワーク ホップが発生します。これらのステージのいずれかでネットワークに問題があると、期限超過エラーが表示されることがあります。

各ステージのレイテンシをキャプチャできます。詳細については、Spanner リクエストのレイテンシ ポイントをご覧ください。Spanner でレイテンシが発生している場所を確認するには、Spanner でレイテンシが発生している場所を特定するをご覧ください。

解決策

レイテンシの内訳を入手したら、指標を使用してレイテンシを診断し、その原因を把握して解決策を見つけることができます。

Data API の問題

Spanner の Data API の最適でない使用パターンによって、期限超過エラーが発生することがあります。このセクションでは、こうした最適でない使用パターンを確認する方法について説明します。

コストの高いクエリの確認

クライアント ライブラリで、構成済みのタイムアウト期限内に実行されない高コストのクエリを実行すると、期限超過エラーが発生することがあります。コストの高いクエリの例には、大きなテーブルの完全スキャン、複数の大きなテーブルのクロス結合、非キー列に対する述語によるクエリ実行(テーブル全体のスキャンも)などがあります(これらに限定されません)。

クエリの統計情報テーブルとトランザクションの統計情報テーブルを使用してコストの高いクエリを調査できます。平均読み取り行数、平均読み取りバイト数、平均スキャン行数など、実行に時間がかかっているクエリ / トランザクションに関する情報がこれらのテーブルに表示されます。さらに、クエリ実行計画を作成して、クエリが実行される様子を詳しく調べることもできます。

解決策

クエリを最適化するには、SQL クエリのベスト プラクティス ガイドをご覧ください。また、前述の統計情報テーブルと実行プランで取得したデータを使用して、クエリを最適化し、データベースに対してスキーマの変更を行うこともできます。これらのベスト プラクティスは、ステートメントの実行時間を短縮する効果があり、期限超過エラーの解消に役立ちます。

ロックの競合の確認

Spanner のトランザクションは commit するためにロックを取得する必要があります。高スループット状態で実行されているアプリケーションでは、同じリソースでトランザクションが競合することがあります。これが原因で、ロックを取得するための待ち時間が長くなり、全体的なパフォーマンスに影響を及ぼします。その結果、読み取りリクエストと書き込みリクエストで期限を超過する可能性があります。

レイテンシが高���読み取り / 書き込みトランザクションの根本原因は、ロックの統計情報テーブルで確認できます。また、次のブログ投稿もご覧ください。ロックの統計情報テーブルで、ロックの待機時間が最も長い行キーを確認できます。

このロック競合のトラブルシューティング ガイドでは、ロック競合に関係する列にアクセスしているトランザクションを見つける方法が説明されています。また、トランザクション タグのトラブルシューティング ガイドを使用して、ロック競合に関係するトランザクションを見つけることもできます。

解決策

こちらのベスト プラクティスを適用して、ロック競合を減らします。さらに、単純な読み取りのユースケースでは、読み取り専用トランザクションを使用して書き込みとのロック競合を回避します。読み取り / 書き込みトランザクションは、書き込みワークフロー用か、読み取り / 書き込みの混合ワークフロー用に予約する必要があります。これらの手順により、トランザクションの実行時間の全体的なレイテンシを改善し、期限超過エラーを減少させることができます。

最適化されていないスキーマの確認

Spanner データベースに最適なデータベース スキーマを設計する前に、データベースで実行されるクエリの種類を検討する必要があります。スキーマが最適でない場合、一部のクエリの実行時にパフォーマンスの問題が発生する可能性があります。こうしたパフォーマンスの問題により、構成した期限内にリクエストが完了しない場合があります。

解決策

最適なスキーマ設計は、データベースに対する読み取りと書き込みによって異なります。スキーマの仕様に関係なく、スキーマ デザインのベスト プラクティス ガイドと SQL のベスト プラクティス ガイドに沿って操作してください。これらのガイドに沿うことで、最も一般的なスキーマ設計の問題を回避できます。パフォーマンス低下のその他の根本的な原因には以下のものが挙げられます。主キーの選択、テーブル レイアウト(高速アクセスのためのインターリーブ テーブルの使用を参照)、スキーマ設計(パフォーマンスのためのスキーマの最適化を参照)、Spanner インスタンス内に構成されたノードのパフォーマンス(Spanner パフォーマンスの概要を参照)。

ホットスポットの確認

Spanner は分散型データベースであるため、スキーマの設計は、ホットスポットを防ぐことを考慮する必要があります。たとえば、単調増加する列を作成すると、ワークロードを均等に分散するために Spanner で使用できるスプリットの数が制限されます。こうしたボトルネックは、タイムアウトが発生する可能性があります。また、Key Visualizer を使用すると、ホットスポットによるパフォーマンス問題のトラブルシューティングできます。

解決策

この問題を解決するには、最初のステップとして前のセクション最適化されていないスキーマを確認するで特定された解決策をご覧ください。データベース スキーマを再設計し、インターリーブ インデックスを使用して、ホットスポットが発生する可能性のあるインデックスを回避します。上記の手順で問題が解決されない場合は、ホットスポットを防ぐ主キーの選択ガイドをご覧ください。最後に、負荷ベースの分割を防止する可能性がある、最適でないトラフィック パターン(広い範囲の読み取りなど)を回避します。

誤って構成されているタイムアウトの確認

クライアント ライブラリには、Spanner のすべてのリクエストに適切なタイムアウトのデフォルト値が用意されています。ただし、これらのデフォルト構成は、特定のワークロードに合わせて調整する必要がある場合もあります。ユーザークエリのコストを確認し、特定のユースケースに合わせて期限を調整することをおすすめします。

解決策

大半のユースケースではデフォルトのタイムアウト設定で問題ありません。ユーザーはこれらの構成をオーバーライドできますが(カスタム タイムアウトと再試行ガイドを参照)、デフォルトの構成よりも積極的なタイムアウトを使用することはおすすめしません。タイムアウトを変更する場合には、アプリケーションが結果を待つように構成されている実際の時間に設定してください。より長いタイムアウトを構成しても構いませんが、タイムアウトは、アプリケーションが待てる実際の時間よりも短くしないでください。短く設定すると、オペレーションの再試行頻度が高くなります。

Admin API の問題

Admin API リクエストは、Data API リクエストと比較してコストがかかるオペレーションです。管理者リクエスト(CreateInstance、CreateDatabase、CreateBackups など)は、レスポンスを返すまでに数秒かかることがあります。Spanner クライアント ライブラリでは、インスタンス管理リクエストとデータベース管理者リクエストの両方に対して 60 分の期限が設定されます。これは、クライアントが再試行または失敗する前に、サーバーでリクエストを完了できるようにするための措置です。

解決策

Google Spanner クライアント ライブラリを使用して管理者 API にアクセ��する場合は、クライアント ライブラリが更新され、最新バージョンが使用されていることを確認してください。作成したクライアント ライブラリを介して Spanner API に直接アクセスする場合は、インスタンスとデータベース管理リクエストのデフォルト設定(60 分)よりも積極的な期限設定でないことを確認してください。

Google Cloud コンソールの問題

Google Cloud コンソールの Spanner Studio ページから発行されるクエリは 5 分を超えることはできません。実行に 5 分を超える高コストクエリを作成すると、次のエラー メッセージが表示されます。

 Google Cloud コンソールの期限超過のエラー メッセージのスクリーンショット

バックエンドが失敗したクエリをキャンセルし、必要に応じてト��ンザクションをロールバックする可能性があります。

解決策

SQL クエリのベスト プラクティス ガイドを使用して、クエリを書き換えます。

Dataflow の問題

Apache Beam では、デフォルトのタイムアウト構成は、読み取りオペレーションでは 2 時間、commit オペレーションでは 15 秒となっています。これらの構成は、スタンドアロン クライアント ライブラリの期限タイムアウトと比べて、長い時間オペレーションを行うためのものです。ただし、作業項目が大きくなりすぎると、タイムアウトと期限超過エラーが発生する可能性があります。必要に応じて、Apache Beam commit のタイムアウト構成をカスタマイズできます。

解決策

ステップ ReadFromSpanner / Execute query / Read from Spanner / Read from Partitions で期限超過エラーが発生した場合は、クエリ統計情報テーブルを確認して、多数の行をスキャンしたクエリを見つけます。次に、そのようなクエリを変更して、実行時間を短縮してみます。

Dataflow の期限超過エラーの別の例を、次の例外メッセージで示します。

exception:
     org.apache.beam.sdk.util.UserCodeException:
     com.google.cloud.spanner.SpannerException: DEADLINE_EXCEEDED:
     io.grpc.StatusRuntimeException: DEADLINE_EXCEEDED: deadline exceeded after
     3599.999905380s.
     [remote_addr=batch-spanner.googleapis.com/172.217.5.234:443] at
 org.apache.beam.runners.dataflow.worker.GroupAlsoByWindowsParDoFn$1.output(GroupAlsoByWindowsParDoFn.java:184)

このタイムアウトは、作業項目が大きすぎるため発生しました。上記の例では、次の 2 つの推奨事項が役立ちます。まず、シャッフル サービス�������有効����ってい����場合������効にします。次に、データベースの読み取りにおける構成(maxPartitions や partitionSizeBytes など)を微調整します。詳細については、PartitionOptions を参照し、作業項目のサイズを減らしてみます。これを行う方法の例については、こちらの Dataflow テンプレートをご覧ください。

追加の期限超過トラブルシューティング リソース

トラブルシューティングの手順を完了しても DEADLINE_EXCEEDED エラーが引き続き表示される場合は、次の状況でサポートケースを作成してください。

  • Google Front End のレイテンシは高いが、Spanner API リクエストのレイテンシは低い
  • Spanner API リクエストのレイテンシは高いが、クエリ レイテンシは低い

以下のトラブルシューティング リソースもご参照ください。