最近一個客戶從 Oracle 遷移到?PostgreSQL?系的國產數據庫后,CPU一直接近100%,但是再仔細分析,發現%system CPU占到60%左右,當然這是一種不正常的現象。之前我寫過《如何在 Linux 上診斷高%Sys CPU》(https://www.anbob.com/archives/6730.html),使用pidstat確認%sys cpu進程大部分為?PostgreSQL?進程,pstack查看發現call,PostgreSQL 的線程大部分時間都在調用newfstatat()
,這不是正常現象,并且通常意味著數據庫運行中存在頻繁的文件狀態檢查(stat)操作,嚴重時可能導致性能瓶頸。
什么是 newfstatat()?
ENMOTECH
newfstatat()是 Linux 的系統調用,用于檢查文件狀態,類似stat()
、lstat()
等。PostgreSQL 在以下場景中可能頻繁調用newfstatat()
:
判斷WAL文件是否存在或過期;
檢查relation文件(如表、索引文件);
目錄掃描(如
pg_tblspc、
pg_wal、
pg_stat_tmp
等);檢查文件是否存在或大小變化(特別是在歸檔、WAL回放、恢復或重啟點期間;
后臺進程(如checkpointer、walwriter、autovacuum、archiver)可能周期性遍歷文件。
特別是在WAL寫入或checkpoint過程中,PostgreSQL 會頻繁檢查pg_wal
目錄中的文件狀態。頻繁調用它通常表示 PostgreSQL 正在不斷訪問某些文件或目錄的元信息.
如何分析排查?
ENMOTECH
sys% CPU高存在2種情況,常見是系統級配置,還有一種是局部會話級。當看到CPU高,部分人是想著趕緊優化SQL,但是進數據庫發現活動用戶進程并非多高并發,其次一些較差的應用使用DB總有優化不完的TOP SQL。如果沒有成本可以讓你的DBA或乙方廠家在優化SQL上面折騰,或找應用廠家自查,但都效果微乎其微。首先應該定位CPU使用類型與觸發點。
vmstat或top查看sys/user CPU占比;
明確范圍,使用pidstat查找進程,pstack調用堆棧,strace跟蹤函數的調用位置;
perf做系統級負載分析。
如本案例分析到是newfsatat()函數,能猜到是FS文件系統相關,再查看文件系統負載。
使用iostat查看負載,發現數據盤繁忙近100%,根據之前的負載壓測基線數據,大概可以判斷是否達到了硬件磁盤的IOPS或吞吐量上限,使用iotop找I/O高的進程。
優化調整
ENMOTECH
通過上面的排查,發現是I/O方面問題,并且主要進程為checkpoint進程,下面可以在系統級做一些調優,PostgreSQL?本地文件文件確實較多,但inode使用不到10%,之前我記錄過《Linux最佳實踐for Postgresql/openGauss》(https://www.anbob.com/archives/6970.html)在文件系統級有提到,調整文件系統的noatime nodirtime禁用訪問時間,可以在線調整,我們調整完后%SYS CPU有明顯降低,但是I/O繁忙率依舊比較高。
Checkpoint是 PostgreSQL 中重要的后臺進程,負責將共享緩沖區中的臟頁寫入磁盤,并確保事務日志(WAL)的一致性。優化參數主要有:
checkpoint_timeout增加此值可減少checkpoint頻率;
max_wal_size控制兩次checkpoint之間允許的WAL最大大小;
min_wal_size WAL文件回收時的最小保留大小,應與max_wal_size配合調整;
checkpoint_completion_target控制在checkpoint_timeout內完成checkpoint的目標比例。
監控Checkpoint性能
SELECT?*?FROM?pg_stat_bgwriter;SELECT? checkpoints_timed,?? checkpoints_req,??100.0?*?checkpoints_req?/?(checkpoints_timed?+?checkpoints_req)?AS?req_checkpoint_ratio,? buffers_checkpoint,? buffers_cleanFROM?pg_stat_bgwriter;
關注以下指標:
checkpoints_timed – 定時觸發的checkpoint
checkpoints_req – 因WAL增長觸發的checkpoint
buffers_checkpoint – checkpoint寫入的緩沖區數量
buffers_clean- 后臺寫入器清理的緩沖區數量
req_checkpoint_ratio<10%(請求式checkpoint占比低),checkpoint應由超時觸發(
checkpoints_timed),而非WAL寫滿觸發,尤其是>30%應該增加WAL
優化策略
減少checkpoint頻率:增加checkpoint_timeout和max_wal_size
平滑checkpoint I/O:提高checkpoint_completion_target
平衡恢復時間:確保max_wal_size不會導致恢復時間過長
監控調整:根據pg_stat_bgwriter結果持續優化
-- 增加checkpoint間隔(默認5min,可增至15-30min)ALTER?SYSTEM?SET?checkpoint_timeout?=?'30min';-- 允許更多WAL積累(默認1GB,根據磁盤空間調整)ALTER?SYSTEM?SET?max_wal_size?=?'8GB';-- 使checkpoint寫入更分散(默認0.5,建議0.7-0.9)ALTER?SYSTEM?SET?checkpoint_completion_target?=?0.9;
查看 WAL 文件統計
COUNT(*)?AS?total_wal_files,??SUM(size)?/?1024?/?1024?AS?total_size_mb,? (SELECT?setting?FROM?pg_settings?WHERE?name?=?'max_wal_size')?AS?max_wal_sizeFROM?pg_ls_waldir();
檢查 WAL 生成速率
SELECT?? pg_wal_lsn_diff(pg_current_wal_lsn(),?'0/0')?/?1024?/?1024?AS?total_wal_mb,? (SELECT?(sum(blks_hit)+sum(blks_read))?FROM?pg_stat_database)?AS?total_io,? (SELECT?extract(epoch?from?now()?-?pg_postmaster_start_time())?/?3600?AS?hours_up);
優化高 WAL 生成的查詢
SELECT?query, wal_bytes?FROM?pg_stat_statements?ORDER?BY?wal_bytes?DESC?LIMIT?10;
如果太多WAL文件/頻繁checkpoint,提高max_wal_size,降低checkpoint_timeout,提高checkpoint_completion_targetj.我們把max_wal_size從20G調到400G后,明顯磁盤的使用率降了下來。
檢查relation文件
除了WAL清理外,還有可能是檢查relation文件是否存在時觸發newfsatat,下面測試:
-- session 1select?pg_backend_pid();-- session 2?strace?-p xxx?-o s2.o-- session 1select?big query....
創建了一個大分區表,確認有多個relation文件,然后在執行此表的關聯查詢,另一個會話使用strace跟蹤,后面查看newfsatat函數。發現newfsatat調用次數與表數據的文件個數并不成正比,而當join時有調用newfsatat.
# awk -F"(" '{print $1}' s2.o|sort|uniq -c|sort -nk 1? ? ??1?fallocate? ? ??1?ftruncate? ? ??1?mmap? ? ??1?munmap? ? ??2?epoll_pwait? ? ??2?kill? ? ??2?newfstatat? ? ??2?rt_sigprocmask? ? ??3?recvfrom? ? ??3?--- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, si_pid=2024915, si_uid=1000} ---? ? ??3?--- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, si_pid=2024916, si_uid=1000} ---? ? ??3?unlinkat? ? ??4?--- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, si_pid=394857, si_uid=1000} ---? ? ?10?rt_sigreturn? ??521?brk? ??628?sendto? ??761?pread64? ??763?pwrite64??17138?openat??17139?close??18042?lseek# grep newfstatat s2.onewfstatat(AT_FDCWD,?"base/pgsql_tmp/pgsql_tmp1981697.8", {st_mode=S_IFREG|0600, st_size=2211840, ...},?0) =?0newfstatat(AT_FDCWD,?"base/pgsql_tmp/pgsql_tmp1981697.7", {st_mode=S_IFREG|0600, st_size=1810432, ...},?0) =?0
NOTE:使用newfstatat函數檢查的是查詢過程中的pgsql_tmp臨時文件,接下來可以考慮優化SQL減少temp或調DB參數。
總結
ENMOTECH
出現newfstatat()
占用大量調用棧,不是bug,而是 PostgreSQL 或操作系統層面在頻繁獲取文件元信息。但它很可能是以下問題的表現癥狀:
WAL寫入壓力大
Checkpoint頻繁
歸檔問題
文件系統性能差
查詢產生大量的中間temp文件
數據驅動,成就未來,云和恩墨,不負所托!
云和恩墨創立于2011年,是業界領先的“智能的數據技術提供商”。公司以“數據驅動,成就未來”為使命,致力于將創新的數據技術產品和解決方案帶給全球的企業和組織,幫助客戶構建安全、高效、敏捷且經濟的數據環境,持續增強客戶在數據洞察和決策上的競爭優勢,實現數據驅動的業務創新和升級發展。
自成立以來,云和恩墨專注于數據技術領域,根據不斷變化的市場需求,創新研發了系列軟件產品,涵蓋數據庫、數據庫存儲、數據庫管理和數據智能等領域。這些產品已經在集團型、大中型、高成長型客戶以及行業云場景中得到廣泛應用,證明了我們的技術和商業競爭力,展現了公司在數據技術端到端解決方案方面的優勢。