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

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

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

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

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

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

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

  • 短すぎる期限を設定する。これは、オペレーションが不測のレイテンシの増加に対する耐性を持たず、タイムアウトする前に完了できないことを意味します。代わりに、レスポンスが役に立つ時間の期限を設定します。

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

期限超過エラーとは

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

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

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

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

データアクセス 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 データベースなどです。これらのステージのいずれかでネットワークに問題があると、期限超過エラーが表示されることがあります。

各ステージのレイテンシをキャプチャできます(レイテンシ ガイドを参照)。診断ガイドの使用方法については、レイテンシの問題を診断する方法をご覧ください。

解決策

レイテンシの内訳を入手し、レイテンシの問題を診断したら、このレイテンシ問題のトラブルシューティング ガイドを使用して、レイテンシの原因を特定し、その原因を把握できます。

Data API の問題

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

コストの高いクエリを確認する

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

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

解決策

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

ロック競合を確認する

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

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

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

解決策

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

最適化されていないスキーマを確認する

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

解決策

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

ホットスポットを確認する

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

解決策

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

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

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

解決策

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

Admin API の問題

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

解決策

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

Google Cloud コンソールに関する問題

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

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

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

解決策

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

Dataflow の問題

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

解決策

ステップ ReadFromSpanner / Execute query / Read from Cloud 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 つの推奨事項が役立ちます。まず、シャッフル サービスが有効になっていない場合は、有効にします。次に、データベースの読み取りにおける構成(maxPartitionspartitionSizeBytes など)を微調整します。詳細については、PartitionOptions をご覧になり、作業項目のサイズを減らしてください。これを行う方法の例については、こちらの Dataflow テンプレートをご覧ください。

期限超過をトラブルシューティングする別のリソース

上記のトラブルシューティング手順を実施しても期限超過エラーが引き続き発生する場合は、サポートケースを開く必要があるかどうかの判断に次の分類を使用します(レイテンシ問題のトラブルシューティングの表にあるサポートケースの完全なリストをご覧ください)。まとめると、次のシナリオが発生した場合はサポート チケットを開いてください。

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

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