ITPub博客

首页 > 数据库 > PostgreSQL > 数据库教程FGMT64-PostgreSQL运维诊断之操作系统分析

数据库教程FGMT64-PostgreSQL运维诊断之操作系统分析

原创 PostgreSQL 作者:mfkqwyc86 时间:2026-10-21 11:23:51 0 删除 编辑

 数据库教程FGMT64-PostgreSQL运维诊断之操作系统分析


## 前言与内容大纲


风哥做数据库运维这十几年,处理过的生产故障成千上万,有一个结论越到后期越坚定:**PostgreSQL出问题,第一现场往往不在数据库内部,而在它脚下的操作系统**。业务方催着回滚、监控曲线变红、应用报500,这些表象背后,真正的原因常常是CPU排队长、内存被吃光、磁盘刷不进去、网卡丢包、文件句柄耗尽、内核参数不对。这些操作系统层面的异常,会一层一层压到PostgreSQL进程上,最后表现为SQL慢、检查点抖、WAL落盘延迟、流复制断连、乃至主进程被OOM Killer直接干掉。


本套风哥教程属于PostgreSQL Operating System Analysis and Diagnosis方向,本文风哥教程本文要解决的目标很具体:不依赖任何商业监控软件,仅靠Linux自带工具和proc文件接口,建立一条从"全局指标"到"进程调用栈"再到"内核参数"的自上而下诊断链路,快速判断性能问题到底出在CPU、内存、磁盘IO、网络还是内核配置,并给出可落地的排查步骤和优化动作。


本文结构安排:第一部分是理论基础,讲透Linux性能观测的"指标—栈—火焰图"方法论,以及CPU、内存、磁盘IO、网络四大子系统的运行原理,重点剖析PostgreSQL的WAL刷盘、bgwriter、checkpointer、autovacuum、流复制等后台进程对操作系统资源的具体诉求。第二部分是实战操作,基于两台主机fgedu-net-cn1(主库)和fgedu-net-cn2(备库)搭建的单机主备PostgreSQL环境(64GB内存、8颗CPU核心,数据目录/fgedudb/pgdata、WAL目录/fgedudb/pg_wal、实例名fgedudb、数据库用户fgedu),逐条演示top、vmstat、mpstat、pidstat、iostat、iotop、sar、ss、tcpdump、lsof、proc文件系统的真实输出和字段解读,并穿插四个生产级故障案例。第三部分是风哥针对本文总结,把全文提炼成一套可直接照搬的生产诊断清单。


---


## 第一部分 理论基础


### 1.1 性能诊断三支柱方法论


风哥做操作系统诊断,始终遵循业界公认的**指标、栈、火焰图**三支柱模型,这是Netflix性能工程师Brendan Gregg总结的方法论,也是风哥处理疑难杂症的兜底框架。


**支柱一:指标(Metrics)**。指标是可量化、可长期对比的数字,比如CPU利用率、运行队列长度、可用内存、IO等待时间、网卡吞吐、TCP重传率。指标解决"是否异常"和"何时异常"的问题——同一台机器业务高峰和低谷的CPU差距、昨天和今天的上下文切换对比、上线变更前后的IO延迟差异,都必须靠指标说话。Linux的指标来源高度统一:`/proc`下的`stat`、`meminfo`、`diskstats`、`net/dev`等虚拟文件,sysfs的`/sys`,以及基于它们的procps、sysstat工具套件。风哥反复强调,**没有基线就没有诊断**,指标的第一价值是建立基线。


**支柱二:栈(Stacks)**。指标告诉你"CPU很忙",栈告诉你"CPU忙在哪里"。通过perf、ftrace、eBPF/bpftrace采集进程的内核态和用户态调用栈,能精确看到进程是卡在`io_schedule`等磁盘、卡在`futex_wait`等锁、还是卡在`schedule`排队等CPU。这是从"症状"走向"根因"的关键一步。


**支柱三:火焰图(Flame Graph)**。火焰图是把成千上万份调用栈按宽度聚合的可视化产物,横轴宽度代表CPU时间占比,哪个函数最宽瓶颈就在哪。风哥在生产上遇到说不清的疑难杂症,最终都要落一张火焰图才能拍板结论。


本文实战以支柱一(指标)为主,并在案例中演示支柱二(栈)的基本用法;火焰图风哥计划在FGMT后续系列单独展开。


### 1.2 四大子系统与PostgreSQL的耦合


风哥习惯把操作系统资源拆成四大子系统,每个子系统都和PostgreSQL有明确、强烈的耦合关系:


**CPU子系统**。PostgreSQL是多进程架构,每一个客户端连接由Postmaster主进程fork出一个独立操作系统进程。一个中等规模OLTP实例,进程数几百到上千,全部参与内核CFS调度。CPU瓶颈的典型特征是:用户态CPU(us)高说明计算密集,要查SQL;内核态CPU(sy)高说明系统调用和上下文切换过多,要查连接数、锁、软中断分布。


**内存子系统**。PostgreSQL通过`shared_buffers`参数直接向操作系统申请一大块共享匿名内存(按64GB内存规格通常配16~24GB),剩余物理内存绝大部分被内核用作页缓存(page cache),缓冲数据文件和WAL文件。新手最容易踩坑的点是误解`free`的`buff/cache`——那是内核主动拿空闲内存做缓存,不是泄漏,需要时立刻可回收。真正要警惕的是Swap换入换出、OOM Killer日志和透明大页THP。


**磁盘IO子系统**。PostgreSQL的WAL在每次事务提交时都要`fsync`强制落盘,是典型的同步IO;数据文件则通过page cache异步回写,由bgwriter和checkpointer负责。因此磁盘诊断必须把WAL设备的写延迟(同步、延迟敏感)和数据设备的吞吐(异步、带宽敏感)分开看。


**网络子系统**。PostgreSQL每接受一个TCP连接就fork一个进程,长连接加连接池配置不当,极易出现TIME_WAIT堆积、SYN半连接队列溢出、网卡软中断集中在某个核。主备流复制对网络延迟极敏感,WAL Sender与Receiver之间一抖,复制延迟立刻体现在`pg_stat_replication`的`write_lag`、`flush_lag`、`replay_lag`字段上。


(风哥 itpux-com)


### 1.3 CPU子系统要点


**用户态与内核态**。`top`的`us`是用户态CPU(应用计算),`sy`是内核态(系统调用、中断、缺页),`id`空闲,`wa`是IO等待,`st`是虚拟机被偷走的时间。风哥的经验阈值:`us`长期高于70%是应用计算密集;`sy`长期高于30%要怀疑系统调用或切换过多;`wa`持续高于10%且伴随IO指标异常,优先查磁盘。


**运行队列(run queue)**。`vmstat`的`r`列是处于Runnable状态的进程数,它们都在等CPU。经验判断:`r`值超过CPU核数的2~3倍(本文8核即16~24),说明CPU已饱和,进程在排队。


**上下文切换**。分自愿切换(进程主动让出,如等IO、等锁)和非自愿切换(时间片被抢走)。`pidstat -w`可查看。非自愿切换暴涨通常是CPU紧张;自愿切换暴涨通常是锁竞争或频繁IO等待。


**NUMA**。8核以上x86服务器多为NUMA架构,内存分属不同节点,跨节点访问要过互联总线、延迟翻倍。PostgreSQL的共享内存若被调度到远端NUMA节点,性能明显下降。生产环境对数据库进程建议`numactl --interleave=all`或关闭NUMA balancing。


### 1.4 内存子系统要点


**页缓存(page cache)**。所有文件读写都经page cache。PostgreSQL数据文件是普通文件,读写大量走page cache。`free`的`buff/cache`不是"被占用的内存",是"可回收的缓存"。真正该看的是`available`列——它估算在不触发Swap前提下新进程能拿到的内存。


**匿名页**。进程堆、栈以及PostgreSQL的`shared_buffers`都是匿名页,不能直接丢弃,内存紧张时只能换入Swap。


**Swap与swappiness**。数据库服务器上Swap是双刃剑:全关Swap,内存突发打满可能直接OOM杀掉Postgres主进程;开大Swap又会因换页延迟(毫秒到秒级)导致进程卡顿。主流做法是保留1~4GB Swap,并把`vm.swappiness`压到1,让内核在万不得已时才用Swap。


**透明大页THP**。内核试图把4KB小页合并成2MB大页以减少TLB miss,但PostgreSQL这种大量短生命周期进程、频繁内存分配的场景,THP的合并拆分会造成毫秒级甚至秒级卡顿,也就是Z名的"THP stall"。生产数据库必须关闭THP。


**OOM Killer**。内存严重不足时,内核按oom_score(内存占用加运行时长加权)挑进程杀掉。PostgreSQL的shared_buffers动辄十几GB,天然是oom_score最高的进程,一旦OOM,主进程被秒杀,实例整体宕机。


(风哥教程 113257174)


### 1.5 磁盘IO子系统要点


**IO栈**。一次写IO路径:应用write()→page cache→脏页比例超阈值触发回写→块层请求队列→IO调度器合并→设备驱动→磁盘。WAL写入因事务提交必须落盘,须走`fsync`绕过page cache直接刷设备。


**关键指标**。`iostat`的`%util`是设备繁忙时间占比,长期超过80%要警惕;`await`是IO平均等待时间,机械盘10~20ms、SSD 0.5~2ms,WAL设备await超过5ms就要排查;`rkB/s`和`wkB/s`是吞吐;`r/s`和`w/s`是IOPS。


**IO调度器**。RHEL 8以上默认`mq-deadline`或`none`(NVMe设备)。数据库服务器:SSD/NVMe建议`none`或`mq-deadline`,机械盘用`mq-deadline`。


### 1.6 网络子系统要点


**backlog队列**。内核有两个队列:SYN半连接队列(`tcp_max_syn_backlog`)和accept全连接队列(`somaxconn`)。应用accept不及时,全连接队列满,新连接被拒或丢包。生产建议`net.core.somaxconn`调到4096以上。


**TIME_WAIT**。主动关闭方让连接停留60秒(2MSL)。高并发短连接下TIME_WAIT可堆积数十万,占用socket和端口。建议开启`net.ipv4.tcp_tw_reuse=1`,注意不是tw_recycle,后者在NAT场景下有坑。


**网卡多队列与RPS**。多核机器上网卡硬中断默认集中在一个核,导致该核softirq打满。多队列网卡加RSS可分散中断;不支持多队列时用RPS把收包软件分发到其他核。


### 1.7 工具与子系统对应图谱


风哥按子系统把诊断工具梳理成一张索引,方便对照查阅:


- 全局总览:`top`、`htop`、`glances`

- CPU:`vmstat`、`mpstat -P ALL`、`pidstat -u`、`uptime`、`/proc/stat`

- 内存:`free -m`、`vmstat`、`/proc/meminfo`、`pidstat -r`、`pmap -d`

- 磁盘IO:`iostat -xmt`、`iotop -oP`、`pidstat -d`、`/proc/diskstats`

- 网络:`ss -s`、`ss -tanp`、`sar -n DEV`、`sar -n TCP,ETCP`、`tcpdump`、`nstat`

- 进程:`ps -efLf`、`pstree`、`lsof -p`、`strace -p`

- 内核与日志:`dmesg -T`、`/var/log/messages`、`sar`历史库


(风哥数据库教程 itpux-com)


---


## 第二部分 实战操作


### 2.1 环境说明与基线采集


风哥的实战环境是两台主机:


- fgedu-net-cn1:主库,64GB内存、8颗CPU核心,RHEL系列操作系统,数据目录/fgedudb/pgdata,WAL目录/fgedudb/pg_wal,实例名fgedudb,超级用户fgedu,监听5432端口。

- fgedu-net-cn2:备库,同规格硬件,通过流复制从fgedu-net-cn1拉取WAL。


风哥做诊断的**第一步永远是采集基线**。没有基线,一切"异常"都只是感觉。建议在业务低峰期先落一份完整快照:


```

mkdir -p /fgedudb/diag/baseline

cd /fgedudb/diag/baseline


vmstat 1 60 > vmstat.baseline.txt 2>&1 &

mpstat -P ALL 1 60 > mpstat.baseline.txt 2>&1 &

iostat -xmt 1 60 > iostat.baseline.txt 2>&1 &

sar -n DEV 1 60 > sar-dev.baseline.txt 2>&1 &

free -m > free.baseline.txt

cat /proc/meminfo > meminfo.baseline.txt

lscpu > lscpu.baseline.txt

```


60秒后后台任务自动结束,快照落盘。今后任何时刻再遇异常,用相同命令复采,和基线逐项对比。


同时,风哥强烈建议生产环境提前装好并开启sysstat的sar定时采集:


```

yum install -y sysstat

systemctl enable sysstat

systemctl start sysstat

grep -v '^#' /etc/cron.d/sysstat

```


sar历史数据存于`/var/log/sa/`,默认保留28天。故障后用`sar -f /var/log/sa/saXX -u`可回放任意历史时刻的CPU、磁盘、网络,是事后定位最重要的数据源。


### 2.2 CPU子系统诊断实战


#### 2.2.1 top:第一眼的全局视图


在fgedu-net-cn1执行:


```

top -c -P

```


输出关键区段:


```

top - 14:23:01 up 35 days,  2:18,  2 users,  load average: 8.20, 6.15, 4.30

%Cpu(s): 65.3 us,  5.2 sy,  0.0 ni, 28.8 id,  0.3 wa,  0.0 hi,  0.4 si,  0.0 st

MiB Mem :  64321.0 total,   1234.0 free,  32145.0 used,  30942.0 buff/cache

MiB Swap:      4.0 total,      0.0 free,      4.0 used.  31000.0 avail Mem

```


风哥逐行解读:


- `load average: 8.20, 6.15, 4.30`:1/5/15分钟平均负载。8核机器1分钟负载8.2,接近满载但未饱和;若长期超过16(核数乘2),进程已严重排队。

- `%Cpu(s): 65.3 us`:用户态65%,主要是PostgreSQL进程在算。

- `5.2 sy`:内核态5%,正常;超过30%要查系统调用。

- `28.8 id`:空闲28.8%,未到瓶颈。

- `0.3 wa`:IO等待0.3%,磁盘通畅。

- `0.4 si`:软中断0.4%,网络收包正常。


进程列表按`P`键按CPU降序排列:


```

PID   USER      PR  NI    VIRT    RES  %CPU  %MEM     TIME+ S COMMAND

12345 fgedu     20   0   32.5g   1.2g 120.0   1.9  380:21.34 R postgres: fgedudb fgedu 10.0.0.10(54321) SELECT

12346 fgedu     20   0   32.5g   0.9g  85.0   1.4  220:11.02 R postgres: fgedudb fgedu 10.0.0.11(54322) UPDATE

```


风哥提示一个PostgreSQL特有读法:COMMAND列`postgres: fgedudb fgedu 10.0.0.10(54321) SELECT`的格式是`postgres: 实例名 用户名 客户端地址(端口) 语句类型`,可一眼定位到是哪个客户端、哪类SQL在吃CPU。


#### 2.2.2 vmstat:一句话诊断


```

vmstat 1 10

```


```

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----

 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

 3  0      0 1234560 23456 30456789    0    0    12   345  1234  5678 65  5 29  1  0

```


关键字段:


- `r=3`:运行队列3个,远低于8核,CPU未饱和。

- `b=0`:无阻塞在IO的进程。

- `si/so=0`:无Swap换入换出,内存健康。

- `in=1234`:每秒中断数。

- `cs=5678`:每秒上下文切换。8核机器若长期超过3万,要警惕连接过多或锁竞争。

- `us/sy/id/wa`与top对应。


(网上搜索风哥教程可以学习全套数据库教程)


#### 2.2.3 mpstat:看每个核的分布


```

mpstat -P ALL 1 5

```


把CPU0到CPU7逐个列出。风哥重点看两点:一是有没有某个核`%soft`特别高(网卡中断集中);二是有没有某个核100%而其他核空闲(进程绑定或NUMA局部性)。这种"不均"往往指向具体根因。


#### 2.2.4 pidstat:按进程下钻


```

pidstat -u -p ALL 1 10 | grep -E "fgedu|Linux"

```


列出每个进程的`%usr`、`%system`、`%CPU`。风哥用它确认top里高CPU进程是持续占用还是瞬时毛刺。


#### 2.2.5 案例一:CPU飙高的完整定位


**现象**:fgedu-net-cn1业务高峰期`load average`飙到25,应用普遍查询超时。


**排查步骤**:


第一步,`top -c`按P排序,发现3个postgres进程各吃80%到120% CPU,COMMAND列显示`postgres: fgedudb fgedu 10.0.0.20(...) SELECT`。


第二步,进库查活动SQL:


```

SELECT pid, now() - query_start AS dur, query

FROM pg_stat_activity

WHERE state = 'active'

ORDER BY dur DESC;

```


发现是几条返回数百万行的顺序扫描大查询。


第三步,`vmstat 1`看到`cs`飙到每秒4万,说明大查询在CFS调度下频繁切换。


第四步,`mpstat -P ALL 1`看到8个核基本均匀跑满,排除单核或中断问题。


**结论**:CPU飙高是SQL问题而非操作系统问题。后续建索引、改写SQL、加statement_timeout解决。风哥强调:操作系统诊断不是给数据库背锅,而是快速分清"是数据库慢还是操作系统慢"。


### 2.3 内存子系统诊断实战


#### 2.3.1 free正确解读


```

free -m

```


```

               total        used        free      shared  buff/cache   available

Mem:           64321       32145        1234        2048       30942       31000

Swap:              4           0           4

```


风哥逐列讲:


- `used=32145`:被进程真实占用,其中约20GB是shared_buffers,其余是连接进程、work_mem、操作系统本身。

- `free=1234`:真正空闲物理页很少,正常,Linux刻意把空闲内存用作cache。

- `buff/cache=30942`:页缓存加块缓存,需要时立刻可回收。

- `available=31000`:**最有意义的数字**,估算不触发Swap前提下新应用可拿到的内存。64GB机器还余31GB,内存完全够用。


#### 2.3.2 /proc/meminfo关键项


```

cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|Dirty|Writeback|AnonPages|Shmem|HugePages_Total|HugePages_Free"

```


风哥重点关注:`Dirty`(脏页,超过20GB要警惕回写压力)、`Writeback`(正在回写的页)、`AnonPages`(匿名页总量)、`HugePages_Total`(若用大页在此看预留量)。


#### 2.3.3 Swap与OOM排查


内存类最凶险故障是OOM Killer杀掉PostgreSQL主进程。排查路径:


```

dmesg -T | grep -i -E "oom|killed process"

```


典型OOM日志:


```

[Fri Oct 17 10:23:11 2026] Out of memory: Kill process 12345 (postgres) score 950 or sacrifice child

[Fri Oct 17 10:23:11 2026] Killed process 12345 (postgres) total-vm:33GB, anon-rss:18GB, file-rss:0

```


一旦出现,顺藤摸瓜查内存为何突然打满,常见原因:


1. 某大查询`work_mem`过大,并发排序时每个连接吃几百MB;

2. 连接突然涌入,各连接栈加私有内存累加打满;

3. `shared_buffers`超过物理内存40%,page cache不足,内核开始回收匿名页触发换页;

4. THP未关,合并过程瞬时内存暴涨。


风哥针对64GB内存PostgreSQL实例的推荐配置:


```

# postgresql.conf 关键参数

shared_buffers = '16GB'

effective_cache_size = '48GB'

work_mem = '64MB'

maintenance_work_mem = '1GB'

wal_buffers = '64MB'

max_connections = '500'

```


(上51CTO搜索风哥可以学习全套数据库教程)


#### 2.3.4 关闭透明大页THP


```

cat /sys/kernel/mm/transparent_hugepage/enabled

echo never > /sys/kernel/mm/transparent_hugepage/enabled

echo never > /sys/kernel/mm/transparent_hugepage/defrag

```


第一行通常输出`[always] madvise never`,临时关闭后必须变成`[never]`。Y久关闭要写入rc.local或tuned profile。


#### 2.3.5 案例二:OOM Killer杀主进程


**现象**:fgedu-net-cn1凌晨3点自动重启,PostgreSQL实例宕机。


**排查过程**:


第一步,`dmesg -T | grep oom`发现凌晨2:58有一次OOM,被杀的正是Postmaster主进程(PID 12345),anon-rss 18GB。


第二步,查`/var/log/messages`,发现凌晨2:50有个批量数据清理任务在跑,同时开了20个连接执行DELETE。


第三步,查`pg_stat_activity`历史和pg_stat_statements,发现这些DELETE触发大量排序和哈希。


第四步,进一步查`pg_settings`发现`work_mem`被某会话临时改成512MB,20个并发连接同时做大哈希聚合,瞬时吃掉10GB以上。


**结论**:非shared_buffers配置问题,而是批量任务work_mem失控。修复:限制批量任务并发、对该会话单独设合理work_mem、打开`log_min_duration_statement`和`log_temp_files`便于监控。


### 2.4 磁盘IO子系统诊断实战


#### 2.4.1 iostat详解


```

iostat -xmt 1 5

```


```

Device            r/s     w/s     rkB/s    wkB/s  await  %util

sda               1.00   50.00     20.00  4096.00   3.50   25.00

sdb              10.00  200.00    200.00  8192.00  15.20   85.00

```


字段解读:


- `r/s`、`w/s`:每秒读写IO次数(IOPS)。

- `rkB/s`、`wkB/s`:读写吞吐。

- `await`:IO平均等待。sdb的15ms对SSD偏高、对机械盘正常。

- `%util`:设备繁忙时间占比,85%已近瓶颈。


风哥判断规则:WAL设备(本文/fgedudb/pg_wal对应sdb)await长期超过5ms且%util超过80%,优先查WAL刷盘是否成瓶颈。


#### 2.4.2 iotop:按进程看IO


```

iotop -oP

```


`-o`只显示正在产生IO的进程,`-P`显示进程而非线程。PostgreSQL场景常见高IO进程:`postgres: writer process`(bgwriter)、`postgres: checkpointer process`、`postgres: wal writer process`、`postgres: autovacuum launcher`、以及用户连接`postgres: fgedudb fgedu ... COPY`或`... CREATE INDEX`。


#### 2.4.3 pidstat -d


```

pidstat -d 1 10

```


与iotop类似,输出更适合脚本化采集和落盘。


#### 2.4.4 案例三:WAL刷盘延迟导致提交变慢


**现象**:fgedu-net-cn1业务高峰期事务提交从2ms飙到30ms,应用批量超时。


**排查**:


第一步,`iostat -xmt 1`发现WAL所在sdb的`await=25ms`、`%util=95%`。


第二步,`iotop -oP`看到`wal writer process`每秒写入约20MB,但设备IOPS已到1500。


第三步,`sar -f /var/log/sa/sa17 -d`回看前一天同时段,await只有1.5ms,说明WAL设备本身没坏,是写入量上来了。


第四步,查`pg_stat_bgwriter`的`buffers_checkpoint`和`buffers_clean`异常高,说明checkpointer频繁刷脏页;再查`pg_stat_activity`发现一张大表在做全表更新,产生了大量WAL。


**结论**:不是磁盘损坏,是批量更新任务把WAL刷盘打满。优化:批量更新拆成每批1万行小批次、错开业务高峰、WAL设备换成NVMe。


(风哥 itpux-com)


### 2.5 网络子系统诊断实战


#### 2.5.1 ss命令


`netstat`已过时,风哥统一推荐`ss`:


```

ss -s

ss -tanp | grep 5432

ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn

```


会看到`ESTAB`、`TIME-WAIT`、`FIN-WAIT-2`、`SYN-RECV`等状态。风哥经验值:


- `TIME-WAIT`超过2万要开`tcp_tw_reuse`。

- `SYN-RECV`超过100要怀疑半连接队列溢出。

- `ESTAB`超过`max_connections`的80%要预警。


#### 2.5.2 sar网络指标


```

sar -n DEV 1 10

```


看各网卡`rxkB/s`、`txkB/s`、`rxpck/s`、`txpck/s`、`ifutil`。万兆网卡`ifutil`长期超过70%要考虑绑bond或升级。


```

sar -n TCP,ETCP 1 10

```


`retrans/s`占总发包比例超过0.5%就要查网络质量。


#### 2.5.3 内核参数调优


风哥针对64GB/8CPU数据库服务器的`/etc/sysctl.conf`推荐:


```

net.core.somaxconn = 4096

net.core.netdev_max_backlog = 8192

net.ipv4.tcp_max_syn_backlog = 8192

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_fin_timeout = 15

net.ipv4.ip_local_port_range = 1024 65535

fs.file-max = 1048576

fs.nr_open = 1048576

vm.overcommit_memory = 2

vm.overcommit_ratio = 90

vm.swappiness = 1

vm.dirty_ratio = 5

vm.dirty_background_ratio = 2

```


同时修改`/etc/security/limits.conf`:


```

fgedu  soft  nofile  65535

fgedu  hard  nofile  65535

fgedu  soft  nproc   65535

fgedu  hard  nproc   65535

fgedu  soft  core    unlimited

fgedu  hard  core    unlimited

```


#### 2.5.4 案例四:连接打满与backlog溢出


**现象**:应用报"too many clients already",但`max_connections=500`、`pg_stat_activity`活跃连接仅300。


**排查**:


第一步,`ss -tan | grep 5432 | wc -l`看到1200个socket,大量处于`SYN-RECV`和`TIME-WAIT`。


第二步,`dmesg -T | grep -i "syn\|listen"`看到`TCP: request_sock_TCP: Possible SYN flooding on port 5432`。


第三步,`netstat -s | grep -i "listen\|overflow"`发现`ListenOverflows`和`ListenDrops`持续增长。


**结论**:内核`somaxconn`默认128,PostgreSQL监听socket backlog被限在128以内,高峰连接建立速度超过accept速度,全连接队列溢出。修复:`net.core.somaxconn`调到4096,并让postgresql.conf的`max_connections`与连接池(pgbouncer)配置匹配。


(风哥教程 113257174)


### 2.6 综合诊断:一键采集脚本


风哥生产经验:**接到故障电话的第一时间,先跑一键采集脚本把现场快照落盘,再慢慢分析**。故障现场稍纵即逝,事后往往已恢复、无从查证。


脚本路径/fgedudb/diag/collect.sh,采集项清单如下(思路可直接照搬):


```

#!/bin/bash

# 风哥操作系统诊断一键采集脚本

# 用法:bash collect.sh /fgedudb/diag/incident_$(date +%Y%m%d_%H%M)


OUT=$1

mkdir -p $OUT


# 1. 系统基本信息

uname -a > $OUT/uname.txt

uptime > $OUT/uptime.txt

lscpu > $OUT/lscpu.txt

cat /proc/meminfo > $OUT/meminfo.txt


# 2. CPU

top -b -n 1 > $OUT/top.1.txt

vmstat 1 30 > $OUT/vmstat.30.txt

mpstat -P ALL 1 10 > $OUT/mpstat.txt

pidstat -u 1 10 > $OUT/pidstat.u.txt


# 3. 内存

free -m > $OUT/free.txt

pidstat -r 1 10 > $OUT/pidstat.r.txt


# 4. 磁盘IO

iostat -xmt 1 10 > $OUT/iostat.txt

pidstat -d 1 10 > $OUT/pidstat.d.txt


# 5. 网络

ss -s > $OUT/ss.s.txt

ss -tanp > $OUT/ss.tanp.txt

sar -n DEV 1 5 > $OUT/sar.dev.txt

sar -n TCP,ETCP 1 5 > $OUT/sar.tcp.txt


# 6. 进程与PostgreSQL

ps -efLf | grep -E "postgres|fgedu" | grep -v grep > $OUT/ps.postgres.txt

pstree -p > $OUT/pstree.txt


# 7. 日志

dmesg -T > $OUT/dmesg.txt

tail -500 /var/log/messages > $OUT/messages.tail.txt


# 8. PostgreSQL内部

su - fgedu -c "psql -c 'SELECT * FROM pg_stat_activity;' fgedudb" > $OUT/pg_stat_activity.txt

su - fgedu -c "psql -c 'SELECT * FROM pg_stat_bgwriter;' fgedudb" > $OUT/pg_stat_bgwriter.txt

su - fgedu -c "psql -c 'SELECT * FROM pg_stat_replication;' fgedudb" > $OUT/pg_stat_replication.txt


echo "采集完成:$OUT"

```


脚本约跑30秒,把关键现场数据落盘打包留档。生产环境强烈建议在监控告警触发时自动调用。


(风哥数据库教程 itpux-com)


### 2.7 sar历史数据回放


很多问题不是"正在发生",而是"昨天下午3点卡了10分钟",实时抓不到,要靠sar历史回放。


```

sar -f /var/log/sa/sa17 -u

sar -f /var/log/sa/sa17 -d

sar -f /var/log/sa/sa17 -n DEV

sar -f /var/log/sa/sa17 -u -s 14:00:00 -e 15:00:00

```


风哥习惯:拿到故障报告,先`sa17 -u`看CPU、再`sa17 -d`看IO、再`sa17 -n DEV`看网络,三条线一对,就能锁定异常时间窗内到底是哪个子系统出了问题。


### 2.8 上线自检清单


风哥给出新机器或新实例上线前的逐项自检:


```

# 1. 关闭THP

cat /sys/kernel/mm/transparent_hugepage/enabled

# 必须显示 [never]


# 2. swappiness

cat /proc/sys/vm/swappiness

# 必须 <= 10


# 3. somaxconn

cat /proc/sys/net/core/somaxconn

# 必须 >= 1024


# 4. 文件句柄

ulimit -n

cat /proc/sys/fs/file-nr

# 必须 >= 65535


# 5. 时钟同步

chronyc tracking

# System time offset应在几十ms以内


# 6. 磁盘调度器

cat /sys/block/sdb/queue/scheduler

# SSD建议 [none] 或 [mq-deadline]


# 7. NUMA

numactl --hardware

# NUMA架构建议PostgreSQL启动用 numactl --interleave=all


# 8. 时区与时间

date

timedatectl

# 生产统一用CST(Asia/Shanghai)或UTC

```


(网上搜索风哥教程可以学习全套数据库教程)


---


## 第三部分 风哥针对本文总结


风哥针对本文总结一下:PostgreSQL运维诊断之操作系统分析,本质是一套"自上而下、由外到内"的排查方法论。先看操作系统四大子系统(CPU、内存、磁盘IO、网络)的指标是否异常,再逐层下钻到进程级、SQL级、内核栈级。绝大多数性能故障的第一现场都在操作系统层——CPU饱和、内存打满、IO阻塞、网络丢包——而不是数据库内核本身出了bug。


本文风哥教程本文提炼了三条核心结论:


第一,**先建基线,再谈异常**。没有基线的诊断都是主观感觉。生产必须开启sysstat,低峰期采完整快照,故障时才有对比。


第二,**工具要看懂字段含义,不是跑一遍命令就完事**。`top`的`wa`、`vmstat`的`r`与`cs`、`iostat`的`await`与`%util`、`ss`的`TIME-WAIT`与`SYN-RECV`,每个数字背后都有明确的生产经验阈值,懂得阈值才能判断异常。


第三,**一键采集脚本是救命稻草**。故障现场稍纵即逝,接到告警先落盘再分析。本文给的collect.sh思路可直接拿去改。


最后风哥强调:操作系统诊断不是为了给数据库背锅,而是为了在最短时间内分清"是数据库慢、是操作系统慢、还是网络慢"。分清之后,优化动作才能落在正确的地方——调SQL、调参数、换磁盘、还是加连接池。本套风哥教程后续FGMT系列会继续深入PostgreSQL内部的执行计划、锁、缓冲区、WAL、VACUUM等专题,风哥会把操作系统层和数据库层的诊断串成一条完整的故障处理链路。


(上51CTO搜索风哥可以学习全套数据库教程)


风哥针对本文的实操要求:读者应在自己的fgedu-net-cn1/fgedu-net-cn2实验环境上把本文所有命令完整跑一遍,保存基线快照,此后每次数据库性能波动都用它来对比定位。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9664900/viewspace-3186258/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
风哥Oracle,MySQL,PostgreSQL,Linux,大数据,国产数据库,中间件等教程

注册时间:2010-10-26

  • 博文量
    78
  • 访问量
    406512