Spanner には、クエリ、読み取り、トランザクションに関する分析情報の取得に役立つ、一連の組み込み統計テーブルが用意されています。統計情報とアプリケーション コードを関連付けてトラブルシューティングの改善を図るため、アプリケーション コードで Spanner の読み取り、クエリ、トランザクション オペレーションにタグ(自由形式の文字列)を追加できます。これらのタグは、統計情報テーブルに入力され、タグに基づいて関連付けと検索を行えます。
Spanner では、2 種類のタグ(リクエスト タグと トランザクション タグ)がサポートされています。その名前が示すように、トランザクションにはトランザクション タグを、個々のクエリ API や読み取り API にはリクエストタグを追加できます。トランザクション タグはトランザクション スコープで設定でき、個々のリクエストタグはトランザクション内の該当する API リクエストごとに設定できます。アプリケーション コードで設定されるリクエストタグとトランザクション タグは、次の統計情報テーブルの列に入力されます。
統計情報テーブル | 統計情報テーブルに入力されるタグの種類 |
---|---|
TopN クエリ統計情報 | リクエストタグ |
TopN 読み取り統計情報 | リクエストタグ |
TopN トランザクション統計情報 | トランザクション タグ |
TopN ロック統計情報 | トランザクション タグ |
リクエストタグ
クエリや読み取りリクエストには、オプションのリクエストタグを追加できます。Spanner は、リクエストタグ別に統計情報をグループ化します。これは、クエリ統計情報と読み取り統計情報両方の REQUEST_TAG
フィールドで確認できます。
リクエストタグを使用する場合
リクエストタグの使用によりメリットを得られるシナリオの例を次に示します。
- 問題のあるクエリや読み取りの発生源を見つける: Spanner では、組み込み統計テーブル内の読み取りとクエリに関する統計情報が収集されます。統計情報テーブルで時間がかかるクエリや CPU 使用率の高い読み取りが見つかったときに、すでにタグが割り当てられていれば、タグの情報に基づいて、こうしたオペレーションを呼び出しているソース(アプリケーション / マイクロサービス)を特定できます。
- 統計情報テーブルの読み取りやクエリを特定する: リクエストタグを割り当てると、関心のあるタグに基づいて、統計情報テーブルの行をフィルタリングできます。
- 特定のアプリケーションやマイクロサービスからのクエリが遅いかどうかを判断する: リクエストタグを使用すると、特定のアプリケーションやマイクロサービスからのクエリがレイテンシが高いかどうかを見分けるのに役立ちます。
- 一連の読み取りやクエリに関する統計情報をグループ化する: リクエストタグを使用して、一連の類似した読み取りやクエリのパフォーマンスを追跡、比較、報告できます。たとえば、同じアクセス パターンを持つテーブル / 一連のテーブルに複数のクエリがアクセスしている場合は、そうしたクエリのすべてに同じタグを追加して、それらを一緒に追跡することを検討できます。
リクエストタグを割り当てる方法
次のサンプルでは、Spanner クライアント ライブラリを使用してリクエストタグを設定する方法を示します。
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
統計情報テーブルでリクエストタグを確認する方法
次のクエリでは、10 分間隔のクエリの統計情報が返されます。
SELECT t.text,
t.request_tag,
t.execution_count,
t.avg_latency_seconds,
t.avg_rows,
t.avg_bytes
FROM SPANNER_SYS.QUERY_STATS_TOP_10MINUTE AS t
LIMIT 3;
クエリから返される結果の例として、以下のデータを見てみましょう。
テキスト | request_tag | execution_count | avg_latency_seconds | avg_rows | avg_bytes |
---|---|---|---|---|---|
SELECT SingerId, AlbumId, AlbumTitle FROM Albums | app=concert,env=dev,action=select | 212 | 0.025 | 21 | 2365 |
select * from orders; | app=catalogsearch,env=dev,action=list | 55 | 0.02 | 16 | 33.35 |
SELECT SingerId, FirstName, LastName FROM Singers; | [empty string] | 154 | 0.048 | 42 | 486.33 |
この結果の表から、クエリに REQUEST_TAG
を割り当てた場合は、統計テーブルに値が入力されることがわかります。リクエストタグが割り当てられていない場合は、空の文字列として表示されます。
タグ付きクエリの場合、統計情報はタグごとに集計されます(リクエストタグ app=concert,env=dev,action=select
の平均レイテンシは 0.025 秒など)。タグが割り当てられていない場合、統計情報はクエリごとに集計されます(3 行目のクエリの平均レイテンシは 0.048 秒など)。
トランザクション タグ
オプションのトランザクション タグは、個々のトランザクションに追加できます。Spanner は、トランザクション タグ別に統計情報をグループ化します。これは、トランザクションの統計情報テーブルの TRANSACTION_TAG
フィールドで確認できます。
トランザクション タグを使用する場合
トランザクション タグの使用によりメリットを得られるシナリオの例を次に示します。
- 問題のあるトランザクションの発生源を見つける: Spanner では、トランザクションの統計情報テーブル内の読み取り / 書き込みトランザクションに関する統計情報が収集されます。トランザクションの統計情報テーブルで遅いトランザクションが見つかり、すでにタグが割り当てられている場合は、そのタグの情報に基づいて、トランザクションを呼び出しているソース(アプリケーション / マイクロサービス)を特定できます。
- 統計テーブル内のトランザクションを区別する: トランザクション タグを割り当てると、関心があるタグに基づいてトランザクション統計情報テーブルの行をフィルタリングできます。トランザクション タグを使用しない場合は、統計で表されるオペレーションを見つけるのことが、煩雑なプロセスになる可能性があります。たとえば、トランザクションの統計情報の場合、タグ付けされていないトランザクションを特定するためには、関連するテーブルと列を調べる必要があります。
- 特定のアプリケーションやマイクロサービスからのトランザクションが遅いかどうかを判断する確認: トランザクション タグを使用すると、特定のアプリケーションやマイクロサービスからのトランザクションのレイテンシが高いかどうかを見分けるのに役立ちます。
- 一連のトランザクションに関する統計情報をグループ化する: トランザクション タグを使用して、一連の類似したトランザクションのパフォーマンスを追跡、比較、報告できます。
- ロックの競合に関係する列にアクセスしているトランザクションを見つける: トランザクション タグを使用すると、ロックの統計情報テーブルでロックの競合を引き起こしている個々のトランザクションを特定できます。
- 変更ストリームを使用して Spanner からユーザー変更データをストリーミングする: 変更ストリーム データレコードには、ユーザーデータを変更したトランザクションのトランザクション タグが含まれます。これにより、変更ストリームの読み取り側は、タグに基づいて変更をトランザクション タイプに関連付けることができます。
トランザクション タグを割り当てる方法
次のサンプルでは、Spanner クライアント ライブラリを使用してトランザクション タグを設定する方法を示します。クライアント ライブラリを使用する際、トランザクション呼び出しの先頭には、トランザクション内のすべてのオペレーションに適用されるトランザクション タグを設定できます。
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
トランザクション統計情報テーブルでトランザクション タグを確認する方法
次のクエリでは、10 分間隔のトランザクションの統計情報が返されます。
SELECT t.fprint,
t.transaction_tag,
t.read_columns,
t.commit_attempt_count,
t.avg_total_latency_seconds
FROM SPANNER_SYS.TXN_STATS_TOP_10MINUTE AS t
LIMIT 3;
クエリから返される結果の例として、以下のデータを見てみましょう。
fprint | transaction_tag | read_columns | commit_attempt_count | avg_total_latency_seconds |
---|---|---|---|---|
40015598317 | app=concert,env=dev | [Venues._exists, Venues.VenueId, Venues.VenueName, Venues.Capacity] |
278802 | 0.3508 |
20524969030 | app=product,service=payment | [Singers.SingerInfo] | 129012 | 0.0142 |
77848338483 | [empty string] | [Singers.FirstName, Singers.LastName, Singers._exists] | 5357 | 0.048 |
この結果のテーブルから、トランザクションに TRANSACTION_TAG
を割り当てると、トランザクションの統計情報テーブルに値が入力されることがわかります。トランザクション タグが割り当てられていない場合は、空の文字列として表示されます。
タグ付けされたトランザクションの場合、統計情報はトランザクション タグごとに集計されます(トランザクション タグ app=concert,env=dev
の平均レイテンシは 0.3508 秒など)。タグが割り当てられていない場合、統計情報は FPRINT
ごとに集計されます(3 行目の 77848338483 は平均レイテンシが 0.048 秒など)。
ロック統計情報テーブルでトランザクション タグを表示する方法
次のクエリでは、10 分間隔のロック統計情報が返されます。
CAST()
関数は、row_range_start_key
BYTES フィールドを STRING に変換します。
SELECT
CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
s.lock_wait_seconds,
s.sample_lock_requests
FROM SPANNER_SYS.LOCK_STATS_TOP_10MINUTE s
LIMIT 2;
クエリから返される結果の例として、以下のデータを見てみましょう。
row_range_start_key | lock_wait_seconds | sample_lock_requests |
---|---|---|
Songs(2,1,1) | 0.61 | LOCK_MODE: ReaderShared COLUMN: Singers.SingerInfo TRANSACTION_TAG: app=product,service=shipping LOCK_MODE: WriterShared COLUMN: Singers.SingerInfo TRANSACTION_TAG: app=product,service=payment |
albums(2,1+) | 0.48 | LOCK_MODE: ReaderShared COLUMN: users._exists1 TRANSACTION_TAG: [empty string] LOCK_MODE: WriterShared COLUMN: users._exists TRANSACTION_TAG: [empty string] |
この結果のテーブルから、トランザクションに TRANSACTION_TAG
を割り当てると、ロックの統計情報テーブルに値が入力されることがわかります。トランザクション タグが割り当てられていない場合は、空の文字列として表示されます。
API メソッドとリクエスト / トランザクション タグのマッピング
リクエストタグとトランザクション タグは、トランザクション モードが読み取り専用トランザクションか読み取り / 書き込みトランザクションかに応じて、特定の API メソッドに適用されます。通常、トランザクション タグは読み取り / 書き込みトランザクションに適用され、リクエストタグは読み取り専用トランザクションに適用されます。次の表では、API メソッドから該当するタグの種類へのマッピングを示します。
API メソッド | トランザクション モード | リクエストタグ | トランザクション タグ |
---|---|---|---|
Read、 StreamingRead |
読み取り専用トランザクション | ○ | × |
読み取り / 書き込みトランザクション | ○ | ○ | |
ExecuteSql、 ExecuteStreamingSql1 |
読み取り専用トランザクション1 | ○1 | × |
読み取り / 書き込みトランザクション | ○ | ○ | |
ExecuteBatchDml | 読み取り / 書き込みトランザクション | ○ | ○ |
BeginTransaction | 読み取り / 書き込みトランザクション | × | ○ |
commit | 読み取り / 書き込みトランザクション | × | ○ |
1 Apache Beam SpannerIO Dataflow コネクタを使用して実行される変更ストリーム クエリの場合、REQUEST_TAG
には Dataflow ジョブ名が含まれます。
制限事項
読み取り、クエリ、トランザクションにタグを追加する際は、次の制限事項を考慮してください。
- タグ文字列の長さは、50 文字までに制限されています。この上限を超える文字列は、切り捨てられます。
- タグに使用できる文字は、ASCII 文字(32~126)のみです。任意の Unicode 文字は、アンダースコアに置き換えられます。
- 先頭のアンダースコア(_)は、文字列から削除されます。
- タグでは、大文字と小文字が区別されます。たとえば、あるクエリセットにリクエストタグ
APP=cart,ENV=dev
を追加し、別のクエリセットにapp=cart,env=dev
を追加すると、Spanner では、統計情報がタグごとに分けて集計されます。 次のような状況では、統計情報テーブルにタグがない可能性があります。
- 期間中に実行されたすべてのタグ付きオペレーションの統計情報を Spanner がテーブルに保存できない場合は、指定された期間で最もリソース消費量の多いオペレーションが優先されます。
タグの命名
データベース オペレーションにタグを割り当てる場合は、各タグ文字列で伝えたい情報を検討することが重要です。選択した規則やパターンによって、タグの効果が高まります。たとえば、タグ適切な名前付けを行うと、統計情報とアプリケーション コードの関連付けがより簡単になります。
タグは、前述の制限事項の範囲内で自由に選択できます。とはいえ、タグ文字列は、カンマで区切られた Key-Value ペアのセットとして構成することをおすすめします。
たとえば、Spanner データベースを e コマースのユースケースで使用しているとします。特定のクエリに割り当てるリクエストタグに、アプリケーション、開発環境、クエリによるアクションに関する情報を含めたい場合があります。この場合、Key-Value 形式のタグ文字列を app=cart,env=dev,action=update
として割り当てることを検討してください。つまり、クエリは開発環境内のカート アプリケーションから呼び出され、カートの更新に使用されます。
カタログ検索アプリケーションからの別のクエリがあり、タグ文字列を app=catalogsearch,env=dev,action=list
として割り当てる場合を考えます。ここで、これらのクエリのいずれかがクエリ統計テーブルに高レイテンシ クエリとして現れる場合は、タグを使用してその原因を簡単に特定できます。
以下の例では、タグ付けパターンが、運用統計の整理にどのように使用されるかを示します。この例は網羅的なものではありません。タグ文字列内で、カンマなどの区切り文字を使用してそれらを組み合わせることもできます。
タグキー | タグと値のペアの例 | 説明 |
---|---|---|
アプリケーション | app=cart app=frontend app=catalogsearch |
オペレーションを呼び出しているアプリケーションの特定に役立ちます。 |
環境 | env=prod env=dev env=test env=staging |
オペレーションに関連付けられている環境を特定する際に有用です。 |
フレームワーク | framework=spring framework=django framework=jetty |
オペレーションに関連付けられているフレームワークの特定に役立ちます。 |
アクション | action=list action=retrieve action=update |
ユーザーが行った操作を特定する際に有用です。 |
サービス | service=payment service=shipping |
オペレーションを呼び出すマイクロサービスの特定に役立ちます。 |
留意点
REQUEST_TAG
を割り当てると、同じタグ文字列を持つ複数のクエリの統計情報が、クエリ統計情報テーブルの単一の行にグループ化されます。TEXT
フィールドには、これらのクエリのいずれかのテキストのみが現れます。REQUEST_TAG
を割り当てると、同じタグ文字列を持つ複数の読み取りの統計情報が、読み取り統計情報テーブルの 1 行にグループ化されます。読み取られた一連の列は、すべてREAD_COLUMNS
フィールドに追加されます。TRANSACTION_TAG
を割り当てると、同じタグ文字列を持つトランザクションの統計情報が、トランザクション統計情報テーブルの 1 行にグループ化されます。トランザクションによって書き込まれた一連のすべての列はWRITE_CONSTRUCTIVE_COLUMNS
フィールドに追加され、読み取られた一連のすべての列はREAD_COLUMNS
フィールドに追加されます。
タグを使用したトラブルシューティングのシナリオ
問題のあるトランザクションの原因を見つける
次のクエリにより、選択した期間における上位トランザクションの元データが返されます。
SELECT
fprint,
transaction_tag,
ROUND(avg_total_latency_seconds,4) as avg_total_latency_sec,
ROUND(avg_commit_latency_seconds,4) as avg_commit_latency_sec,
commit_attempt_count,
commit_abort_count
FROM SPANNER_SYS.TXN_STATS_TOP_10MINUTE
WHERE interval_end = "2020-05-17T18:40:00"
ORDER BY avg_total_latency_seconds DESC;
次の表に、アプリケーション自身へのクエリ、または同じデータベースに対するクエリの実行によって返されたサンプルデータを示します。ここで、アプリケーションは、3 つ(cart、product、frontend)あります。
レイテンシが大きなトランザクションを特定したら、関連するタグを使用して、アプリケーション コードの関連部分を特定し、トランザクションの統計情報を使用してさらにトラブルシューティングを行います。
fprint | transaction_tag | avg_total_latency_sec | avg_commit_latency_sec | commit_attempt_count | commit_abort_count |
---|---|---|---|---|---|
7129109266372596045 | app=cart,service=order | 0.3508 | 0.0139 | 278802 | 142205 |
9353100217060788102 | app=cart,service=redis | 0.1633 | 0.0142 | 129012 | 27177 |
9353100217060788102 | app=product,service=payment | 0.1423 | 0.0133 | 5357 | 636 |
898069986622520747 | app=product,service=shipping | 0.0159 | 0.0118 | 4269 | 1 |
9521689070912159706 | app=frontend,service=ads | 0.0093 | 0.0045 | 164 | 0 |
11079878968512225881 | [empty string] | 0.031 | 0.015 | 14 | 0 |
同様に、Request Tag は、クエリ統計分析テーブルから問題のあるクエリの原因を見つけるためや、読み取り統計情報テーブルから問題のある読み取りの原因を見つけるために使用できます。
特定のアプリケーションやマイクロサービスからのトランザクションのレイテンシや他の統計情報を確認する
タグ文字列でアプリケーション名やマイクロサービス名を使用している場合は、そのアプリケーション名やマイクロサービス名を含むタグでトランザクション統計情報テーブルをフィルタリングするのに役立ちます。
支払いアプリに新しいトランザクションを追加して、それらの新しいトランザクションのレイテンシや他の統計情報を確認したいとします。タグ内で支払いアプリケーションの名前を使用した場合は、app=payment
を含むタグに対してのみトランザクション統計情報テーブルをフィルタリングできます。
次のクエリでは、10 分間隔の支払いアプリのトランザクションの統計情報を返します。
SELECT
transaction_tag,
avg_total_latency_sec,
avg_commit_latency_sec,
commit_attempt_count,
commit_abort_count
FROM SPANNER_SYS.TXN_STATS_TOP_10MINUTE
WHERE STARTS_WITH(transaction_tag, "app=payment")
LIMIT 3;
出力例を次に示します。
transaction_tag | avg_total_latency_sec | avg_commit_latency_sec | commit_attempt_count | commit_abort_count |
---|---|---|---|---|
app=payment,action=update | 0.3508 | 0.0139 | 278802 | 142205 |
app=payment,action=transfer | 0.1633 | 0.0142 | 129012 | 27177 |
app=payment, action=retrieve | 0.1423 | 0.0133 | 5357 | 636 |
同様に、リクエストタグを使用して、クエリ統計情報テーブルや読み取り統計情報テーブルで特定のアプリケーションからのクエリや読み取りを見つけられます。
ロックの競合に関係するトランザクションの検出
ロックの待機時間が長いトランザクションと行キーを探し出すには、ロックの競合に関連する行キー、列、対応するトランザクションが列挙された LOCK_STAT_TOP_10MINUTE
テーブルをクエリします。
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_10minute t, spanner_sys.lock_stats_top_10minute s
WHERE
t.interval_end = "2020-05-17T18:40:00" and s.interval_end = t.interval_end;
クエリからの出力例を次に示します。
row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
---|---|---|---|---|
Singers(32) | 2.37 | 1.76 | 1 | LOCK_MODE: WriterShared COLUMN: Singers.SingerInfo TRANSACTION_TAG: app=cart,service=order LOCK_MODE: ReaderShared COLUMN: Singers.SingerInfo TRANSACTION_TAG: app=cart,service=redis |
このテーブルの結果から、Singers
テーブルのキー SingerId=32 で競合が発生していることがわかります。Singers.SingerInfo
は、ReaderShared
と WriterShared
の間でロックの競合が発生した列です。対応するトランザクションで、競合が発生しているもの(app=cart,service=order
と app=cart,service=redis
)を特定することもできます。
ロックの競合を引き起こしているトランザクションを特定したら、トランザクションの統計情報を使用して、これらのトランザクションに絞ってトランザクションのより詳細な動作と、競合を回避可能か、ロックが保持される時間を短くできるかを把握します。詳細については、ロック競合を減らすためのベスト プラクティスをご覧ください。
次のステップ
- 別のイントロスペクション ツールについて学習します。
- Spanner が各データベースについて、データベースの情報スキーマ テーブルに保存するその他の情報について学習します。
- Spanner に関する SQL のベスト プラクティスについて学習します。
- 高 CPU 使用率の調査について学習します。