Greenplum 6.0 新功能介紹——磁盤配額管理工具Diskquota

  • Diskquota是什么
  • Diskquota架構(gòu)
  • Diskquota快速上手

Diskquota是什么

Diskquota extension是Greenplum6.0提供的磁盤配額管理工具,它支持控制數(shù)據(jù)庫schema和role的磁盤使用量。當(dāng)DBA為schema或者role設(shè)置磁盤配額上限后,diskquota工作進程負責(zé)監(jiān)控該schema和role的磁盤使用量,并維護超出配額上限的schema和role的黑名單。當(dāng)用戶試圖往黑名單中的schema或者role中插入數(shù)據(jù)時,操作會被禁止。

Diskquota的典型應(yīng)用場景是對于企業(yè)內(nèi)部多個部門共享一個Greenplum集群,如何分配集群的磁盤資源給不同的部門。Greenplum的Resource Group功能支持對CPU,Memory等資源進行分配。而Diskquota則是對磁盤資源的細粒度分配,支持在schema和role的層級進行磁盤用量的控制,支持秒級延時的磁盤實時使用量檢測,這是傳統(tǒng)基于的cron job的磁盤管理工具做不到的。企業(yè)可以選擇為不同的部門分配專屬schema,從而實現(xiàn)對各個部門的磁盤配額分配。

需要指出Diskquota是對磁盤用量的一種軟限制,“軟”體現(xiàn)在兩個方面: 1. 計算schema和role的實時用量存在一定延時(秒級),因此schema和role的磁盤用量可能會超出配額。延時對應(yīng)diskquota模型的最小刷新頻率,可以通過GUC diskquota.naptime 調(diào)整其大小。2. 對插入語句,diskquota只做查詢前檢查。如果加載數(shù)據(jù)的語句在執(zhí)行過程中動態(tài)地超過了磁盤配額上限,查詢并不會被中止。DBA可以通過show_fast_schema_quota_view和show_fast_role_quota_view快速查詢每個schema和role的配額和當(dāng)前使用量,并對超出配額上限的schema和role進行相應(yīng)處理。

Diskquota架構(gòu)

Diskquota設(shè)計伊始,主要考慮了如下幾個問題:

  1. 使用單獨進程管理diskquota模型,還是將數(shù)據(jù)庫對象的實時磁盤使用量存儲在系統(tǒng)表中。 系統(tǒng)表pg_class存儲了數(shù)據(jù)表的元數(shù)據(jù)信息,比如relpages記錄了analyze后數(shù)據(jù)表的頁面數(shù)。我們沒有采用此方式管理diskquota模型,一方面,如果讓每次數(shù)據(jù)加載、刪除操作都實時更新relpages等信息,會降低數(shù)據(jù)庫性能;另一方面,diskquota基于extension框架,不希望改動DB內(nèi)核,因而選擇使用單獨的監(jiān)控進程來管理diskquota模型(在diskquot工作進程中維護所有數(shù)據(jù)表的實時磁盤使用量)。
  2. 對于單獨進程管理diskquota模型的方案,如何實現(xiàn)Greenplum Master和Segment之間的通信。 對于diskquota而言,Master和Segment之間的通信內(nèi)容主要是每個Segment上實時的磁盤使用量數(shù)據(jù)。由于diskquota是集群級別的磁盤配額管理工具,我們只關(guān)心Master節(jié)點維護的數(shù)據(jù)表的全局磁盤使用量。因此,基于Greenplum的SPI框架,Master上的diskquota工作進程可以定期通過SPI查詢,實時計算和匯總所有Segment上活躍表的磁盤使用量,Segment不需要常駐diskquota工作進程,而只需要一塊存儲活躍表的共享內(nèi)存。
  3. Diskquota性能及其對于Greenplum數(shù)據(jù)庫的影響。 Diskquota工作進程在每個查詢周期只對活躍的數(shù)據(jù)表計算其磁盤使用量,因此其時間復(fù)雜度正比于活躍表的個數(shù)。當(dāng)數(shù)據(jù)庫沒有數(shù)據(jù)加載操作時,diskquota沒有對IO資源的占用。Greenplum的只讀操作不會與diskquota產(chǎn)生交互影響;寫入和修改等操作,每次數(shù)據(jù)落盤(新的頁面申請)會存在將數(shù)據(jù)表的relfilenode信息寫入共享內(nèi)存的額外開銷。

最終diskquota extension的架構(gòu)由以下四部分組成。

  1. Quota Status Checker。負責(zé)維護diskquota模型,計算schema和role的實時磁盤用量,生成超出配額的schema和role的黑名單。
  2. Quota Change Detector。負責(zé)監(jiān)測磁盤變化。INSERT,COPY,DROP,VACUUM FULL等語句會改變數(shù)據(jù)表的大小,我們稱被改變的數(shù)據(jù)表為活躍表,Quota Change Detector將活躍表存入共享內(nèi)存,以供Quota Status Checker使用。
  3. Quota Enforcement Operator。負責(zé)取消查詢。當(dāng)執(zhí)行INSERT,UPDATE,COPY等操作時,如果被操作表所在schema或所屬role超出了磁盤配額,查詢會被取消。
  4. Quota Setting Store。負責(zé)存儲DBA定義的schema和role的磁盤配額。
image.png

圖1. Greenplum Diskquota架構(gòu)

Quota Status Checker

Quota Status Checker基于Greenplum background worker框架實現(xiàn),包含兩類bgworker: diskquota launcher和diskquota worker。

Diskquota launcher負責(zé)管理diskquota worker。每個集群只有一個launcher,并且運行在Master節(jié)點。laucher進程在數(shù)據(jù)庫啟動時(具體時間是Postmaster加載diskquota鏈接庫的時候)被注冊并運行。

Laucher進程主要負責(zé):

  1. 當(dāng)launcher啟動時,基于數(shù)據(jù)庫diskquota中已啟動diskquota extension的數(shù)據(jù)庫列表,為每一個列表中數(shù)據(jù)庫啟動diskquota worker進程。
  2. 當(dāng)laucher運行中,監(jiān)聽數(shù)據(jù)庫Create Extension diskquotaDrop Extension diskquota請求,啟動或中止相關(guān)worker進程,并更改數(shù)據(jù)庫diskquota中的已啟動diskquota extension的數(shù)據(jù)庫列表。
  3. 當(dāng)launcher正常退出時,通知所有diskquota worker進程退出。

Diskquota worker進程實際扮演Quota Status Checkers的角色。每個啟動diskquota extension的數(shù)據(jù)庫都有隸屬于自己worker進程。沒有采用一個worker進程監(jiān)控多個數(shù)據(jù)庫是由于Greenplum和Postgres存在一個進程只能訪問一個數(shù)據(jù)庫的限制。由于每個worker進程占用數(shù)據(jù)庫連接和資源,我們?yōu)橥瑫r啟動disk extension的數(shù)據(jù)庫個數(shù)設(shè)置了上限:10。diskquota worker通過SPI與Segment進行交互,因此,diskquota worker同樣只運行在Master節(jié)點。

Worker進程主要負責(zé):

  1. 初始化diskquota模型,從表diskquota.table_size中讀取所有table的磁盤用量,并計算schema和role的磁盤用量。對于非空數(shù)據(jù)庫第一次啟動diskquota extension,DBA需要調(diào)用UDF diskquota.init_table_size_table()對表diskquota.table_size進行初始化。該初始化需要計算數(shù)據(jù)庫中的所有數(shù)據(jù)文件的大小,因此根據(jù)數(shù)據(jù)庫大小,可能是一個耗時的操作。初始化完畢后,表diskquota.table_size將會由worker進程自動更新。
  2. 以diskquota.naptime為最小刷新頻率,周期性維護diskquota模型,包括所有table,schema,role的磁盤用量和超出diskquota配額的黑名單。

刷新diskquota模型的算法如下:

  1. 獲取schema和role的最新磁盤配額,配額記錄在表’diskquota.quota_config’中.
  2. 獲取活躍表的磁盤使用量,首先調(diào)用SPI函數(shù),從所有Segment的共享內(nèi)存中獲取全局活躍表的列表。之后,匯總計算全局活躍表在所有Segment上的磁盤使用量(通過調(diào)用pg_total_relation_size(table_oid)計算,pg_total_relation_size會自動計算數(shù)據(jù)主表,索引表,toast表,fsm表等數(shù)據(jù)表的總磁盤用量)。
  3. 遍歷pg_class系統(tǒng)表:
    1. 如果table在活躍表中,計算table磁盤使用量的變化值,并更新對應(yīng)table_size_map, namespace_size_map和role_size_map。
    2. 如果table在活躍表中,標記該表的need_to_flush flag為true
    3. 如果table的schema發(fā)生變化, 將該表的磁盤使用量從舊schema移動到新schema。
    4. 如果table的owner(role)發(fā)生變化, 將該表的磁盤使用量從舊role移動到新role。
    5. 標識table的is_existed flag為true
  4. 遍歷table_size_map,基于is_existed flag識別被刪除的表,并減少相關(guān)schema和role的磁盤使用量。
  5. 遍歷pg_namespace系統(tǒng)表:
    1. 從namespace_size_map刪除對應(yīng)schema。
    2. 比較每個schema的磁盤使用量和配額,將超出配額的schema放入diskquota黑名單。
  6. 遍歷pg_role系統(tǒng)表:
    1. 從role_size_map刪除對應(yīng)role。
    2. 比較每個role的磁盤使用量和配額,將超出配額的role放入diskquota黑名單。
  7. 遍歷table_size_map,基于need_to_flush flag將表的磁盤使用量寫入數(shù)據(jù)表diskquota.table_size。Update操作需要針對每條數(shù)據(jù)執(zhí)行一條SQL語句,為了加速操作,使用批量Delete+批量Insert的方式代替逐條Update。具體來說通過以下兩條SQL語句處理所有大小發(fā)生變化的表:delete from diskquota.table_size where tableoid in (need_to_flush oid list)insert into diskquota.table_size values(need_to_flush oid and size list)

Quota Change Detector

Quota Change Detector通過一系列Hook函數(shù)實現(xiàn)。對于Heap表,在smgrcreate()/smgrextend()/smgrtruncate()等位置設(shè)置Hook函數(shù),記錄活躍表信息;對于AO表和CO表,在BufferedAppendWrite/copy_append_only_data/TruncateAOSegmentFile等位置設(shè)置Hook函數(shù),記錄活躍表信息?;钴S表被存儲在每個Segment的共享內(nèi)存中,等待Quota Status Checker周期性查詢。由于活躍表只是一個子集,顯著減少了每次刷新diskquota模型的代價。

Quota Enforcement Operator

Quota Enforcement Operator同樣通過Hook函數(shù)實現(xiàn)。通過重用Greenplum的Hook函數(shù)ExecutorCheckPerms_hook,實現(xiàn)在每次插入和更新數(shù)據(jù)前,檢查目標schema或role是否在diskquota的黑名單中,并中止擊中黑名單的查詢。

Quota Setting Store

diskquota的磁盤配額分為schema和role兩類,存儲在數(shù)據(jù)表’diskquota.quota_config’中。每一個啟動diskquota的數(shù)據(jù)庫存儲和管理自己的磁盤配額。需要指出的是,盡管role不隸屬于數(shù)據(jù)庫,而是一個數(shù)據(jù)庫集群的對象,在diskquota中將role的磁盤配額限定為數(shù)據(jù)庫特定。即role會在不同的數(shù)據(jù)庫有不同的配額,role的磁盤使用量也是不同數(shù)據(jù)庫獨立計算。Quota Setting Store被定義為如下數(shù)據(jù)表。

create table diskquota.quota_config (targetOid oid, quotatype int, quotalimitMB int8, PRIMARY KEY(targetOid, quotatype));

Diskquota快速上手

安裝和配置

  1. 開源版diskquota下載地址:diskquota repo,安裝步驟如下
# source greenplum_path.sh
cd $diskquota; 
make; 
make install;

  1. 創(chuàng)建數(shù)據(jù)庫diskquota 用來持久化啟動diskquota extension的數(shù)據(jù)庫列表。
create database diskquota;

  1. 將diskquota添加到shared_preload_libraries列表
# enable diskquota in preload shared library.
gpconfig -c shared_preload_libraries -v 'diskquota'
# restart database.
gpstop -ar

  1. 配置diskquota extension的刷新頻率
# set naptime (second) to refresh the disk quota stats periodically
gpconfig -c diskquota.naptime -v 2

  1. 創(chuàng)建diskquota extension,例如希望在postgres數(shù)據(jù)庫啟用diskqota extension, 執(zhí)行如下語句。
# suppose we are in database 'postgres'
create extension diskquota;

  1. 如果DBA在非空數(shù)據(jù)庫創(chuàng)建了dikquota extension,會收到提示信息,需要手動執(zhí)行UDF初始化表table_size。根據(jù)數(shù)據(jù)庫中已經(jīng)存在的文件數(shù),該操作可能耗時。
# after create extension diskquota on non empty database
select diskquota.init_table_size_table();

  1. 刪除diskquota extension,例如希望在’postgres’數(shù)據(jù)庫禁用diskqota extension,執(zhí)行如下語句。
# login into 'postgres'
drop extension diskquota;

使用

  1. 設(shè)置schema的磁盤配額
create schema s1;
select diskquota.set_schema_quota('s1', '1 MB');
set search_path to s1;
create table a(i int);
# insert small data succeeded
insert into a select generate_series(1,100);
# insert large data succeeded, since diskquota is soft limit
insert into a select generate_series(1,10000000);
# insert small data failed
insert into a select generate_series(1,100);
# delete quota configuration
select diskquota.set_schema_quota('s1', '-1');
# insert small data succeeded
select pg_sleep(5);
insert into a select generate_series(1,100);
reset search_path;

  1. 設(shè)置role的磁盤配額
create role u1 nologin;
create table b (i int);
alter table b owner to u1;
select diskquota.set_role_quota('u1', '1 MB');
# insert small data succeeded
insert into b select generate_series(1,100);
# insert large data succeeded, since diskquota is soft limit
insert into b select generate_series(1,10000000);
# insert small data failed
insert into b select generate_series(1,100);
# delete quota configuration
select diskquota.set_role_quota('u1', '-1');
# insert small data succeed
select pg_sleep(5);
insert into a select generate_series(1,100);
reset search_path;

  1. 查詢schema的磁盤使用量和配額
select * from diskquota.show_fast_schema_quota_view;

  1. 查詢role的磁盤使用量和配額
select * from diskquota.show_fast_role_quota_view;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容