摘要:DWS的負載管理分為兩層,第一層為cn的全域性並行控制,第二層為資源池級別的並行控制。
本文分享自華為雲社群《GaussDB(DWS) 並行管控&記憶體管控》,作者: fighttingman。
這裡將並行管控和記憶體管控寫在一起,是因為記憶體管控實際是通過限制語句的並行達到記憶體管控的目的的。記憶體管控是基於語句的估算記憶體的前提下進行管控的,通俗的說就是語句有個估算記憶體,當資源池的剩餘記憶體小於語句的估算記憶體時,這個語句就會排隊等待,等資源池內的語句執行完,資源池有足夠的剩餘記憶體的時候,才會讓這個語句執行。所以記憶體管控的實際效果和語句的估算記憶體有很大關係,估算的大了就會造成大量語句排隊,實際沒有使用那麼多記憶體,造成記憶體資源浪費,相反估算的小了,就會有很多語句下發,實際記憶體使用就會變多,就有語句報記憶體不足的錯誤風險。
資料庫系統的並行控制,在整個系統中起著很重要的作用,比如很多使用者的業務壓力過大時,有時會導致連線數量被佔滿,有時會導致某種計算資源被佔滿,有時會導致儲存空間被佔滿,這些情況都會導致整個叢集進入異常甚至不可用的狀態:正在執行的作業互相爭搶CPU,會導致大家都不能好好執行;大量作業執行時,佔用大量記憶體,很容易觸發到記憶體瓶頸,造成作業記憶體不可用問題,導致業務報錯等等。在不進行並行控制的情況下,這些情況都很可能會出現,影響到正常業務。
DWS的負載管理分為兩層,第一層為cn的全域性並行控制,第二層為資源池級別的並行控制。在通過第一層控制的時候,會繼續向前走到第二層資源池控制,根據資源池當前的負載資源情況決定作業繼續執行或者排隊。
基於DWS並行控制邏輯看出,實際作業執行中,可能會在兩種佇列中排隊:
一種是全域性佇列(global queue)這種佇列不區分簡單和複雜作業,也不區分是DDL或者是普通語句,這種是每個cn生效。
一種是資源池佇列(resource pool queue),使用者下發的一般語句會根據資源消耗估算以及複雜程度在這裡進行判斷是否排隊。
在兩層佇列的過濾下,DWS會篩選出當前能執行的語句,使其正常執行,執行時也會受到其所屬資源池資源的限制(只能使用資源池設定的CPU、記憶體、IO配額)。
這裡介紹幾個常用檢視以及SQL語句,可以迅速判斷目前的業務出現問題的原因,受限根據以下檢視可以看到目前的作業是不是在排隊,之後要迅速分析為什麼在排隊,是因為負載管理各個引數設定問題,還是因為正在執行的語句佔據了過多的資源導致的排隊。
pgxc_stat_activity (活躍檢視)
查詢當前執行時間最長的語句的排隊狀態,query_id(資料庫中作業的唯一標識),以及詳細的語句資訊。
select coorname,usename, current_timestamp-query_start as duration, enqueue,query_id,query from pgxc_stat_activity where state='active' and usename <> 'Ruby' order by duration desc;
根據該語句可以迅速判斷出哪些語句執行時間很長,是什麼樣的語句執行很慢以及該語句的query_id,便於迅速進入下一步排查。
該檢視中enqueue欄位中如果顯示waiting in global queue就代表在全域性排隊。全域性排隊是受GUC引數max_active_statements引數控制的,是單cn生效的,也就是每個cn都可以支援這麼大的並行量。比如叢集中有3個cn範例,GUC引數max_active_statements引數設定為60,也就是說每個cn都支援60個語句並行執行,叢集全域性支援3 * 60 = 180並行執行作業。當下發作業大於這個cn設定的max_active_statements的時候就會進行全域性排隊,在pgxc_stat_activity檢視中enqueue欄位就會顯示waiting in global queue。
當GUC引數enable_dynamic_workload設定為off的時候就代表是靜態負載管理模式。靜態負載管理的情況下,pgxc_stat_activity檢視中enqueue欄位只會有waiting in respool queue。並行控制引數為資源池的max_dop(簡單作業)和active_statements(複雜作業)。
1)簡單作業和複雜作業的定義
在靜態負載管理中,簡單作業是估算代價cost值小於GUC引數parctl_min_cost值的作業。反之則判定為複雜作業。該GUC引數預設為10W,
當parctl_min_cost為-1時,或者作業估算代價小於10時,作業都判定為簡單作業。
2)簡單作業並行限制
ALTER RESOURCE POOL resource_pool_a1 WITH (max_dop=10);
通過設定資源池的max_dop引數設定簡單作業並行,關聯資源池resource_pool_a1的使用者都受到這個引數的控制。當所有關聯這個資源池的使用者的所有作業數量之和大於這個引數的時候,就會進行資源池排隊,活躍檢視enqueue欄位就會顯示waiting in respool queue。
3)複雜作業並行限制
ALTER RESOURCE POOL resource_pool_a2 WITH (active_statements=10);
通過設定資源池的active_statements引數控制複雜作業的並行數,關聯資源池resource_pool_a2的使用者都受到這個引數的控制。
資源池使用並行點數的計數方式來計算可執行的複雜作業並行數量,並行點數計算公式為
作業使用記憶體點數:active_points = (query_mem/respool_mem) * active_statements * 100
作業使用並行點數:active_points = 100
資源池總點數:total_points = active_statements * 100
單位點數: 100
4)相關說明
當GUC引數enable_dynamic_workload設定為on的時候就代表是動態負載管理模式。動態負載管理的情況下,pgxc_stat_activity檢視中enqueue欄位會有waiting in respool queue和waiting in global queue。
1)簡單作業和複雜作業的定義
動態負載管理下優化器估算記憶體大於32M認為是複雜作業,反之認為是簡單作業。
執行中的作業複雜簡單情況可以通過PG_SESSION_WLMSTAT中的attribute欄位檢視。
2)動態負載管理相關說明
3)短查詢加速(預設開啟,建議開啟)
混合負載場景下,複雜查詢可能會長時間佔用大量資源,雖然簡單查詢執行時間短、消耗資源少,但是因為資源耗盡,簡單查詢不得不在佇列中等待複雜查詢執行完成。為提升執行效率、提高系統吞吐量,GaussDB(DWS)的「短查詢加速」功能,實現對簡單查詢的單獨管理。
雖然單個簡單作業資源消耗少,但是大量簡單作業並行執行還是會佔用大量資源,因此短查詢加速開啟情況下,需要對簡單查詢進行並行管理;資源管理可能會影響查詢效能,影響系統吞吐量,因此簡單查詢不進行資源管理,異常規則也不生效。
設定方法:
資源池的記憶體管理是基於語句的估算記憶體進行管理的。
1)資源池可用記憶體設定方法
ALTER RESOURCE POOL resource_pool_a1 WITH (MEM_PERCENT=20);
2)資源池作業估算記憶體限制設定方法
ALTER RESOURCE POOL resource_pool_a1 WITH (MEMORY_LIMIT="300MB");
GaussDB(DWS)對外提供諸多系統檢視,可以用來輔助資源管理及資源使用相關問題的分析定位,常用檢視及用法說明如下表所示。(☆代表常用程度)
除過上述常用檢視,資源管理問題定位過程需要根據實際場景,結合範例紀錄檔、叢集狀態等共同分析定位。
因為並行的設定和業務的複雜程度和叢集的規格設定有很大的關係,本推薦僅做參考。推薦基於3CN 12DN,每個dn範例最大可使用64G記憶體情況下推薦的
在813核心版本及以上版本推薦設定如下。
GUC引數:
資源池引數:
出現業務阻塞、效能下降、查詢無響應等類似現網問題時,通過以下方法可以排查是否排隊問題並定位排隊原因,同時根據排隊原因給出相應規避措施。
首先確認是否排隊問題,其次排查排隊原因,確認是否屬於正常排隊:
select rpname,slow_run,slow_wait,slow_limit,used_cpu,cpu_limit,used_mem,estimate_mem from gs_respool_resource_info;
select resource_pool,attribute,lane,status,enqueue,sum(statement_mem) as stmt_mem,count(1) from pgxc_session_wlmstat where status!='finished' and attribute!='Internal' and usename!='Ruby' group by 1,2,3,4,5;
通過檢視可以獲取到各資源池快慢車道作業執行資訊,據此可以判斷是否排隊問題:
如果有作業處於排隊狀態,則可能是排隊導致的問題,否則排除排隊問題;可能的排隊原因包括:
排查排隊原因
常見排隊原因及解決措施
1)全域性並行排隊
單CN實際執行作業數≥全域性並行上限,則全域性並行排隊正常;
單CN實際執行作業數長時間小於全域性並行上限,則可能存在計數洩露。
2)快車道排隊
快車道實際執行作業數≥快車道並行上限,則快車道並行排隊正常;
快車道實際執行作業數長時間小於快車道並行上限,則可能存在計數洩露。
3)靜態慢車道排隊
慢車道實際執行作業數≥慢車道並行上限,則慢車道並行排隊正常;
慢車道實際執行作業累計估算記憶體≥慢車道記憶體上限,則慢車道記憶體佔用達到上限導致排隊,關注是否有查詢估算記憶體過大;
如果慢車道並行和記憶體佔用長時間達不到上限,則可能存在計數洩露。
4)動態CCN排隊
如果查詢在CCN排隊,則需要查詢CCN開發者檢視確認排隊原因:
select * from pg_stat_get_workload_struct_info();
CCN上可能的排隊原因:
1)查詢資源池監控檢視,確認是否正常排隊(813及以上版本)
下面以單CN下發作業為例,多CN下發作業需查詢pgxc_respool_resource_info檢視。
select rpname,slow_run,slow_wait,slow_limit,used_cpu,cpu_limit,used_mem,estimate_mem from gs_respool_resource_info;
通過該查詢可以直觀的觀察各資源池作業負載資訊,如果資源池running作業並行、記憶體長時間無法達到資源池上限,則考慮是否存在排隊異常。
2)查詢作業負載檢視(813以下版本)
813及以上版本建議使用上邊方法確認是否有排隊異常,當然也可以使用以下方法確認存在排隊異常,排除特性BUG影響。
813以下版本僅有pg_session_wlmstat檢視,沒有pgxc檢視,可通過以下語句建立臨時pgxc檢視:
CREATE OR REPLACE VIEW pgxc_session_wlmstat_tp AS SELECT * FROM pg_catalog.pgxc_parallel_query('cn', 'SELECT pg_catalog.pgxc_node_str(), * FROM pg_catalog.pg_session_wlmstat') AS ( nodename name, datid oid, datname name, threadid bigint, processid integer, usesysid oid, appname text, usename name, priority bigint, attribute text, block_time bigint, elapsed_time bigint, total_cpu_time bigint, cpu_skew_percent integer, statement_mem integer, active_points integer, dop_value integer, control_group text, status text, enqueue text, resource_pool name, query text, is_plana boolean, node_group text, lane text );
查詢叢集內各資源池在所有CN上的作業執行、排隊統計資訊:
select resource_pool,attribute,lane,status,enqueue,sum(statement_mem) as stmt_mem,count(1) from pgxc_session_wlmstat where status!='finished' and attribute!='Internal' and usename!='Ruby' group by 1,2,3,4,5;
通過該查詢可以直觀的觀察各資源池作業負載資訊,如果資源池running作業並行、記憶體長時間無法達到資源池上限,則考慮是否存在排隊異常。
確認是否存在排隊異常
如果經過前兩個步驟分析,懷疑可能存在排隊異常,可能的原因有以下幾種: