Skip to main content
RunBook Academy

PostgreSQLXVI · Observability, Logging and AlertingObservability

Correlating PostgreSQL evidence with the operating system

Intermediate⏱ ~30 minpsqlps

What you'll learn

  • Join a backend to its operating system process and back
  • Choose the OS instrument that matches the wait event class
  • Avoid the memory-accounting mistakes shared memory causes
  • Sample two instruments closely enough to compare them

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

PostgreSQL knows what it is waiting for. The operating system knows what the machine is doing. Neither is sufficient, and joining them is one column.

The join

Read-only / Safefour active backends and what they are waiting on
$ SELECT pid, state, wait_event_type, wait_event, left(query,32) AS query
FROM pg_stat_activity WHERE backend_type='client backend' AND state='active' LIMIT 4;
 pid | state  | wait_event_type |  wait_event   |              query
-----+--------+-----------------+---------------+----------------------------------
880 | active | LWLock          | WALWrite      | END;
881 | active | Lock            | transactionid | UPDATE pgbench_branches SET bbal
882 | active | IO              | WalSync       | END;
883 | active | LWLock          | LockManager   | UPDATE pgbench_branches SET bbal
Read-only / Safethe same pids in the operating system
$ ps -o pid,stat,time,rss,vsz,comm -p 880,881,882,883
    PID STAT     TIME   RSS    VSZ COMMAND
  880 Ss   00:00:00 70800 229688 postgres
  881 Ds   00:00:00 66188 229708 postgres
  882 Ss   00:00:00 69132 229708 postgres
  883 Ss   00:00:00 71720 229688 postgres
Read-only / Safeand /proc, for one of them
$ grep -E '^(VmRSS|Threads|voluntary_ctxt|nonvoluntary_ctxt)' /proc/880/status
VmRSS:	   70800 kB
Threads:	1
voluntary_ctxt_switches:	6657
nonvoluntary_ctxt_switches:	22

Threads: 1 — one thread per backend, the process model from Part I, seen from the other side.

Choosing the OS instrument from the wait event

The wait event class tells you which OS tool will have something to say:

Wait event classLook atWith
IO/DataFileReadDisk read latency and queue depthiostat -x 1, biolatency
IO/WalSyncfsync latencyiostat -x 1, pg_test_fsync
LWLockCPU and context switchestop, vmstat 1, /proc/PID/status
LockNothing in the OS. Application contentionPart IX
ClientNetwork and the applicationss -tn, application logs
NULL (running)CPU saturationtop, mpstat, perf

That mapping saves the most common wasted hour in database troubleshooting: reaching for iostat when the wait events say Lock. The disk is not the problem, has never been the problem, and will look fine no matter how long you stare at it.

The system-level numbers that matter

vmstat 1 5            # r, b, si, so, us, sy, wa
iostat -x 1 5         # r_await, w_await, %util, aqu-sz
free -m               # and the caveat below
ss -s                 # connection counts and states
df -h /var/lib/postgresql /var/lib/postgresql/*/main/pg_wal

The ones worth knowing by heart:

  • vmstat si/so non-zero — swapping. Lesson XI-06.
  • vmstat b — processes blocked on I/O.
  • vmstat wa — CPU time waiting on I/O.
  • iostat r_await/w_await — per-request latency. The number that corresponds to IO/* wait events.
  • df on pg_wal separately — lesson XII-03’s outage.

What to take from this

  • pg_stat_activity.pid is the OS pid. That is the whole join.
  • Two instruments sampled microseconds apart need not agree. Sample close together and profile rather than snapshot.
  • Let the wait event class choose the OS tool. Lock means the OS has nothing to say.
  • Know vmstat si/so/b/wa and iostat r_await/w_await.
  • Never sum RSS across backendsshared_buffers is counted in each. Measured: 728 MB of RSS over 128 MB of buffers.
  • Inside a container, free reports the host. Read the cgroup files.
  • Capture before you fix. The best evidence exists only while the problem does.

Cross-course references

  • Linux for Production Sysadmins — Part XXXVIII (Linux performance fundamentals), Part XL (Memory Performance) and Part XLI (Storage Performance) cover the host-side instruments this lesson pairs with the database’s own.
  • Observability for Production Sysadmins — Part LI (Correlating metrics, logs, and traces) and Part LVI (Linux observability) cover putting both on one timeline, which is what makes the correlation an argument rather than a coincidence.
  • Docker & Containers — Part XV (Resource controls) covers why host figures and container figures disagree, and which one the OOM killer uses.

Quiz

Knowledge check · 6 questions

  1. Q1. A monitoring system sums RSS across all PostgreSQL backends and reports 40 GB used on a host with 32 GB of RAM. What is wrong?

  2. Q2. Wait-event sampling shows the backends are overwhelmingly on Lock waits. Which operating system tool will help?

  3. Q3. Inside a container, free -m reports 47 GB available on a cluster limited to 2 GB. Why, and what should be read instead?

  4. Q4. Which evidence exists only while an incident is happening? Select all that apply.

  5. Q5. PostgreSQL reporting a Lock wait while ps shows the same process in state D is evidence that the two views are inconsistent.

  6. Q6. Why should capturing evidence precede fixing during a database incident, and what should be captured?

Passing score: 75%. Answers are checked in this browser.