本文分享自華為雲社群《【GaussTech速遞】技術解讀之細粒度資源管控》,作者:GaussDB 資料庫。
背景
對資料庫叢集內資源管控與資源隔離一直是企業客戶長久以來的訴求。華為雲GaussDB作為一款企業級分散式資料庫,一直致力於滿足企業對大型資料庫叢集的管理需要。
資料庫可以管理的資源有計算資源與儲存資源,計算資源包括CPU、記憶體、IO與網路,儲存資源包括資料儲存空間、日誌儲存空間與臨時檔案等。
從使用者角度來看,資源管控透過設定閾值或者優先順序限定程式對資源的使用,保證承諾服務等級協議的同時,又滿足不同使用者間資源隔離,達成多個租戶共享資料庫資源的目的。
從系統的角度來看,引入資源監控與控制的手段,可以實現資源在可控情況下被合理利用的目的,避免資源耗盡,防止系統停止響應、崩潰等情況的發生。作業優先順序,可以保證作業平穩執行,避免某個作業佔用資源過高時影響其他作業,並在資源富裕時,實現資源利用的最大化。除此以外,還能滿足外部的期望,保證系統資源使用最大化。透過對作業控制,可以保證作業是平穩的,避免作業執行過程中出現不可控的行為。
為了解決上述目標,華為雲GaussDB資料庫提供了一種對資料庫叢集內資源進行細粒度管控的方案——細粒度資源管控。該方案在不同的管控粒度(如使用者級、會話級與語句級)和不同的管控維度(CPU、記憶體與IO)都提供了對應的管控能力。使用者可以根據自己業務需求採取合適的管控維度與管控粒度來達成資源管控與資源隔離的目標,滿足不同場景的資源控制的需要。
技術架構
我們先來看下細粒度資源管控的技術架構和執行原理:
從上圖中可以看到,GaussDB提供資源池模組來完成CPU、記憶體與IO的管控邏輯。使用者可以建立一個資源池並指定其可以使用的CPU、記憶體與IO的份額,並把資源池與使用者繫結。之後該使用者發起的作業在資料庫核心最佳化解析、執行引擎以及儲存引擎模組執行的過程中都會受到實時資源管控,確保其CPU、記憶體與IO都在對應資源池的範圍內。
假設A公司部署了一套GaussDB例項,其同時存在三個不同的應用來訪問該例項,如OLTP業務、報表業務、其他低優先順序業務。A公司希望對三個業務做資源的合理管控,在保證資源使用最大化的情況下,系統平穩執行。我們可以使用系統管理員執行如下命令來為三個業務的使用者設定,其資源份額比例為50:30:10,剩餘的10%為系統預留。
這裡僅做簡單的使用示例,每一個引數的具體含義會在後面的章節進行詳細說明。
create resource pool respool_tp with(control_group="cgroup_tp", max_dynamic_memory="5GB", max_shared_memory="5GB", io_limits=50, io_priority="High");
alter role tp_user RESOURCE POOL 'respool_tp';
create resource pool respool_report with(control_group="cgroup_report", max_dynamic_memory="3GB", max_shared_memory="3GB", io_limits=30, io_priority="Medium");
alter role report_user RESOURCE POOL 'respool_report';
create resource pool respool_other with(control_group="cgroup_other", max_dynamic_memory="1GB", max_shared_memory="1GB", io_limits=10, io_priority="Low");
alter role other_user RESOURCE POOL 'respool_other';
如上操作後,OLTP業務、報表業務與其他低優先順序業務分別使用tp_user、report_user與other_user連入GaussDB執行作業時,這三個業務則會受到對應的資源池respool_tp、respool_report與respool_other的管控,在資源發生爭搶的時候保證三個業務分別可以使用GaussDB叢集50%、30%以及10%的資源。
關鍵能力
在瞭解了細粒度資源管控的整體架構和使用方法之後,我們再來看看它具備哪些關鍵能力,這些能力可以為客戶帶來什麼樣的業務價值。
CPU管控
GaussDB的CPU管控是以資源池粒度來做使用者資源管控的,每一個資源池繫結一個控制組,透過控制組(Control Group,CGroup)來實現CPU的管控。CGroup是Linux核心提供的一種限制、記錄、隔離程序組所使用的物理資源(如CPU、Memory、IO等)的機制。
考慮到資料庫系統、使用者、作業不同維度的隔離性和可配置性,GaussDB使用控制組的層級特性構造符合資料庫場景的模型(見下圖),其滿足客戶SLA的關鍵特性,並支援三個維度的層次隔離和控制:資料庫程式與非資料庫程式隔離、資料庫常駐後備執行緒與執行作業執行緒隔離以及資料庫多使用者之間的隔離。
GaussDB控制組可以設定CPU的百分比以及核數的上限,其中根節點負責管控GaussDB程序可用的CPU份額;Backend控制組負責管控資料庫常駐後臺執行緒的CPU份額(Vacuum、DefaultBackend);Class控制組負責管控使用者的作業執行緒的CPU份額(UserClass1,UserClass2,...UserClassN);Class控制組內還可以建立Workload控制組(TopWD,RemainWD...)進行更細粒度的管控。
接上面的示例,我們用GaussDB提供的CGroup工具來為A公司的OLTP業務、報表業務以及其他低優先順序業務分別建立控制組,CPU分配比例為50%、30%與10%。
gs_cgroup -c -S cgroup_tp -s 50;
gs_cgroup -c -S cgroup_report -s 30;
gs_cgroup -c -S cgroup_other -s 10;
執行如上命令就代表我們成功建立了3個控制組,之後可以在建立資源池時指定該控制組名稱。繫結資源池的使用者所發起的作業就會收到控制組對應CPU份額的管控。
CGroup管控CPU有兩個問題需要注意:
一是,如果執行緒的CPU需要受CGroup管控,那麼需要執行CGroup的系統API來為執行緒繫結對應的CGroup,該操作較為耗時;
二是,CGroup的CPU管控效果,線上程數與CPU成比例的情況下,管控效果最佳。
基於這些問題GaussDB提出了執行緒組的概念,每一個資源池對應一個執行緒組,執行緒組裡的執行緒都繫結了該資源池所對應的CGroup。同時,GaussDB會將每一個執行緒組的執行緒數量調整到與對應CGroup的CPU份額一致。具體可見下圖:
每一個使用者發起的作業都會被分發到對應的執行緒組裡的執行緒來執行,由於執行緒已經繫結了對應的Cgroup節點,所以作業系統會線上程排程時完成CPU管控。
GaussDB提供兩層使用者機制,繫結Class控制組的資源池稱之為組資源池,對應的使用者為組使用者,繫結Workload控制組的資源池稱之為業務資源池,對應的使用者為業務使用者。組使用者一般對應一個部門,而業務使用者對應這個部門的不同的業務。業務資源池的各個資源維度的資源份額會不會超過所屬組資源池的份額,從而達到兩級資源管控的目標。
CPU管控也提供名稱為session_respool的GUC來限制單個會話的CPU不超過對應資源池的CPU上限。
記憶體管控
GaussDB提供動態記憶體與共享快取的管控,建立資源池時可以指定max_dynamic_memory與max_shared_memory來分別完成動態記憶體與共享快取的閾值設定。
動態記憶體管控並沒有更改其原有的記憶體資源分配機制,僅在分配記憶體之前增加一個邏輯判斷層,對多分配出的記憶體進行記賬,透過檢查該記賬值是否達到允許使用的記憶體上限來完成記憶體的管控。當動態記憶體超過上限時,作業申請記憶體會失敗。作業退出時,該作業已申請的記憶體會進行釋放來保證其他作業可以正常執行。同理,當作業使用的共享快取超過資源池的管控上限時,再次申請共享快取,需要先釋放自己已經佔用的共享快取,比如BufferPool,作業申請頁面時,會對自己已經佔用的頁面進行淘汰,淘汰之後空餘出來的頁面供自己繼續使用。
GaussDB除了使用者粒度的記憶體管控外,也提供session_max_dynamic_memory與query_max_mem兩個GUC引數來完成會話級與語句級動態記憶體的管控,當一個會話或者語句所使用的動態記憶體達到GUC的閾值時,作業申請記憶體失敗。
IO管控
GaussDB的磁碟讀寫IO都由後臺執行緒完成,該執行緒無法區分頁面屬主,只是按照時間順序依次落盤,無法針對不同使用者管控不同的IO使用。基於此,考慮IO管控功能採用邏輯IO統計方式,對使用者或者會話的讀寫IO進行管控限制,在工作執行緒和共享快取之間增加了邏輯IO計數,對於行存表來說每6000(可透過io_control_unit GUC進行修改)行算做一次IO,當一秒產生的讀寫IO請求數超過資源池設定的閾值時,則將該IO請求加入到後臺執行緒的一個等待佇列裡,後臺執行緒將對等待佇列裡的這些IO請求進行監控,當其等待時間符合條件時,將這些IO請求從等待佇列中喚醒。
GaussDB支援兩種模式的IO資源管控,上線數值模式是透過設定固定的觸發IO次數的數值,進行IO資源控制;優先順序模式是指在當前磁碟長時間使用率達到95%以上,所有作業都無法達到上線數值模式時,使用者可透過該模式進行IO控制,控制該作業原本觸發IO的優先順序比例,優先順序包含三擋:High、Medium與Low。
接上面的示例,我們為A公司的OLTP業務、報表業務以及其他低優先順序業務分別建立資源池,IO權重分別設定的為High、Medium與Low。那麼,OLTP業務能使用50%的IO請求向BufferPool中讀取或寫入資料,少量的IO請求會進入等待佇列等待;報表業務能使用20%的IO請求向BufferPool中讀取或寫入資料,較多的IO請求會進入等待佇列等待;其他低優先順序業務能使用10%的IO請求向BufferPool中讀取或寫入資料,較多的IO請求會進入等待佇列等待;後臺監控執行緒會週期性的遍歷IO等待佇列,喚醒等待時間符合要求的IO請求從BufferPool讀取或寫入資料。
GaussDB除了支援使用者粒度的IO管控外,也支援透過設定會話級GUC引數io_limits與io_priority,來完成指定會話上允許作業的IO管控。
連線數與併發管控
GaussDB提供基於資源池的連線數管控與併發管控,建立資源池時可以指定max_connections與max_concurrency來分別完成連線數與併發數的設定,可以使用如下SQL,為前面示例A公司的三個業務對應的資源池完成連線數與併發數管控:
alter resource pool respool_tp with(max_connections=-1, max_concurrency = -1);
alter resource pool respool_report with(max_connections=200, max_concurrency = 100);
alter resource pool respool_other with(max_connections=100, max_concurrency = 50);
如上SQL執行成功後,實時生效。A公司OLTP業務的連線數與併發數不受限制,只有叢集有資源它都可以使用到;報表業務的最大連線數為200,其他低優先順序業務的最大連線數為100,當這兩個業務建立的連線數超過該值時,GaussDB核心會自動攔截,報當前連線數不足,連結失敗;報表業務的最大併發數為100,其他低優先順序業務的最大併發數為50,當這兩個業務同時發起的作業數超過該值時,超出的作業將會進入等待佇列,直到已有的作業完成之後GaussDB才會將其喚醒繼續執行作業。
儲存空間管控
儲存空間管控,用於限定不同使用者可以使用的空間配額,防止單使用者儲存空間使用過大導致整個資料庫業務受阻。GaussDB透過在建立使用者時指定儲存空間的大小來實現對儲存資源的管控。
儲存空間資源分為三種型別:永久表空間(Perm Space)、臨時表空間(Temp Space)與運算元下盤空間(Spill Space)。
可以使用如下SQL,為前面示例A公司的三個業務對應的使用者完成磁碟空間額管控。
alter user tp_user PERM SPACE '200G' TEMP SPACE '20G' SPILL SPACE '20G';
alter user report_user PERM SPACE '100G' TEMP SPACE '10G' SPILL SPACE '10G';
alter user other_user PERM SPACE '100G' TEMP SPACE '10G' SPILL SPACE '10G';
儲存空間管理支援對組使用者和業務使用者的儲存空間管理。當業務使用者對應的組使用者存在空間限制時,業務使用者的空間也受到該組使用者的空間限制。指定儲存空間的大小後,該使用者在DN上所有的寫操作會增加使用者已用空間,刪除操作減少使用者已用空間,CN會週期性的從DN獲取一次已用空間總和,並對使用者已用空間進行判斷,超過最大值後cancel掉寫作業(insert/create table as/copy),後面寫作業報錯退出。
特性演示
特性演示這裡我們就簡單的為大家演示一下CPU的管控效果,因為對業務影響最大的就是CPU。
建立兩個資源池分別設定20%與60%的CPU,然後使用兩個繫結了該資源池的使用者開始跑業務。觀測CPU的實際使用情況。
1. 建立控制組:
gs_cgroup -c -S class1 -s 20;
gs_cgroup -c -S class2 -s 60;
2. 建立資源池:
CREATE RESOURCE POOL xuuer_pool with(control_group = "class1");
CREATE RESOURCE POOL xyuser1_pool with(control_group = "class2");
3. 建立使用者繫結資源池:
create role user1 RESOURCE POOL 'xuuer_pool';
create role user2 RESOURCE POOL 'xyuser1_pool';
4. 透過Top觀察系統CPU狀態,同時細粒度資源管控提供gs_wlm_respool_cpu_info函式來觀察各個資源池的CPU實時情況。
如上圖,可知初期系統CPU是空閒狀態,資源池的CPU監控檢視也顯示CPU使用為0。讓user1開始跑業務,觀測可知系統CPU有一定業務佔用,查詢資源池的CPU監控檢視顯示,user1可以使用80%的CPU。此時,讓user2也開始跑業務,觀測可知系統CPU進入繁忙狀態,查詢資源池的CPU資源監控的系統函式可知user1的CPU使用率開始下降,user2的CPU使用率開始上升。
整理兩個使用者的CPU使用率並繪製曲線圖如下圖,可看出user1與user2的CPU使用率最終會平衡到3比1的狀態,符合資源池對應的CGroup控制組裡設定的20%與60%的比例,達到了CPU管控的效果。
總結
細粒度資源管控特性目前支援集中式與分散式。分散式下的計算資源管控是各個節點獨立管控自己節點的資源,儲存資源管控是以叢集維度來整體管控的。
細粒度資源管控作為多租戶的資源隔離的底座,實現資源的精準劃分與控制,並解決高負載場景下資源不足而導致叢集不可服務的問題。該特性適用於資料隔離不敏感,但對不同業務有資源隔離需求的場景,如果客戶對資源隔離和資料隔離都有需求的話,可以關注一下我們後面即將分享的多租資料庫特性哦!
點選關注,第一時間瞭解華為雲新鮮技術~