全部產品
Search
文件中心

PolarDB:SQL限流

更新時間:Jun 24, 2025

PolarDB PostgreSQL版(相容Oracle)提供了SQL限流功能。SQL限流功能以串連地址為維度配置限流規則,避免異常流量的SQL語句造成業務影響。本文主要為您介紹SQL限流功能的使用方式。

簡介

SQL限流功能允許以串連地址為維度配置限流規則,通過SQL模板的方式匹配當前串連地址上執行的SQL並限制其最大並發數或QPS。可被用於以下情境:

  • PolarDB叢集上存在慢SQL導致資料庫負載較高,影響正常業務執行。

  • 希望對某一類風險SQL限制其可使用的資源,或完全拒絕其執行。

操作步驟

說明

如您需要開啟SQL限流功能,請聯絡我們處理。

  1. 登入PolarDB控制台,在左側導覽列單擊叢集列表,選擇叢集所在地區,並單擊目的地組群ID進入叢集詳情頁。

  2. 在左側導覽列單擊配置與管理 > 安全管理

  3. SQL限流頁簽,點擊新增,建立SQL限流規則。

    image

  4. 建立SQL限流規則彈窗內設定如下配置項後,單擊確定。

    類別

    參數

    說明

    基本資料

    規則名稱

    限流規則的名稱,需滿足如下要求:

    • 不能超過30個字元。

    • 必須由大小寫字母和數字組成。

    規則描述

    可選,用於備忘該限流規則的相關資訊,便於後續管理。不能超過64個字元。

    EndpointID

    選擇限流規則作用的串連地址。

    說明
    • 當前僅支援在叢集地址和按活躍請求數負載平衡的自訂地址(讀寫或唯讀均可)上配置限流規則,主地址以及按串連數負載平衡的唯讀地址暫時不支援SQL限流。

    • 不同地址上配置的限流規則互不影響,同一地址上配置的限流規則僅對使用該地址的Business Connectivity生效。

    規則配置

    規則類型

    選擇限流規則模式,支援活躍並發數限流串連級QPS限流

    說明

    按串連級QPS限流為限制單個串連的每秒請求次數,商務就緒側配置串連池或使用長串連的情境,短串連情境下建議使用活躍並發數限流。

    當前模式

    選擇SQL模板的匹配方式,支援模板匹配全文匹配,兩種匹配方式的區別請參見模板匹配與全文匹配

    資料庫帳號名

    配置限流規則作用的帳號,支援配置多個帳號,但不超過10個,帳號名稱之間使用英文逗號分隔。為空白時,預設對所有帳號生效。

    資料庫名

    配置限流規則作用的資料庫。支援配置多個資料庫,但不超過10個,資料庫名稱之間使用英文逗號分隔。為空白時,預設對所有資料庫生效。

    SQL模板

    配置SQL模板,詳細配置請參見SQL模板與匹配模式

    最長等待隊列長度

    配置最長等待隊列長度,取值範圍為0-1024。當命中的SQL並發度或QPS達到規則限制時將會進入延遲隊列進行重試,當延遲隊列中等待的SQL數量超過最長等待隊列長度時新的請求將會直接返回錯誤。合理配置最長等待隊列長度可避免大量SQL被限流時延遲隊列無限制增長導致資料庫代理記憶體耗盡(OOM)。

    最大活躍並發數

    設定最大活躍並發數。

    說明

    僅選擇活躍並發數限流規則類型時,需要配置該參數。

    每串連最大QPS

    設定每串連最大QPS。

    說明

    僅選擇串連級QPS限流規則類型時,需要配置該參數。

實現方式

SQL限流為資料庫代理側實現的功能,通過在資料庫代理上配置各種限流規則以控制轉寄的特定SQL的並發數或QPS,對資料庫叢集的讀寫或唯讀節點不會帶來額外影響,因此僅支援以叢集或自訂地址為維度進行配置。

SQL模板與匹配模式

模板匹配與全文匹配

SQL模板可以是任何符合PolarDB PostgreSQL版(相容Oracle)叢集標準文法的SQL,當配置SQL模板後根據配置的匹配模式不同,資料庫代理會對SQL模板進行不同的預先處理。

  • 假設配置了一條限流規則並配置了以下SQL模板:

    SELECT * FROM tbl WHERE id < 1;
    • 當選擇模板匹配時,會對SQL模板進行簡單正則化,去除多餘空格、注釋,並掃描SQL中的常量部分(單引號字串、數字等)替換為萬用字元,得到如下結果:

      -- 模板化結果
      SELECT * FROM tbl WHERE id < ?
    • 當選擇全文匹配時,也會對SQL模板進行簡單正則化,但不會替換其中的常量部分,結果如下所示:

      -- 僅格式化結果
      SELECT * FROM tbl WHERE id < 1

    之後資料庫代理會對產生的格式化SQL產生唯一標識用於後續匹配。

  • 當限流規則啟用後,對於每條經過的業務SQL,資料庫代理也會進行和SQL模板類似的預先處理。以以下業務SQL為例:

    SELECT * FROM tbl WHERE id < 100;

    同樣會產生兩種格式化的SQL並計算唯一標識,並嘗試與限流規則進行匹配:

    -- 模板化結果
    SELECT * FROM tbl WHERE id < ?
    
    -- 僅格式化結果
    SELECT * FROM tbl WHERE id < 100

啟用SQL限流規則後在轉寄當前SQL前,資料庫代理會遍曆當前配置的限流規則,當限流規則配置為模板匹配時會使用模板化結果與限流規則配置的SQL模板進行匹配,當限流規則配置為全文匹配時會使用僅格式化結果與限流規則配置的SQL模板匹配,匹配命中後會統計其並發度或QPS並執行對應的限流操作。

因此,對於上述的業務SQL和SQL模板,僅當配置為模板匹配時才會命中規則。

參數化支援

SQL模板中允許使用參數化寫法,與正常PostgreSQL參數綁定文法一致:

SELECT * FROM tbl WHERE id < $1 AND name = $2 LIMIT 1;

其中,參數化部分在模板匹配和全文匹配中均會被格式化為萬用字元:

-- 模板化結果
SELECT * FROM tbl WHERE id < ? AND name = ? limit ?

-- 僅格式化結果
SELECT * FROM tbl WHERE id < ? AND name = ? limit 1

因此對於以下業務SQL:

SELECT * FROM tbl WHERE id < $1 AND name = 2 LIMIT 100;

當前模式配置為模板匹配時可以命中上述規則,當前模式為全文匹配時無法命中上述規則。

說明

暫不支援在SQL模板中直接使用?寫法進行參數化:

-- 非法的SQL模板,不符合PostgreSQL標準文法,不會命中任何SQL
SELECT ?, ?, ?;

-- 合法的SQL模板
SELECT $1, $2, $3;

Prepared Statment

當業務使用Prepared statement時,Prepare語句本身不會觸發限流,只有Execute語句會觸發限流。對於Execute語句會對其對應的Prepare語句中的SQL部分進行對應的格式化或模板化並匹配規則。

說明

關於Prepared statement的詳細內容請參見PREPARE

樣本

使用以下SQL模板配置一條限流規則, 匹配模式選擇模板匹配:

SELECT * FROM tbl WHERE id < $1 AND name > $2;

對於以下業務SQL:

-- prepare語句不會觸發限流
PREPARE s1 AS SELECT * FROM tbl WHERE id < $1 AND name > 100;

-- execute語句會用其對應的prepare語句中的sql部分匹配限流規則
EXECUTE s1;

EXECUTE s1;

EXECUTE s1;

三條Execute將會命中限流規則並被限流。

同樣地,當在限流規則的SQL模板中使用Prepare語句時,也僅會對Prepare語句中的SQL部分進行必要的格式化或模板化用於後續限流,因此建立規則時使用以下兩條SQL模板完全等價:

-- 模板1
PREPARE s1 AS SELECT * FROM tbl WHERE id < $1 AND name > $2;

-- 模板2
SELECT * FROM tbl WHERE id < $1 AND name > $2;

擴充協議支援

與Prepare語句類似,當業務驅動使用擴充協議時,僅有Execute報文會觸發限流。對每個Execute報文會找到其對應的Parse報文並計算SQL模板匹配限流規則。因此SQL限流可以支援擴充協議,配置時通常無需額外關注業務使用的協議。

說明

關於擴充協議的詳細內容請參見社區文檔

使用限制

目前SQL限流功能存在以下受限的使用情境:

  • 多語句(Multi-Statement)暫不支援限流,使用多語句時將不會觸發任何配置的限流規則。

    多語句指在一條SQL文本中包含多個使用分號間隔的SQL語句,以下是一個使用JDBC驅動執行的多語句樣本:

    Statement statement = connection.createStatement();
    
    statement.execute("select 1; select 2; select 3");

    多語句可能同時命中多條限流規則,為避免非預期的結果暫不支援限流。

  • 部分特殊語句,如事務控制語句、預存程序等不支援限流。對如Commit類的事務控制語句限流會導致事務無法正常結束,因此不會命中限流規則。

  • 當用戶端或驅動使用批量執行(Statement Batching)模式時,批量執行的SQL僅會觸發第一條命中的限流規則。以下是一個使用JDBC驅動的批量執行的樣本:

    Statement statement = connection.createStatement();
    
    statement.addBatch("select 1");
    statement.addBatch("select 2");
    statement.addBatch("select 3");
    
    int[] result = statement.executeBatch();
    statement.close();
    connection.close();

    與多語句類似,使用Statement Batching時驅動通常會將多條SQL的擴充協議報文組合并一次性發送,同樣會形成類似多語句的同時命中多條限流規則的情況。此時僅會啟用命中的第一條限流規則。對於上述的批量執行樣本,當串連地址上同時配置以下三條SQL模板的限流規則時:

    -- 模板1
    SELECT 1;
    
    -- 模板2
    SELECT 2;
    
    --模板3
    SELECT 3;

    僅有模板1會命中。

  • SQL模板暫時不支援對關鍵字忽略大小寫,配置SQL模板時需要與期望限流的SQL文字大小寫一致。

  • SQL模板暫不支援對in/any等不定長運算式進行忽略元素個數的模板化。例如:

    -- SQL模板
    SELECT * FROM tbl WHERE id IN ($1, $2, $3);
    
    -- SQL1,可以命中模板
    SELECT * FROM tbl WHERE id IN (1, 6, 8);
    
    -- SQL2,無法命中模板
    SELECT * FROM tbl WHERE id IN (1, 6, 8, 8);
  • 當前不存在任何已配置的限流規則時,初次添加規則時無法對存量串連生效。在控制台存在任何已配置的限流規則時(無論是否啟用),後續的新增、修改、刪除操作均可即時對所有串連生效。

    說明
    • 當您的業務啟用長串連並期望任何時刻新增規則都可以立即生效時,建議在對應地址上配置一條任意的規則禁用後保留,後續增加或修改規則均可對新老串連生效。

    • 當資料庫代理版本為2.3.58及以上,新增、修改、刪除限流規則可即時對所有串連生效。您可在控制台查看資料庫代理Proxy的版本,如未滿足核心小版本要求,請升級資料庫代理版本

限流方式

目前SQL限流使用SQL模板加延遲隊列的技術實現QPS或活躍並發數限流。業務SQL必須命中限流規則後才會統計對應規則上的QPS或並發數。當並發數或QPS超過規則配置的限制時,資料庫代理會將該SQL放入延遲隊列中延遲一段時間後重試,從而鑑效組資料庫側的並發度/QPS不超過規則限制。

延遲隊列的延遲時間與規則配置的QPS/並發數成反比。同時命中某條規則的SQL在延遲隊列中等待的最大數量受規則中配置的最長等待隊列長度限制,超出限制時代理將不會轉寄該SQL,同時向用戶端返回以下錯誤:

SELECT 123;
Current query is being throttled and waiting queue is full.
說明

以上報錯不會中斷或改變當前串連的事務狀態,用戶端在收到該錯誤後依然可以選擇提交或復原該事務。

同時,當配置的SQL限流規則中最大活躍並發數或每串連最大QPS為0時,任何命中該規則的SQL都會被拒絕轉寄並直接向用戶端返回上述錯誤,可以使用該方式完全拒絕一類SQL的執行。

說明
  • 延遲隊列內部存在最小的重試時間間隔,當配置的最大QPS較大時,實際QPS會略小於設定的最大值。

  • 配置任意SQL限流規則後,無論是否命中,代理都需要對每條業務SQL進行模板化、產生唯一標識並嘗試匹配規則等一系列操作,因此啟用SQL限流會帶來5%-10%的轉寄效能下降,建議僅在資料庫側存在明顯慢SQL影響正常業務運行時進行限流。慢SQL消除後可以直接在控制台禁用限流規則,已配置的規則禁用後不會生效並可以持久化保留,後續可隨時啟用。

最佳實務

測試組態的限流規則是否生效

由於限流規則可以配置對哪些帳號和資料庫生效,通常可以建立一個帳號並對該帳號配置一條並發數或QPS為0的限流規則,以測試是否可以命中期望限流的SQL。

假設希望對以下SQL限流:

SELECT * FROM generate_series(1, 100000);
  1. 建立測試資料庫賬戶

    image

  2. 對測試賬戶配置限流規則,並設定活躍最大並發數為0,配置限流規則請參見操作步驟

    image

  3. 驗證規則是否生效。當前規則僅對建立測試賬戶生效,不會對當前業務產生影響。配置後通過規則中選擇的串連地址串連到資料庫執行該SQL,正常返回錯誤即可確認生效:

    SELECT * FROM generate_series(1, 100000);
    Current query is being throttled and waiting queue is full.

利用SQL限流處理生產環境慢SQL

  1. 準備測試環境。

  2. 在ECS執行個體上使用pgbench工具串連PolarDB叢集地址並初始化壓測資料。

    pgbench -h <PolarDB叢集地址> -p <PolarDB叢集地址的連接埠> -i -s 10 -U <PolarDB資料庫使用者名稱> <測試資料庫名稱>

    然後啟動壓測,使用pgbench內建的tpcb-like模式,類比正常業務負載。

    pgbench -h <PolarDB叢集地址> -p <PolarDB叢集地址的連接埠> -P 1 -b tpcb-like -j 5 -c 10 -M prepared -T 6000 -U <PolarDB資料庫使用者名稱> <測試資料庫名稱> 
  3. 類比慢SQL情境,建立一個串連會話,在測試資料庫中執行如下語句:

    WITH t AS (SELECT md5(i::text) AS id FROM generate_series(1, 10000000) i) SELECT * FROM t ORDER BY id LIMIT 1;

    該SQL會消耗大量計算資源,通常大約需要5秒返回如下結果:

                    id                
    ----------------------------------
     0000023f507999464aa2b78875b7e5d6
    (1 row)

    再次啟動pgbench,使用自訂指令碼壓測上述SQL,啟動10個串連,類比慢SQL導致叢集負載高的情境:

    echo "WITH t AS (SELECT md5(i::text) AS id FROM generate_series(1, 10000000) i) SELECT * FROM t ORDER BY id LIMIT 1;" > slow.sql
    
    pgbench -h <PolarDB叢集地址> -p <PolarDB叢集地址的連接埠> -P 1 -f slow.sql -j 5 -c 10 -M prepared -T 6000 -U <PolarDB資料庫使用者名稱> <測試資料庫名稱> 

    開始壓測後,原本的正常業務負載立刻大幅下跌:

    image

  4. 在控制台使用以下SQL模板配置一條限流規則,規則類型選擇活躍並發數限流:

    WITH t AS (SELECT md5(i::text) AS id FROM generate_series($1, $2) i) SELECT * FROM t ORDER BY id LIMIT $3;

    image

    將慢SQL限制並發數為1,啟用規則後即可看到業務負載回升,限流規則已生效。

    image

  5. 在控制台修改限流規則,單擊目標限流規則操作列的修改將活躍最大並發數進一步下調為0,完全拒絕慢SQL執行:

    image

    配置後即可看到慢SQL壓測端返回錯誤並中斷,至此業務負載完全恢複。

    image