When Postgres Isn't the Process That Kills Your Database

saisrirampur1 pts0 comments

. -->

What else runs on your Postgres server, and how do we stop it from taking the database down? | ClickHouse<br>Skip to content

Open searchOpen region selectorEnglish<br>Japanese<br>Korean<br>Chinese<br>French<br>Spanish<br>Portuguese<br>Arabic

49.4kSign inGet Started

->Scroll to top<br>BackBlog<br>Engineering<br>Copy pageCopied!More actionsView as Markdown Open this page in Markdown<br>Open in ChatGPT Ask questions about this page<br>Open in Claude Ask questions about this page<br>Open in v0 Ask questions about this page

What else runs on your Postgres server, and how do we stop it from taking the database down?

Kaushik Iska<br>Aug 21, 2026 · 6 minutes read

What else is running on your Postgres server's VM, and what stops it from taking the database down? Alongside Postgres, ours runs several PgBouncer instances, a backup agent, metrics exporters, a local Prometheus, a log collector, and a handful of watchdog timers. Each process protects the database. Each can also leak memory, burn CPU, or fill a disk.

That places every one of them inside the database's failure model. A monitoring process can consume the memory Postgres needs. A backup agent can saturate the CPUs serving queries. Either failure can bring down the whole instance.

A shared machine is shared memory #

Postgres gets one unusually strong boundary. Its shared_buffers allocation lives in huge pages reserved at boot, so another process cannot slowly eat into it. We described why we make that allocation strict in our post on reserving huge pages for Postgres.

Postgres also needs memory outside shared_buffers. The kernel's page cache, each backend's working memory, connection state, and plenty of smaller allocations come from the same machine-wide pool used by PgBouncer, WAL-G, Prometheus, exporters, and logging. A leak in any one of those processes can consume the headroom every database backend depends on.

ClickHouse Managed Postgres gives the supporting processes explicit resource limits. Four Go services, Prometheus, the WAL-G backup agent, postgres_exporter, and node_exporter—run in one cgroup v2 slice. The systemd MemoryHigh and MemoryMax properties write the slice's memory.high and memory.max controls. Each service also carries a GOMEMLIMIT sized so the individual Go heap budgets add up below memory.high.

Runtime and cgroup enforcement #

The boundaries do different jobs:

BoundaryWhat it doesWhy it existsGOMEMLIMITMakes the Go runtime collect more aggressively as its heap approaches its configured target.Heap growth increases GC frequency before the cgroup reaches kernel-enforced thresholds.memory.highForces direct reclaim and throttles allocations charged to the cgroup.Pressure is applied to the processes responsible for the cgroup's memory usage.memory.maxSets the hard cgroup ceiling; if reclaim cannot reduce usage, the kernel raises an OOM event in that cgroup.OOM victim selection is scoped to processes charged to the supporting-services cgroup.

GOMEMLIMIT is deliberately the first line of defense. Go can react with much more context than the kernel: it knows what is heap, what is live, and when another garbage-collection cycle might help. A service approaching its budget does more collection work and usually stays inside the line on its own.

GOMEMLIMIT remains a runtime target. Native allocations, retained objects, or a genuine leak can carry a process past it. The cgroup supplies kernel enforcement: charges above memory.high enter reclaim and throttling.

Charges that cannot be reclaimed below memory.max trigger a cgroup OOM event.

Postgres memory is charged to a separate cgroup, so a memory.max event in the supporting-services cgroup does not select a Postgres process.

The slice's allowance is the same headroom that our strict-overcommit policy sets aside on top of Postgres's share. The commit budget reserves the memory; the cgroup holds the processes to it. The two controls describe the same capacity from opposite directions.

Budgets across every resource #

A process can behave perfectly in heap usage and still hurt the database somewhere else, so the same discipline extends across the VM:

Backups run at a fraction of the default CPU weight, so foreground database work wins when the machine is busy.

WAL-G's buffers are a fixed fraction of RAM, keeping memory use bounded as workload grows.

The log collector has its own memory limiter, keeping a burst of logs from becoming a second incident.

Metrics leaving the box are hand-picked, so a new label cannot quietly create an unbounded cardinality bill in memory, CPU, and network traffic.

Each resource now has an enforcement point: scheduler weight for CPU, fixed buffer sizing and cgroups for memory, local thresholds for disk, and an allowlist for exported metric series.

Disk-full session exemptions #

Postgres needs free disk to make progress, and a full data volume can quickly turn an ordinary workload into an availability incident. At the emergency threshold, the disk-full watchdog terminates sessions...

memory postgres cgroup database process from

Related Articles