PolarDB PostgreSQL版在使用過程中,可能會出現CPU使用率異常升高甚至達到滿載的情況。本文將介紹造成這種情況的常見原因和排查方法,以及對應的解決方案。
問題原因
業務量上漲
當CPU使用率上升時,最有可能的情況是業務量的上漲導致數據庫使用的計算資源增多。
排查方法
需要排查目前數據庫的活躍連接數是否比平時多,您可以通過以下兩種方法進行排查:
如果數據庫配備了監控系統,則活躍連接數的變化情況可以通過圖表的形式觀察到。
如果數據庫沒有配備監控系統,則需要連接到數據庫,執行以下命令來獲取當前活躍連接數。
SELECT COUNT(*) FROM pg_stat_activity WHERE state NOT LIKE 'idle';
說明其中:
pg_stat_activity
是PolarDB PostgreSQL版的內置系統視圖,該視圖返回的每一行都是一個正在運行中的PolarDB PostgreSQL版進程。state
表示進程當前的狀態。取值如下:active
:進程正在執行查詢。idle
:進程空閑,正在等待新的客戶端命令。idle in transaction
:進程處于事務中,但目前暫未執行查詢。idle in transaction (aborted)
:進程處于事務中,且有一條語句發生過錯誤。fastpath function call
:進程正在執行一個fast-path函數。disabled
:進程的狀態采集功能被關閉。
上述命令可以查詢到所有非空閑狀態的進程數,即可能占用CPU的活躍連接數。如果活躍連接數較平時更多,則CPU使用率上升是由于業務量上漲導致。
問題原因
慢查詢
如果CPU使用率上升,而活躍連接數的變化范圍處在正常范圍內,則有可能出現了較多性能較差的慢查詢。這些慢查詢可能在很長一段時間里占用了較多的CPU,導致CPU使用率上升。
PolarDB PostgreSQL版提供了慢查詢日志的功能,執行時間高于log_min_duration_statement
的SQL將會被記錄到慢查詢日志中。然而當CPU占用率接近滿載時,將會導致整個系統的停滯,所有SQL的執行可能都變慢,所以慢查詢日志中記錄的信息可能非常多,不易排查。
排查方法
定位執行時間較長的慢查詢
pg_stat_statements
插件能夠記錄數據庫服務器上所有SQL語句在優化和執行階段的統計信息。
由于該插件需要使用共享內存,因此插件名需要被配置在shared_preload_libraries
參數中。
如果當前數據庫中沒有創建pg_stat_statements
插件,執行以下命令,創建該插件。該過程將會注冊好插件提供的函數及視圖:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
pg_stat_statements
插件和數據庫系統本身都會不斷累積統計信息。為了排查CPU異常升高后這段時間內的問題,需要將數據庫和插件中留存的統計信息清空,然后開始收集從當前時刻開始的統計信息:-- 清空當前數據庫的統計信息 SELECT pg_stat_reset(); -- 清空 pg_stat_statements 插件截止目前收集的統計信息 SELECT pg_stat_statements_reset();
等待1~2分鐘,使數據庫和插件充分采集這段時間內的統計信息。
統計信息收集完畢后,參考以下命令查詢執行時間最長的5條SQL。
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5; SELECT * FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
定位讀取Buffer數量較多的慢查詢
當一張表缺少索引,而對該表的查詢基本上都是點查時,數據庫將不得不使用全表掃描,并在內存中使用過濾條件來過濾掉大量的無效記錄,導致CPU使用率大幅上升。
通過pg_stat_statements
插件的統計信息,參考以下命令,查詢截止目前讀取Buffer數量最多的5條SQL。
SELECT * FROM pg_stat_statements
ORDER BY shared_blks_hit + shared_blks_read DESC
LIMIT 5;
通過PolarDB PostgreSQL版內置系統視圖pg_stat_user_tables
中的統計信息,也可以統計出使用全表掃描時掃描次數最多的表。
參考以下命令,查詢具備一定規模數據量(元組約為10萬個)且使用全表掃描獲取到的元組數量最多的5張表。
SELECT * FROM pg_stat_user_tables
WHERE n_live_tup > 100000 AND seq_scan > 0
ORDER BY seq_tup_read DESC
LIMIT 5;
定位長時間執行不結束的慢查詢
通過系統內置視圖pg_stat_activity
,可以查詢出長時間執行不結束的SQL,這些SQL有極大可能造成CPU使用率過高。
參考以下命令,查詢執行時間最長,且當前還未退出的5條SQL。
SELECT
*,
extract(epoch FROM (NOW() - xact_start)) AS xact_stay,
extract(epoch FROM (NOW() - query_start)) AS query_stay
FROM pg_stat_activity
WHERE state NOT LIKE 'idle%'
ORDER BY query_stay DESC
LIMIT 5;
結合前一步中排查到的使用全表掃描次數最多的表,參考以下命令,獲取在該表上執行時間超過一定閾值(例如10s)的慢查詢。
SELECT * FROM pg_stat_activity
WHERE
state NOT LIKE 'idle%' AND
query ILIKE '%表名%' AND
NOW() - query_start > interval '10s';
解決方案
對于異常占用CPU較高的SQL,如果僅有個別非預期SQL,則可以通過給后端進程發送信號的方式,先讓SQL執行中斷,使CPU使用率恢復正常。參考以下命令,以慢查詢執行所使用的進程pid(
pg_stat_activity
視圖的pid
列)作為參數,中止相應的進程的執行。SELECT pg_cancel_backend(pid); SELECT pg_terminate_backend(pid);
如果執行較慢的SQL是業務上必要的SQL,則需要對它進行調優。可以對SQL涉及到的表進行采樣,更新其統計信息,使優化器能夠產生更加準確的執行計劃。
說明采樣需要占用一定的CPU,最好在業務低谷期進行。
ANALYZE 表名;
對于全表掃描較多的表,可以在常用的過濾列上創建索引,使用索引掃描,減少全表掃描在內存中過濾不符合條件的記錄所造成的CPU浪費。