抽丝剥茧丨PostgreSQL 系国产数据库%SYS CPU newfstatat() high 调优一例(一)

发布于:2025-08-16 ⋅ 阅读:(13) ⋅ 点赞:(0)

最近一个客户从 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

优化策略

  1. 减少checkpoint频率:增加checkpoint_timeout和max_wal_size

  2. 平滑checkpoint I/O:提高checkpoint_completion_target

  3. 平衡恢复时间:确保max_wal_size不会导致恢复时间过长

  4. 监控调整:根据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年,是业界领先的“智能的数据技术提供商”。公司以“数据驱动,成就未来”为使命,致力于将创新的数据技术产品和解决方案带给全球的企业和组织,帮助客户构建安全、高效、敏捷且经济的数据环境,持续增强客户在数据洞察和决策上的竞争优势,实现数据驱动的业务创新和升级发展。

自成立以来,云和恩墨专注于数据技术领域,根据不断变化的市场需求,创新研发了系列软件产品,涵盖数据库、数据库存储、数据库管理和数据智能等领域。这些产品已经在集团型、大中型、高成长型客户以及行业云场景中得到广泛应用,证明了我们的技术和商业竞争力,展现了公司在数据技术端到端解决方案方面的优势。

图片


网站公告

今日签到

点亮在社区的每一天
去签到