天天看點

PolarDB-X SQL限流,為您的核心業務保駕護航

背景與介紹

SQL限流,顧名思義,是一種對SQL的查詢速度進行限制的能力。一般情況下,我們希望SQL查詢語句在資料庫上的執行速度越快越好,然而資料庫的資源有限,在CPU、IO、記憶體等某一項資源達到上限時,查詢在并發執行時會有激烈的資源争搶,這時查詢會有因為資源不足而出現逾時,影響使用者業務。這時使用者首先想到的是升配資料庫執行個體,計算資源不足則增加計算節點,IO資源不足則增加存儲節點分攤IO開銷,以此增加資源上限。

PolarDB-X SQL限流,為您的核心業務保駕護航

如上圖所示,PolarDB-X包含計算節點(CN)和存儲節點(DN),由于計算節點是無狀态的,增加計算節點操作可以在短時間内完成,然而增加存儲節點,涉及到資料遷移,無法快速完成。當無法快速增加資源上限時,我們想到的是如何進行合理的資源配置設定讓現有的存量資源發揮出最大的價值,簡單概括為:讓高優先級甚至直接影響核心業務的查詢能夠獲得足夠資源,而低優先級甚至可以不在這時執行的查詢獲得較少的資源。PolarDB-X正是以SQL限流的形式提供了這樣的能力,讓使用者能夠在核心業務的查詢受到其他邊緣業務查詢排擠的情況下,快速采取措施限制邊緣業務的查詢,恢複核心業務,及時止血。

小實驗:SQL限流的關鍵作用

接下來使用一個小實驗來展現SQL限流的關鍵作用。

首先在阿裡雲的官網上購買一個入門級的PolarDB-X 2.0的執行個體,因為筆者需要長期測試使用,商品類型上選擇了“包年包月”,讀者若想體驗可選“按量付費”,體驗完後記得及時釋放。

PolarDB-X SQL限流,為您的核心業務保駕護航

接着對PolarDB-X執行個體進行實驗操作,操作過程由三個階段組成:核心業務流量通路、邊緣業務流量通路、開啟SQL限流。

第一階段,對PolarDB-X施加TPC-C流量。TPC-C流量主要包含5種事務的發起:訂單建立(New-Order)、訂單支付(Payment)、發貨(Delivery)、訂單狀态查詢(Order-Status)、庫存狀态查詢(Stock-Level),以此模拟一個電商平台的核心系統。

第二階段,從另外的施壓機并發發起IO-Bound的查詢操作,查詢語句如下:

select * from bmsql_oorder as bubububuverybadsql limit 10000;      

以此模拟,邊緣業務流量對資料庫的通路,對核心業務查詢形成資源争搶。

第三階段,在發現核心業務流量收到影響之後,使用者在SQL日志和show full processlist指令的執行結果中雙雙發現一條非核心業務而且費IO資源的查詢語句。果斷采取措施,使用PolarDB-X的SQL限流能力對包含關鍵字"bubububuverybadsql"的SELECT查詢進行限流,限流方式為禁止執行這樣的SQL,使其查詢傳回錯誤,以此屏蔽邊緣業務流量。

通過監控檢視實驗結果,QPS和RT的監控如下:

PolarDB-X SQL限流,為您的核心業務保駕護航

在第一階段,核心業務流量正常通路,QPS處于高位,RT較小;在第二階段,由于費資源的邊緣業務流量的影響,QPS急劇下降,RT上升,核心業務受到重大影響;在第三階段開始的時間點,運用SQL限流大法後,QPS上升至正常水位,RT下降,核心業務恢複正常。

功能簡介

我們參考業界資料庫的SQL限流功能,結合PolarDB-X自身特點,開發了具有簡潔易用的互動接口、多樣的限流政策、平均比對複雜度O(1)、節點級限流執行個體級監控的SQL限流能力,可解使用者燃眉之急。

簡潔易用的互動接口

如果要對一種特定模式的SQL進行限流,使用者可以通過SQL接口建立限流規則來指定需要限流的SQL的特征,以及限流行為(對比對上的SQL采取的措施)。SQL文法中,我們使用CCL_RULE或者CCL_RULES文法關鍵字來代表限流操作。CREATE、DROP、SHOW開頭的SQL限流文法用于建立、删除、檢視SQL限流規則。文法簡潔易懂,友善使用者快速上手,而且不易出錯。

多樣的限流政策

我們提供豐富的SQL限流的比對次元,可讓使用者盡可能精準地比對到需要限流的SQL。

例子

繼續以上文小實驗的SQL為例,如果想要禁止執行這樣的SQL,首先分析這條的SQL所具有的特征:

特征名稱 特征值
使用者名 ccltest
用戶端IP 未知
資料庫 tpcc100
bmsql_oorder
獨特的關鍵詞 bubububuverybadsql
語句類型 SELECT

如果我們希望比對到的SQL直接傳回錯誤,則建立限流規則并嘗試執行這樣的SQL,結果如下:

PolarDB-X SQL限流,為您的核心業務保駕護航

PolarDB-X在提高限流精準度上進行了深入探索。使用關鍵詞比對時,需要指定該SQL獨特的關鍵詞或者關鍵詞組合,來避免錯誤地對其他的SQL實施了限流,當無法拿到完整的單條SQL時,可用關鍵詞進行有效限流。另外,PolarDB-X允許指定SQL模版編号(可從explain、show full processlist和SQL日志中得到)進一步提高SQL限流精準度。

有時,我們不希望這樣比較耗資源的SQL被一直傳回錯誤,而是希望獲得執行結果,但能允許執行得慢一點。PolarDB-X允許使用者在限流規則中,指定查詢并發度(MAX_CONCURRENCY)、等待隊列最大長度(WAIT_QUEUE_SIZE)、最大等待時間(WAIT_TIMEOUT)。每個查詢進入執行狀态都會占用一個并發度,退出時釋放并發度,而當并發度不夠的時候,查詢進入等待隊列,當超出等待隊列長度或者等待逾時,查詢都會傳回錯誤。

平均比對複雜度O(1)

比對方式

限流規則存在優先級,後建立的優先級高于先建立的,比對時按優先級從高到到低進行比對,比對到一個限流規則即傳回結果,不再比對剩餘的限流規則。PolarDB-X在SHOW CCL_RULES指令的傳回結果中指出了現有限流規則的優先級。

性能優化

假設限流規則的數量為N,每個限流規則都采用關鍵詞比對,單個限流規則裡的平均關鍵詞數量為M,關鍵詞長度是個常量,則限流規則的比對複雜度為圖檔。我們做了實驗,如果Naive地進行挨個比對,當限流規則數量為73個,每個規則有21個關鍵詞,關鍵詞長度為6個字元,相比沒有限流規則時,資料庫性能下降15.8%。我們使用空間換時間的方式對比對開銷進行了優化,使得比對開銷降為常量,經測試發現:規則比對開銷幾乎沒對資料庫性能産生影響。

接下來對優化點進行簡單介紹:

  1. 使用者比對次元優化。
PolarDB-X SQL限流,為您的核心業務保駕護航

當用戶端登入PolarDB-X時,PolarDB-X内部會配置設定一個連接配接對象給該用戶端,每個對象有一個全執行個體唯一的ConnId用于标示該連接配接,是以這個ConnId可以映射到該連接配接對象上不可變的資訊,比如user@host。是以,限流子產品發現某個查詢因為使用者名而無法比對到任何一個限流規則時,之後都不再比對該連接配接上的查詢。

  1. 關鍵詞比對内轉為模版編号比對。
PolarDB-X SQL限流,為您的核心業務保駕護航

如上圖所示,當一個關鍵詞比對的限流規則比對上一個查詢時,而且查詢中的參數值沒有比對到關鍵詞,我們則認為是該SQL的模版比對上限流規則,可使用元組(TemplateId,Schema,User,Host)作為Key,将比對結果緩存。下次同一使用者名,同一查詢來的時候,可直接傳回比對到的規則。

假設一個限流規則的比對關鍵詞組為 ["polardbx1", "polardbx2"], 目前符合該關鍵詞組的SQL有:

1. select `name` as polardbx1, `age` as polardbx2 from test where id = 1;
2. select * from test where `name` = 'polardbx1' or `name` = 'polardbx2';      

第一個查詢語句比對結果會被緩存,而第二個查詢語句因為是參數值比對中了限流規則中的關鍵詞,比對結果不會被緩存。

  1. 無法比對到規則的查詢語句的優化

假設一個限流規則的比對關鍵詞組為 ["polardbx1", "polardbx2"],目前在執行的SQL有:

a1. select `name` as polardbx1 from test where id = 1;
a2. select `name` as polardbx1 from test where id = 2;
b1. select `name` as polardbx1 from test where `name` = 'polardbx1';
b2. select `name` as polardbx1 from test where `name` = 'polardbx2';      

如上所示,查詢語句a1和a2,b1和b2具有相同的SQL模版。比對時,與2中類似,元組(TemplateId,Schema,User,Host)作為Key,将比對結果緩存,是以他們在緩存比對結果時會使用相同的CacheKey。

以a1和a2為例,他們的SQL模版都是:

a. select `name` as polardbx1 from test where id = ?;      

參數值分别為 1 和 2。假設建立完限流規則後,a1語句先于a2執行,執行a1時,限流子產品緩存該模版不比對的結果,當a2再來執行時,我們隻需要對判斷a1與a2唯一變動,即參數值,是否能對比對結果産生影響即可,顯然a2的參數值為2,不是任何限流規則的關鍵詞,是以直接傳回不比對的結果。

然而,當b1先于b2執行的時候,b2的參數值'polardbx2'可能會影響比對結果,我們對b2仍然進行完整的比對,最後傳回比對到的規則。

為提高效率,我們根據所有規則的關鍵詞會預先建立一個BloomFilter,以此快速判斷一個參數值是否可能為某個限流規則裡的關鍵詞。

節點級限流執行個體級監控

PolarDB-X限流規則中的并發度、等待隊列長度都是針對單個節點的參數,假設限流規則并發度為P,執行個體計算節點個數為K,則整個執行個體的并發度最大為KP。

為什麼限流規則參數不針對整個執行個體?

從PolarDB-X架構中可以看出,資源是跟着節點走的,節點越多資源越多,使用節點級限流時,節點增加或減少不會改變限流行為的合理性。另外,由于PolarDB-X的負載均衡機制是針對連接配接數,将連接配接數均勻分布在各個計算節點上,我們能通過以下的僞代碼構造出負載不均衡的場景:

connPoola = []
connPoolb = []
for i in range(1000):
    connPoola.push(createConnection('jdbc:mysql:10.10.10.9:3306/a'))
    connPoolb.push(createConnection('jdbc:mysql:10.10.10.9:3306/n'))

use connPoola for IO Bound Work
use connPoolb for core business      

使用以上建立連接配接池的方式,當計算節點個數正好為2且SLB采用常見的輪詢方式的時候,connPoola和connPoolb将分别連接配接到各自的節點上。生産環境中,如果多個不同業務功能的連接配接池并發建立,也可能會産生相似的效果。此時如果針對connPoola中的查詢進行限流,如果限流參數是針對執行個體級的,限流行為則與會與預想的大相徑庭。

使用執行個體級參數的好處是,使用者評估整個執行個體的限流效果時無需關心節點個數。現實是使用者目前可以從PolarDB-X控制台上感覺到節點個數,可以友善地評估出整個執行個體的限流效果。

綜合考慮,使用節點級限流更為合理。

為友善使用者監控執行個體狀況,和顯示上的簡潔性,使用SHOW CCL_RULES指令檢視限流規則的時候,限流效果聚合了多個計算節點上的資訊。

總結與展望

本文首先介紹了SQL限流的使用場景,它可通過限制邊緣業務查詢,留出資源來為核心業務保駕護航。接着是功能簡介,PolarDB-X結合自身雲原生分布式的特點,提供了具有簡潔易用的互動接口、多樣的限流政策、平均複雜度O(1)、節點級限流執行個體級監控的SQL限流能力。

目前,當查詢比對到限流規則進入等待隊列時,仍然占用線程池裡的一條線程,未來我們将會讓出線程,提高資源使用率。我們亦将沿着資料庫智能化的演進方向,探索如何根據workload自動為使用者建立限流規則。