※このブログは2024年2月7日に公開された英語ブログ「Enhancing Database Stability in TiDB with Runaway Query Management 」の拙訳です。
データベースの安定性を維持することは、どのようなビジネスにとっても最重要です。重要なシステムで予期せぬパフォーマンスの低下が発生すると、大きな損失が発生する可能性があるからです。変更テスト・プロセスを合理化したり、新しいテクノロジーを採用したりすることで、予期せぬインシデントを一定の範囲内に抑えることができます。しかし、急激なデータ量の変化、複雑化するクエリ、部分的に検証されたSQLなど、突発的なSQLパフォーマンスの問題は、依然として不意打ちを食らうことがあります。
このようなインシデントは、レイテンシーに敏感なアプリケーションにとって深刻な結果をもたらす可能性があり、それを軽減することは困難です。その解決策として、TiDB 7.2では、予期しないクエリを管理し、これらの問題に体系的に対処するためのランナウェイクエリ管理機能を導入しました。
ランナウェイクエリとは?
ランナウェイクエリとは、予想される実行時間やリソース使用量を超えるクエリのことです。ランナウェイクエリの管理は、効率的で制御可能な自動リソース管理メカニズムを提供します。予期せぬSQLパフォーマンス問題の悪影響を軽減することで、複雑なワークロードシナリオにおけるTiDBの安定性を向上させます。
ランナウェイクエリ管理の使用例とは?
ランナウェイクエリ管理は次のような状況で有効です:
- 重要なシステムのサービス品質を維持するために、SQLパフォーマンスの異常な問題を自動的に特定し、対処することが不可欠です。
- 突然SQLのパフォーマンス問題が発生し、即座に効果的な修正ができない場合があります。
- セキュリティやパフォーマンスに問題があることが分かっている特定のSQLを禁止リストに入れたり、レートリミットを設定する必要があります。
ランナウェイクエリの仕組みは?
Runaway query managementの本質的な機能は、クエリの特定と処理の2つです。
ランナウェイクエリ特定
TiDBのリソース制御モジュールには、2つの識別方法があります:動的識別と静的識別です。
動的識別
動的識別は、リソース・グループで定義されたリアルタイムのパフォーマンス・メトリクスに基づいて、ランナウェイクエリを自動的に識別します。現在この方法はEXEC_ELAPSED設定を使用してSQLコマンドの実際の実行時間を決定します。EXEC_ELAPSEDで指定された制限時間より長い時間がかかる問い合わせは、ランナウェイクエリとして識別されます。
以下のSQLコマンドでは、実行に5秒以上かかる 「default 」リソース・グループのクエリは、ランナウェイクエリとしてマークされます。
ALTER RESOURCE GROUP default
QUERY_LIMIT=(EXEC_ELAPSED='5s', ACTION=KILL);
識別されたランナウェイクエリがあると、リソースグループ内のWATCHルールを構成して、指定された時間枠内で識別されたクエリのSQL特性を監視することができます。このアプローチにより、SQLの特徴に基づいてランナウェイクエリを直接認識することができ、ルールベースの識別を待つ必要がなくなります。
以下の例では、10分以内に識別されたランナウェイクエリと類似した特徴を持つクエリを監視するWATCHルールを追加しています。したがって、次の10分間は、システムは5秒ルールを実行することなく、ランナウェイクエリを直接識別します。指定された時間の後、クエリのパフォーマンスが正常になれば、監視ルールは失効します。
ALTER RESOURCE GROUP default
QUERY_LIMIT=(EXEC_ELAPSED='5s', ACTION=KILL, WATCH=SIMILAR DURATION='10m');
静的識別
自動化されたルールでは、すべての問題のあるクエリに正確にフラグを立てることができないため、私たちは、明確なSQLの特徴によってクエリを認識する手動アプローチ(静的識別)を導入しました。管理者は QUERY WATCH コマンドを使用して、特定の SQL 特性を識別して処理するルールを定義することができます。これにより、基本的にデータベースクエリの禁止リストが作成されます。静的識別方法には以下のものがあります:SQL Text:これは、SQLテキストそのものに基づく完全一致を意味します。
SQL Digest:このメソッドは、同じSQLダイジェストを持つクエリをマッチさせ、構造は似ているがわずかな違いがあるクエリを識別します。例えばselect c from t1 where a=1 と select c from t1 where a=2 は同じダイジェスト値です。
Plan Digest:このメソッドは、同じ実行プランを共有するクエリをマッチングし、パフォーマンス問題の背後にありがちな特定のプランをターゲットにします。
スロークエリログによってSQLの特徴を収集することができます。例えば:
SELECT count(1)
FROM sbtest.sbtest1 AS S
,sbtest.sbtest2 AS S2
,sbtest.sbtest3 AS S3 WHERE S1.c=S2.c AND S1.c=S3.c;
# Time: 2023-09-19T17:16:56.640436+08:00
...
# Digest: d3c7846bb8f6b817ae395db30eadedec57af08f7983466f68db93d9ce1ac5872
...
# Plan_digest: 41fee801f07e06aa4aba4c0142ce4c624e8dc932c9e14d49854b8ce57366b443
あなたの経験に基づいて、識別方法の一つを選択することができます。以下の例では、SQL DIGESTを使用して、同様のクエリをモニタリングキューに追加しています。
mysql> QUERY WATCH ADD ACTION KILL SQL DIGEST 'd3c7846bb8f6b817ae395db30eadedec57af08f7983466f68db93d9ce1ac5872';
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.RUNAWAY_WATCHES ORDER BY id\G
*************************** 1. row ***************************
ID: 54
RESOURCE_GROUP_NAME: default
START_TIME: 2023-09-20 01:59:14
END_TIME: UNLIMITED
WATCH: Similar
WATCH_TEXT: d3c7846bb8f6b817ae395db30eadedec57af08f7983466f68db93d9ce1ac5872
SOURCE: manual
ACTION: Kill
1 row in set (0.04 sec)
Runaway Queriの処理
ハンドリングとは、特定されたランナウェイクエリを管理する方法のことです。サポートされている方法は以下のと通りです。
DRYRUN:何もせずに問題を特定し、その結果をログやビューに表示します。誤検知を検出するための初期テストに有用です。
COOLDOWN:リソースグループ内で特定されたクエリの優先度を下げ、処理を遅くします。
KILL:データベースのパフォーマンスを保護するために、特定されたクエリを終了します。
TiDB 7.5では、複雑な状況でのCOOLDOWNには制限があります。高いサービス品質を維持するためにKILLを使用することをお勧めします。以下のサンプルシナリオでは、ランナウェイクエリは検出されると自動的に終了されます。
ALTER RESOURCE GROUP default QUERY_LIMIT=(EXEC_ELAPSED='5s', ACTION=KILL, WATCH=SIMILAR DURATION='10m');
LoggingとObservability
TiDBは、問題の特定と管理に関連するすべての既述の設定と履歴データを記録し、アクセスするための一連のシステムテーブルを提供します:
・INFORMATION_SCHEMA.RESOURCE_GROUPS: このテーブルには、ランナウェイクエリ識別ルールとそれに対応する処理設定を含む、リソース・グループの定義の概要を示します。
・INFORMATION_SCHEMA.RUNAWAY_WATCHES:このテーブルは、モニタリング・キューに確立されたルールを一覧表示します。
・MYSQL.TIDB_RUNAWAY_QUERIES:のテーブルは、検出され、対処されたランナウェイクエリの過去のインスタンスのログを保持します。
実行中のランナウェイクエリ管理
ランナウェイクエリ管理がどのように機能するか、以下のシミュレーションで見てみましょう:
フェーズ | ワークロード | リソースグループの設定 | QPS | P99 |
1 | 通常 | なし | 11K | 50ms |
2 | 通常 + 継続的に負荷の高いクエリが実行 | なし | 3K | 200ms |
3 | 通常 + 継続的に負荷の高いクエリが実行 | QUERY_LIMIT=(EXEC_ELAPSED=’1s’, ACTION=KILL) | 7.5K | 70ms ~ 80ms |
4 | 通常 + 継続的に負荷の高いクエリが実行 | QUERY_LIMIT=(EXEC_ELAPSED=’1s’, ACTION=KILL, WATCH=EXACT DURATION=’5m’) | 11K | 50ms |
以下は、各フェーズでの実行結果です:
- 初期状態として、フェーズ1は通常の負荷シナリオで開始しました。全体のQPSはほぼ11kで、P999のレイテンシは約50msです。
- フェーズ2で異常なクエリを1秒に1回、3~8秒間投入したところ、QPSは11kから約3kに激減し、P999レイテンシは60msから200msに増加しました。
- この問題に対処するため、デフォルトのリソースグループにランナウェイクエリ識別ルールを実装し、実行時間が1秒を超えるクエリを終了させました。この調整により、QPSは7.5kに改善し、P999レイテンシは減少する結果となりました。
mysql> alter resource group default QUERY_LIMIT=(EXEC_ELAPSED='1s', ACTION=KILL);状況を観察するには、MYSQL.TIDB_RUNAWAY_QUERIESシステム・テーブルに問い合わせることができます。以下に示すように、ランナウェイクエリ管理システムは、積極的かつ一貫して問題のあるSQLクエリを特定し、処理するようになりました。
mysql> select * from mysql.tidb_runaway_queries limit 1 \G
*************************** 1. row ***********************
resource_group_name: default
time: 2023-09-19 15:18:10
match_type: identify
action: kill
original_sql: SELECT count(1)
FROM sbtest.sbtest1 AS S1
,sbtest.sbtest2 AS S2
,sbtest.sbtest3 AS S3
WHERE S1.c=S2.c
AND S1.c=S3.c
plan_digest: 41fee801f07e06aa4aba4c0142ce4c624e8dc932c9e14d49854b8ce57366b443
tidb_server: 127.0.0.1:4000
mysql> select count(*) from mysql.tidb_runaway_queries;
+----------+
| count(*) |
+----------+
| 56 |
+----------+
1 row in set (0.02 sec)しかし、QPSは元の状態に回復していませんでした。なぜなら、1秒以上のクエリが終了しても、その時間システムを占有していたためです。
- フェーズ4では、リソース・グループにウォッチ・ルールを追加し、ランナウェイ条件に一致するクエリのテキストを5分間監視リストに含めるようにしました。その結果、ランナウェイ条件に一致するクエリは即座に終了し、1秒間の待ち時間がなくなりました。TiDBは5分後にクエリのパフォーマンスを再評価し、パフォーマンスが回復すれば制限を解除します。この時、システムのQPSとP999は初期段階のレベルに戻ります。
WATCHルールを取得するには、次のクエリを実行してINFORMATION_SCHEMA.RUNAWAY_WATCHES テーブルの情報を取得します:mysql> alter resource group default QUERY_LIMIT=(EXEC_ELAPSED='1s', ACTION=KILL, WATCH=EXACT DURATION='5m');
mysql> SELECT * FROM INFORMATION_SCHEMA.RUNAWAY_WATCHES ORDER BY id\G
***************** 1. row ****************
ID: 50
RESOURCE_GROUP_NAME: default
START_TIME: 2023-09-19 16:58:20
END_TIME: 2023-09-19 17:03:20
WATCH: Exact
WATCH_TEXT: SELECT count(1)
FROM sbtest.sbtest1 AS S1
,sbtest.sbtest2 AS S2
,sbtest.sbtest3 AS S3
WHERE S1.c=S2.c
AND S1.c=S3.c
SOURCE: 127.0.0.1:4000
ACTION: Kill
1 row in set (0.01 sec)
ここまでで、ランナウェイクエリ管理によって個々のSQLクエリのリソース消費を制限し、全体的なパフォーマンスへの影響を軽減する方法について基本的な理解ができたはずです。
注意:上記のデモでは、リソース・グループがクエリを自動的に検出しなくても、スロークエリログやシステム・テーブルを使用して問題のあるクエリを特定することで、パフォーマンスの問題に対処することができます。これらのクエリは、QUERY WATCHを使用して手動で監視リストに追加し、効果的に禁止リストを作成することができます。
結論
TiDBのランナウェイクエリ管理機能の主な利点は、ユーザーエクスペリエンスの向上にあります。ユーザはデータベース内のランナウェイクエリを自動・手動アプローチによって容易に監視・管理することができ、通常のビジネスオペレーションへの干渉を最小限に抑えることができます。
今後は、より洗練された識別ルール、多様な処理戦略、観測可能性の強化など、この機能をさらに進化させていく予定です。さらに、グラフィカルな管理機能を導入してユーザーエクスペリエンスをさらに向上させ、TiDBをトップクラスのエンタープライズデータベースプラットフォームとして進化させていく予定です。
ランナウェイクエリ管理は、最新の製品版リリースであるTiDB 7.5をダウンロードしてお試しください。また、TiDB Slackコミュニティでは、他のTiDBのユーザーとの交流や、エンジニアリングチームとのリアルタイムなディスカッションをお楽しみいただけます。
TiDB Cloud Dedicated
TiDB Cloudのエンタープライズ版。
専用VPC上に構築された専有DBaaSでAWSとGoogle Cloudで利用可能。
TiDB Cloud Serverless
TiDB Cloudのライト版。
TiDBの機能をフルマネージド環境で使用でき無料かつお客様の裁量で利用開始。