全部產品
Search
文件中心

ApsaraDB RDS:SQL限流(rds_ccl)

更新時間:Jun 19, 2024

當您的資料庫遇到高並發挑戰或特定SQL語句資源消耗過高時,雲資料庫RDS PostgreSQL為您提供了SQL限流功能。該功能可以有效防止特定SQL語句導致的資源過度消耗,確保您的資料庫系統穩定運行,更好地服務業務需求。

背景

SQL限流是一種重要的資料庫管理技術,可以通過限制並發SQL數,從而避免過高的資料庫負載,保證資料庫的穩定性和可靠性,提高資料庫的效能和效率,從而更好地支援業務需求。

應用情境

SQL限流的應用情境不僅限於高並發訪問,還包括以下幾個方面:

  • 防止惡意攻擊

    通過限制某類SQL的並發數,防止惡意攻擊或者DoS攻擊,保護資料庫的安全性。

  • 控制資源使用

    通過限制某類SQL的並發數,控制資料庫資源的使用量,避免資源耗盡導致資料庫崩潰或者效能下降。

    例如在Database Backup、恢複、監控等SQL操作時,為了避免其對資料庫效能的影響,可以使用SQL限流量控制相關操作的速度。

前提條件

  • RDS PostgreSQL執行個體需滿足以下要求:

    • 執行個體大版本為PostgreSQL 14或以上。

    • 執行個體核心小版本為20230330或以上。

    說明

    如需升級核心小版本,請參見升級核心小版本

  • 使用此外掛程式前,需配置如下參數:

    • rds_enable_ccl取值為on

    • compute_query_id取值為autoon

    說明

    您可以前往控制台修改執行個體參數,更多資訊,請參見設定執行個體參數

使用限制

影響

如果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語句。

配置時,使用$$$<任一字元>$包裹限流SQL語句,更多資訊,請參見Dollar-Quoted String Constants

例如:

-- 使用$$包裹SQL語句
$$SELECT * FROM my_table;$$

-- SQL語句中已存在$$,使用$ccl$包裹SQL語句
$ccl$SELECT * FROM my_table WHERE my_column = $$hello$$;$ccl$

該函數根據query_string取值計算query_id,再根據query_id匹配同類SQL進行限流。query_id的更多資訊,請參見query_id簡介

query_id

bigint

需要限流的SQL語句的query_id,更多資訊,請參見query_id簡介

node_tag

int

限流的節點。

  • 1:僅限制主執行個體。

  • 2:僅限制唯讀執行個體。

  • 3:限制主執行個體和唯讀執行個體。

說明

建立SQL限流規則函數中,此參數僅表示規則可應用的範圍,不會自動在唯讀執行個體中生效,您如果想要此規則在唯讀執行個體中發揮SQL限流作用,需要手動載入,具體操作,請參見載入SQL限流規則

max_concurrency

int

限制此類SQL的最大並發數。

取值範圍:0~100000

max_waiting

int

限制此類SQL的最大等待數,超過設定上限時,新的SQL會導致PostgreSQL核心觸發ABORT,終止並復原事務。

取值範圍:0~100000

is_enabled

boolean

該規則是否生效。

  • true:立即生效

  • false:不生效

comment

varchar

規則描述。

search_path

varchar

目標限流SQL運行時的模式搜尋路徑(search_path),如果配置為空白字串(''),將使用預設search_path,您可以使用SHOW search_path;命令查詢。

注意事項

  • 在文法一中,commentsearch_path如果不配置,可以填寫為空白字串(''),如果配置為NULL,則函數不會進行任何操作而直接返回。

  • 在文法二中:

    • query_stringcomment如果不配置,可以填寫為空白字串(''),如果配置為NULL,則函數不會進行任何操作而直接返回。

    • 如果同時配置了query_idquery_string,AliPG核心將以query_id為準進行SQL限流。

  • 該函數會返回ccl_idccl_id是當前資料庫下限流規則的唯一標識。

SQL樣本

在主執行個體的ccl_test資料庫中,有資料表ccl_tbl,建立SQL限流規則:

  1. 對所有的SELECT * FROM ccl_tbl語句(假設其query_id=1)進行限流。

  2. 最多允許3條此類SQL並發執行。

  3. 最多允許2個此類SQL等待。

  4. 規則建立成功後立即生效。

  • 文法一:

    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_stringcomment的資訊會被截斷,只顯示前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配置為23)後,再在唯讀執行個體中調用此函數,手動載入規則。

文法

SELECT rds_load_ccl_rule(ccl_id int);

參數解釋

參數

類型

說明

ccl_id

int

SQL限流規則ID,如何查詢SQL限流規則ID,請參見查詢SQL限流規則

注意事項

  • 只有在主執行個體中調用rds_add_ccl_rule函數建立了SQL限流規則,且node_tag配置為23時,才能在唯讀執行個體中載入規則。

  • 失效的規則無法被載入,如果唯讀執行個體需要載入某條失效的規則,請先在主執行個體中使其生效,具體方法,請參見使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

變更後最大並發數。

  • 如果增加最大並發數,則等待中的SQL將立即執行。

  • 如果減少最大並發數,不會影響正在執行的SQL,直到當前並發數小於新的最大並發數後,等待中的SQL才會開始執行。

new_max_waiting

int

變更後最大等待數。

  • 如果增加最大等待數,則允許更多的限流SQL進入等待。

  • 如果減少最大等待數,不會影響正在等待中的SQL,但如果此時有新的SQL需要等待,且會使當前等待SQL數大於新的最大等待數時,將會導致PostgreSQL核心觸發ABORT,終止並復原事務。

注意事項

  • 更新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_rulerds_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)