當您的資料庫遇到高並發挑戰或特定SQL語句資源消耗過高時,雲資料庫RDS PostgreSQL為您提供了SQL限流功能。該功能可以有效防止特定SQL語句導致的資源過度消耗,確保您的資料庫系統穩定運行,更好地服務業務需求。
背景
SQL限流是一種重要的資料庫管理技術,可以通過限制並發SQL數,從而避免過高的資料庫負載,保證資料庫的穩定性和可靠性,提高資料庫的效能和效率,從而更好地支援業務需求。
應用情境
SQL限流的應用情境不僅限於高並發訪問,還包括以下幾個方面:
防止惡意攻擊
通過限制某類SQL的並發數,防止惡意攻擊或者DoS攻擊,保護資料庫的安全性。
控制資源使用
通過限制某類SQL的並發數,控制資料庫資源的使用量,避免資源耗盡導致資料庫崩潰或者效能下降。
例如在Database Backup、恢複、監控等SQL操作時,為了避免其對資料庫效能的影響,可以使用SQL限流量控制相關操作的速度。
前提條件
使用限制
無
影響
如果SQL限流配置不合理,可能影響業務,請在使用時根據業務負載進行配置。
例如,在某商城促銷業務情境下,由於訪問激增造成資料庫壓力較大,可使用此功能限制某類查詢SQL的並發數,從而減輕資料庫壓力。但如果限流設定過小,也可能影響相關業務。
注意事項
如果在執行個體重啟、主備切換等情境,SQL限流規則不會自動載入,需要手動重新載入。具體操作,請參見載入SQL限流規則。
費用
該外掛程式免費。
建立和刪除外掛程式
請使用高許可權帳號執行如下命令。
建立外掛程式
CREATE EXTENSION rds_ccl;
刪除外掛程式
DROP EXTENSION rds_ccl;
使用樣本
請使用高許可權帳號執行如下命令。
建立SQL限流規則
使用情境
該函數只能在主執行個體中調用,用於建立一個SQL限流規則。
文法
文法一:根據設定的SQL語句進行限流。
SELECT rds_add_ccl_rule(
query_string varchar,
node_tag int,
max_concurrency int,
max_waiting int,
is_enabled boolean,
comment varchar, -- 可選
search_path varchar -- 可選
);
文法二:根據設定的query_id進行限流。
SELECT rds_add_ccl_rule_with_query_id(
query_id bigint,
node_tag int,
max_concurrency int,
max_waiting int,
is_enabled boolean,
query_string varchar, -- 可選
comment varchar -- 可選
);
參數解釋
參數 | 類型 | 說明 |
query_string | varchar | 需要限流的SQL語句。 配置時,使用 例如:
該函數根據query_string取值計算query_id,再根據query_id匹配同類SQL進行限流。query_id的更多資訊,請參見query_id簡介。 |
query_id | bigint | 需要限流的SQL語句的query_id,更多資訊,請參見query_id簡介。 |
node_tag | int | 限流的節點。
說明 建立SQL限流規則函數中,此參數僅表示規則可應用的範圍,不會自動在唯讀執行個體中生效,您如果想要此規則在唯讀執行個體中發揮SQL限流作用,需要手動載入,具體操作,請參見載入SQL限流規則。 |
max_concurrency | int | 限制此類SQL的最大並發數。 取值範圍:0~100000 |
max_waiting | int | 限制此類SQL的最大等待數,超過設定上限時,新的SQL會導致PostgreSQL核心觸發ABORT,終止並復原事務。 取值範圍:0~100000 |
is_enabled | boolean | 該規則是否生效。
|
comment | varchar | 規則描述。 |
search_path | varchar | 目標限流SQL運行時的模式搜尋路徑(search_path),如果配置為空白字串( |
注意事項
在文法一中,comment和search_path如果不配置,可以填寫為空白字串(
''
),如果配置為NULL
,則函數不會進行任何操作而直接返回。在文法二中:
query_string和comment如果不配置,可以填寫為空白字串(
''
),如果配置為NULL
,則函數不會進行任何操作而直接返回。如果同時配置了query_id和query_string,AliPG核心將以query_id為準進行SQL限流。
該函數會返回ccl_id,ccl_id是當前資料庫下限流規則的唯一標識。
SQL樣本
在主執行個體的ccl_test資料庫中,有資料表ccl_tbl,建立SQL限流規則:
對所有的
SELECT * FROM ccl_tbl
語句(假設其query_id=1
)進行限流。最多允許3條此類SQL並發執行。
最多允許2個此類SQL等待。
規則建立成功後立即生效。
文法一:
SELECT rds_add_ccl_rule( $$SELECT * FROM ccl_tbl;$$, -- 待限流的SQL語句,使用$$包裹 1, -- 僅限制主執行個體 3, -- 最多允許3條此類SQL並發執行 2, -- 最多允許2個此類SQL等待 true, -- 規則立即生效 'limit constant select', -- 規則描述 '' -- 使用預設的search_path );
文法二:
SELECT rds_add_ccl_rule_with_query_id( 1, -- 待限流的SQL語句的query_id 1, -- 僅限制主執行個體 3, -- 最多允許3條此類SQL並發執行 2, -- 最多允許2個此類SQL等待 true, -- 規則立即生效 '' -- SQL語句的文本,本樣本不填寫 'limit constant select', -- 規則描述 );
查詢SQL限流規則
使用情境
該命令可以在主執行個體或唯讀執行個體中使用,用於查詢已建立的SQL限流規則。
文法
查看當前執行個體中所有庫下的SQL限流規則:
SELECT * FROM rds_enabled_ccl_rule;
說明此命令查詢結果中,由於顯示限制,query_string和comment的資訊會被截斷,只顯示前200個字元,如果需要查看完整資訊,請使用
SELECT * FROM rds_show_current_db_ccl_rule();
命令。查詢當前資料庫下的所有SQL限流規則:
SELECT * FROM rds_show_current_db_ccl_rule();
使SQL限流規則生效
使用情境
該函數只能在主執行個體中調用,適用於以下情境:
如果建立SQL限流規則時,is_enabled參數配置為false,則可以使用此函數使規則生效。
使失效的規則再次生效。
文法
SELECT rds_enable_ccl_rule(ccl_id int);
參數解釋
參數 | 類型 | 說明 |
ccl_id | int | SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則。 |
注意事項
無
SQL樣本
SELECT rds_enable_ccl_rule(1);
載入SQL限流規則
使用情境
該函數可以在主執行個體或唯讀執行個體中調用,用於載入SQL限流規則,只有被載入的規則才會發揮SQL限流作用。
適用於以下情境:
主執行個體:
建立SQL限流規則時,如果is_enabled配置為true,則規則會自動載入到主執行個體,無需手動調用。
建立SQL限流規則時,如果is_enabled配置為false,調用
rds_enable_ccl_rule
函數使規則生效時,規則會自動載入到主執行個體,無需手動調用。如果主執行個體重啟,則需要手動調用此函數,載入規則。
唯讀執行個體:
如果需要規則在唯讀執行個體發揮作用,則需要在主執行個體建立規則(node_tag配置為2或3)後,再在唯讀執行個體中調用此函數,手動載入規則。
文法
SELECT rds_load_ccl_rule(ccl_id int);
參數解釋
參數 | 類型 | 說明 |
ccl_id | int | SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則。 |
注意事項
只有在主執行個體中調用
rds_add_ccl_rule
函數建立了SQL限流規則,且node_tag配置為2或3時,才能在唯讀執行個體中載入規則。失效的規則無法被載入,如果唯讀執行個體需要載入某條失效的規則,請先在主執行個體中使其生效,具體方法,請參見使SQL限流規則生效。
SQL樣本
SELECT rds_enable_ccl_rule(1);
變更SQL限流規則
使用情境
該函數只能在主執行個體中調用,用於變更SQL限流規則中的最大並發數和最大等待數。
文法
SELECT rds_update_ccl_rule(
ccl_id int,
new_max_concurrency int,
new_max_waiting int
);
參數解釋
參數 | 類型 | 說明 |
ccl_id | int | SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則。 |
new_max_concurrency | int | 變更後最大並發數。
|
new_max_waiting | int | 變更後最大等待數。
|
注意事項
更新SQL限流規則後,規則立即生效。
當前僅支援變更SQL限流規則中的最大並發數和最大等待數。
SQL樣本
SELECT rds_update_ccl_rule(
2, -- ccl_id
4, -- 新的最大並發數為4
5 -- 新的最大等待數為5
);
使SQL限流規則失效
使用情境
該函數只能在主執行個體中調用,用於使某條SQL限流規則失效,該規則不再發揮SQL限流作用。
如果要使指定的規則生效,請參見使SQL限流規則生效。
文法
使指定SQL限流規則失效:
SELECT rds_disable_ccl_rule(ccl_id int);
使當前庫下的所有SQL限流規則失效:
SELECT rds_disable_all();
參數解釋
參數 | 類型 | 說明 |
ccl_id | int | SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則。 |
注意事項
失效的規則無法被載入,如果唯讀執行個體需要載入某條失效的規則,請先在主執行個體中使其生效,具體方法,請參見使SQL限流規則生效。
使SQL限流規則失效時,會自動將規則從主執行個體卸載,該規則不再發揮SQL限流作用。
SQL樣本
SELECT rds_disable_ccl_rule(1);
卸載SQL限流規則
使用情境
該函數可以在主執行個體或唯讀執行個體中調用,用於卸載SQL限流規則,被卸載的規則不會再發揮SQL限流作用。
適用於以下情境:
主執行個體:
如果在主執行個體中調用了
rds_disable_ccl_rule
或rds_disable_all
函數使規則失效,規則將自動從主執行個體卸載,無需手動調用。如果在主執行個體調用了
rds_del_ccl_rule
函數刪除規則,規則將自動從主執行個體卸載,無需手動調用。您也可以手動調用此函數,將規則從主執行個體卸載。
唯讀執行個體:
如果不希望某條規則在唯讀執行個體發揮限流作用,可以在唯讀執行個體中手動調用此函數。
文法
SELECT rds_unload_ccl_rule(ccl_id int, db_name varchar default '');
參數解釋
參數 | 類型 | 說明 |
ccl_id | int | SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則。 |
db_name | varchar | 預設為空白字串,表示當前資料庫。您也可以指定其他資料庫,將其他資料庫下的SQL限流規則卸載。 |
注意事項
規則卸載後,不再發揮SQL限流作用,如需再次使用,需要重新載入,更多資訊,請參見載入SQL限流規則。
SQL樣本
SELECT rds_unload_ccl_rule(1,'');
刪除SQL限流規則
使用情境
該函數只能在主執行個體中調用,用於刪除某條SQL限流規則。規則刪除時,自動從主執行個體卸載。
文法
SELECT rds_del_ccl_rule(ccl_id int);
參數解釋
參數 | 類型 | 說明 |
ccl_id | int | SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則。 |
注意事項
無。
SQL樣本
SELECT rds_del_ccl_rule(1);
返回結果:
rds_del_ccl_rule
----------------------
-7851264404688445170
(1 row)
返回結果為query_id。
如果規則不存在,則刪除報錯。
附錄
query_id簡介
query_id是PostgreSQL中SQL的特殊標識,同類SQL的query_id相同。
例如:
-- 以下兩個sql的query_id相同 SELECT * FROM tbl WHERE a = 1; SELECT * FROM tbl WHERE a = 2;
query_id包含有SQL中對象的資訊(即oid資訊),不同資料庫下的同名表不是同一個對象,不同schema下的同名表也不是同一個對象。所以相同的SQL,如果其包含的查詢對象不同,那麼query_id就不相同。
如果是SQL中的訪問對象的是全域表,或是全域函數,query_id相同。
樣本1:
pg_database
為全域表,在不同資料庫中查詢query_id相同。ccl_test資料庫中執行如下語句:
SELECT rds_get_query_id($$SELECT * FROM pg_database;$$);
返回結果:
rds_get_query_id ---------------------- -8733244708994363681 (1 row)
ccl_test2資料庫中執行如下語句:
SELECT rds_get_query_id($$SELECT * FROM pg_database;$$);
返回結果:
rds_get_query_id ---------------------- -8733244708994363681 (1 row)
樣本2:
pg_sleep
為全域函數,在不同資料庫中查詢query_id相同。ccl_test資料庫中執行如下語句:
SELECT rds_get_query_id($$SELECT pg_sleep(1);$$);
返回結果:
rds_get_query_id -------------------- 440101247839410938 (1 row)
ccl_test2資料庫中執行如下語句:
SELECT rds_get_query_id($$SELECT pg_sleep(1);$$);
返回結果:
rds_get_query_id -------------------- 440101247839410938 (1 row)
調用函數情境下,當參數類型變化或是有無FROM子句時,query_id會發生變化。
例如,同樣調用
pg_sleep
函數,不同情況下返回query_id
結果不同。無FROM子句:
SELECT rds_get_query_id($$SELECT pg_sleep(1);$$);
返回結果:
rds_get_query_id -------------------- 440101247839410938 (1 row)
有FROM子句:
SELECT rds_get_query_id($$SELECT * FROM pg_sleep(1);$$);
返回結果:
rds_get_query_id ---------------------- -3404018605099167039 (1 row)
參數類型變化:
select rds_get_query_id($$SELECT * FROM pg_sleep(1.0);$$);
返回結果:
rds_get_query_id --------------------- 3073869725037049158 (1 row)