在數字化系統扮演重要角色的今天,資料庫穩定性成為企業關注的核心問題。對於重要計算機系統而言,突發的效能下降可能對業務造成不可估量的損失。為了穩定資料庫效能,使用者可以從管理流程入手規範變更的測試,或者利用產品手段減少預期外的變化。然而,這仍舊無法完全規避突發的SQL效能問題,其中的原因包括但不僅限於:
- 資料量和資料分佈劇烈變化,從前被驗證過的執行計劃可能變得效率更低。
- 資料庫中的查詢變得越來越複雜,最佳化器對執行計劃的選擇存在不可控因素。
- 頻繁的業務更新給測試帶來巨大壓力,未經充分驗證的 SQL 有潛在的效能問題 。
對於一些對延遲非常敏感的應用而言,這些潛在問題有可能對業務造成不可估量的損失。 如何降低這類不可控的突發問題對業務的影響,是擺在每個管理者面前的難題。
做為資源管控的一部分,TiDB 在 7.2.0 引入 Runaway Queries 管理,並持續增強,旨在透過系統化的手段緩解上述難題。
本文將從從適用場景、實現原理等角度詳細介紹 TiDB 的 Runaway Queries 管理功能,並透過一個示例展示其在系統中的作用。
什麼是 Runaway Queries
Runaway Queries 是指執行時間或消耗資源超出預期的查詢,在執行時間和資源消耗上有顯著特徵。
Runaway Queries 管理旨在提供一種高效、可控、自動化的資源識別和管控機制,以降低突發 SQL 效能問題帶來的負面影響,保護複雜工作負載下系統的穩定性,讓 TiDB 更加可靠。
Runaway Queries 管理適用哪些場景
● 為了保障重要系統的服務質量,需要能夠自動識別並處理異常 SQL 效能問題。
● 當遇到突發 SQL 效能問題,但又沒有立即有效的修復手段時,希望臨時緩解其影響。
● 當已知個別 SQL 有安全或效能問題,希望加入黑名單或對其進行限流。
Runaway Queries 管理能做什麼
Runaway Queries 管理主要提供兩個重要能力,即對查詢的 “識別” 和 “處置” 。
3.1 查詢的識別
TiDB 資源管控模組提供 兩類 識別方式
● 動態識別 - 根據執行時規則識別 。指根據 SQL 實際執行指標自動識別 (透過 resource group 定義),目前支援利用 EXEC_ELAPSED 設定實際執行時間,即當查詢執行時間超過 EXEC_ELAPSED 的定義時,這個查詢會被識別為 Runaway Query。比如:
ALTER RESOURCE GROUP default QUERY_LIMIT=(EXEC_ELAPSED='5s', ACTION=KILL);
○ 上面命令執行的效果是, 屬於 default 資源組的查詢執行超過 5 秒鐘,那麼這個查詢會被識別為 Runaway Query。 (識別規則的生效範圍為“資源組”,如果你沒有建立任何資源組,那麼可以修改 default 資源組的規則將會對全域性有效。 )
○ TiDB 特意提供了每個資源組 Query Max Duration 的監控指標,能夠檢視一段時間內執行時間最長的查詢,這個指標能夠協助設定一個合理的 EXEC_ELAPSED .
Resource Group 的定義同時支援將識別到的 SQL 特徵同時加入監控列表特定一段時間,即一段時間內,資源管控直接識別 SQL 特徵而無需用規則識別。相當於將 SQL 放入監控名單,並階段性檢查是否它已經恢復健康。
ALTER RESOURCE GROUP default QUERY_LIMIT=(EXEC_ELAPSED='5s', ACTION=KILL, WATCH=SIMILAR DURATION='10m');
○ 上述例子裡,我們向配置里加入了 WATCH 規則, 那麼和被識別成 Runaway Query 查詢類似的查詢(比如只有過濾值不同),在接下來的 10 分鐘裡,會直接執行對應操作,而不會再等待 5 秒。10 分鐘之後,如果這個查詢的效能已經恢復,則不再對其進行限制;如果沒有恢復,則再次對這個查詢監控 10 分鐘。
● 靜態識別 - 根據 SQL 特徵識別 。自動篩選規則並不能精確的識別出所有有問題的查詢,因此我們加入了對監控列表的人工管理。透過 query watch 命令定義 SQL 特徵識別及處置規則, 能夠達到資料庫查詢黑名單的作用。目前已支援的 SQL 特徵的設定:
○ SQL Text : 根據 SQL 文字做精確匹配。
○ SQL Digest : 根據 SQL Digest 匹配模式相同的查詢。比如 select c from t1 where a=1 和 select c from t1 where a=2 擁有相同的 Digest。
○ Plan Digest : 根據 Plan Digest 匹配執行計劃相同的查詢。相同 SQL 可能存在多個執行計劃,造成效能問題的往往是其中少部分執行計劃。
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;
# 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)
3.2 查詢的處置
處置 , 指被識別到的 Runaway Queries 要如何處理。目前支援以下幾個處理方式。
● DRYRUN : 僅識別不做處理,在日誌和對應檢視中顯示。 初期配置的時候,可以利用 DRYRUN 試執行一段時間,檢測是否有誤判的風險。
● COOLDOWN : 將查詢置於資源組的最低優先順序,限制其處理速度。
● KILL : 終止被識別的查詢,防止其進一步影響資料庫效能。
○ 在 7.5.0 版本, COOLDOWN 在複雜場景下的限制作用有限,如果對服務質量要求比較高,則推薦設定 KILL
在這個例子裡,被識別為 Runaway Queries 的查詢會被自動取消。
ALTER RESOURCE GROUP default QUERY_LIMIT=(EXEC_ELAPSED='5s', ACTION=KILL, WATCH=SIMILAR DURATION='10m');
3.3 歷史記錄及觀測性
以上所有的設定,及識別和處置的歷史記錄,TiDB 提供了一組系統表用於查詢:
● INFORMATION_SCHEMA.RESOURCE_GROUPS : 資源組定義,包括對 Runaway Queries 識別規則和處置設定。
● INFORMATION_SCHEMA.RUNAWAY_WATCHES : 監控佇列中的規則。
● MYSQL.TIDB_RUNAWAY_QUERIES : 記錄被識別和處置的 Runaway Queries 歷史記錄。
執行示例
- 正常負載下, 整體 QPS 接近 11k , P999 在 50ms 上下。
- 出現一個異常查詢,每秒提交一次,執行時間在 3~8 秒, QPS 從 11K 急劇下降至 3K 左右,P999 由 60ms 增加到 200ms 。
- 這時我們嘗試向 default 資源組加入一條規則,自動殺掉執行時間超過 1 秒的查詢。QPS 回升至 7.5k , P999 下降。
mysql> alter resource group default QUERY_LIMIT=(EXEC_ELAPSED='1s', ACTION=KILL);
Query OK, 0 rows affected (1.02 sec)
mysql> SELECT * FROM information_schema.resource_groups;
+---------+------------+----------+-----------+--------------------------------+------------+
| NAME | RU_PER_SEC | PRIORITY | BURSTABLE | QUERY_LIMIT | BACKGROUND |
+---------+------------+----------+-----------+--------------------------------+------------+
| default | UNLIMITED | MEDIUM | YES | EXEC_ELAPSED='1s', ACTION=KILL | NULL |
+---------+------------+----------+-----------+--------------------------------+------------+
1 row in set (0.01 sec)
透過系統表 mysql.tidb_runaway_queries ,我們看到 Runaway 管理開始介入,有問題的 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 秒的查詢殺掉,但每個查詢仍舊都會執行 1 秒,對系統仍舊造成消耗 。
- 修改資源組規則,把符合 runaway 規則的查詢的文字,加入到監控列表中,時長為 5 分鐘。 這意味著,如果文字匹配到被標記為 runaway 的查詢,那麼會被直接殺掉,不再等待 1 秒;而每隔 5 分鐘,TiDB 會自動放開限制,檢查一下查詢的效能是否恢復。如果恢復,則不再對此查詢進行取消處理 。這時系統的 QPS 和 P999 恢復到階段 1 的水平。
mysql> alter resource group default QUERY_LIMIT=(EXEC_ELAPSED='1s', ACTION=KILL, WATCH=EXACT DURATION='5m');
Query OK, 0 rows affected (0.53 sec)
mysql> SELECT * FROM information_schema.resource_groups;
+---------+------------+----------+-----------+-------------------------------------------------------------+------------+
| NAME | RU_PER_SEC | PRIORITY | BURSTABLE | QUERY_LIMIT | BACKGROUND |
+---------+------------+----------+-----------+-------------------------------------------------------------+------------+
| default | UNLIMITED | MEDIUM | YES | EXEC_ELAPSED='1s', ACTION=KILL, WATCH=EXACT DURATION='5m0s' | NULL |
+---------+------------+----------+-----------+-------------------------------------------------------------+------------+
1 row in set (0.00 sec)
檢視檢視,有一條 watch 規則生成:
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)
有問題的查詢被執行時會直接退出,告知已經被監控隔離:
ERROR 8254 (HY000): Quarantined and interrupted because of being in runaway watch list
至此,我們看到, 透過對異常查詢的自動識別和監測,能夠有效限制個別 SQL 的資源消耗, 緩解其對整體效能的影響。
在上述示例中,即使沒有設定資源組對查詢的自動識別,在出現 SQL 效能問題時,我們仍可以透過“慢日誌”或者系統表找出問題查詢的“特徵”,用 QUERY WATCH 手工將查詢加入監視列表,達到設定黑名單的效果。
展望
TiDB Runaway Queries 管理的一個顯著優勢是提升了使用者體驗。透過自動化和手動管理的結合,使用者能夠更輕鬆地監控和控制資料庫中的 Runaway Queries,避免它們對正常業務的干擾。
未來, TiDB 會持續增強管理 Runaway Queries 的能力, 支援更多且複雜的識別規則, 增加更豐富的處理手段,全面提升可觀測性,透過引入圖形化管理的方式進一步提升使用者體驗 , 為 TiDB 邁向企業級資料庫平臺保駕護航。