Memory Pressure and OOM Kill
criticalSummary
When total memory demand from a process or the entire host exceeds available physical RAM plus swap, the Linux OOM killer terminates one or more processes to reclaim memory, causing immediate connection loss, data corruption risk if in-flight writes are lost, and process restart overhead.
Description
The Linux OOM (Out-Of-Memory) killer is invoked when the kernel cannot satisfy a memory allocation request from any process and swap space is exhausted. The OOM killer selects a process to terminate based on an oom_score calculation (a function of memory usage, runtime, and /proc/PID/oom_adj). Database processes (PostgreSQL postmaster, Redis, MongoDB mongod) are large memory consumers and are frequently selected as OOM victims.
For PostgreSQL: when the postmaster process is OOM-killed, all client connections are severed immediately. The shared memory segment (shared_buffers) is deallocated. Dirty shared buffer pages that had not been checkpointed to disk are lost: these will be replayed from WAL on restart, but WAL replay may take minutes for a large shared_buffers. All active transactions are rolled back by the crash recovery process. Depending on crash recovery mode, the database may be unavailable for 1–10 minutes.
For Redis: if the Redis process is OOM-killed and persistence is disabled (save "" or appendonly no), all in-memory data is permanently lost. If appendonly yes is configured, the AOF file contains all committed writes but recovery requires replaying it: seconds to minutes depending on AOF size.
Memory pressure scenarios in PostgreSQL: 1. shared_buffers configured too large: shared_buffers = 16GB on a 16GB host
leaves 0GB for OS page cache, sort operations, and other processes.
2. Sort and hash operations exceeding work_mem: a complex query with 10 hash
joins at work_mem = 256MB can allocate 10 × 256MB = 2.5GB for a single query.
Multiply by concurrent queries.
3. Connection count × connection overhead: each PostgreSQL connection uses
5–10MB of memory (stack, local cache). 1,000 connections = 5–10GB.
4. Autovacuum workers with large scale: autovacuum on a very large table
with aggressive settings can consume hundreds of MB per worker.
Memory pressure builds gradually and is often ignored until the OOM event. The first signs are the kernel beginning to reclaim page cache aggressively (free -m shows available memory dropping to near 0) and swap utilisation growing. These are warning signals that OOM is approaching.
Characteristics
Triggers
- ·shared_buffers set to >30% of total RAM without accounting for other memory consumers
- ·work_mem × max_connections × average_concurrent_queries exceeds available RAM
- ·Connection count spike (autoscaling without connection pooling) × per-connection overhead exceeds RAM
- ·Autovacuum workers running concurrently on large tables with high maintenance_work_mem
- ·Application memory leak causing gradual growth until host-level memory exhaustion
Detection Signals
Mitigation Strategies
PostgreSQL recommendation: shared_buffers = 25% of RAM. Leave 75% for OS page cache, work_mem allocations, and other processes. On a 32GB host: shared_buffers = 8GB. This is not the aggressive setting some guides recommend (40–50%): those figures assume the database is the only process on the host.
work_mem × concurrent_complex_queries_per_connection × max_connections must fit within available RAM after shared_buffers. Formula: work_mem = (available_RAM - shared_buffers) / (max_connections × 0.1). For 32GB host with 8GB shared_buffers and 200 connections: work_mem = 24GB / 20 = 1.2GB. Override per-query for known-expensive analytical queries.
Set vm.overcommit_memory = 2 and vm.overcommit_ratio = 80 to prevent the kernel from committing more virtual memory than 80% of physical RAM. Processes that attempt to allocate beyond this will fail at allocation time (ENOMEM) rather than being OOM-killed at access time. PostgreSQL handles this gracefully.
In containerised environments (Kubernetes, Docker), set memory limits for the database container. Redis respects maxmemory configuration. PostgreSQL requires container-level limits combined with shared_buffers tuning. Prevents the database from consuming host memory to the OOM boundary.
Recovery Steps
- 1.Confirm OOM event: check dmesg for OOM killer log entries and identify victim process
- 2.If database process was killed and has not restarted automatically: start the process
- 3.Monitor crash recovery: PostgreSQL will replay WAL from last checkpoint (check logs for progress)
- 4.Reduce memory pressure before reconnecting application: reduce max_connections, reduce shared_buffers if they were the cause
- 5.If Redis was OOM-killed without persistence: application cache is empty; implement thundering herd prevention before re-enabling traffic
- 6.Post-recovery: audit memory configuration against RAM budget and implement memory monitoring with pre-OOM alerting
Estimated recovery time: 30 seconds to 5 minutes for process restart. WAL crash recovery may add 1–10 minutes depending on shared_buffers size and checkpoint age. Redis AOF replay: seconds to minutes. Application connection pool re-establishment: 10–60 seconds.
Affected Systems
Patterns
Technologies
Basis
Precisely specified kernel-level failure mode with observable pre-conditions; PostgreSQL and Redis memory configuration parameters are exact and well-documented
Run This Failure
Blast radius analysis for this failure mode within each scenario that carries it.
Related Architecture Knowledge
Inbound: affects this entity
AI embedding lookup workloads require the entire vector index to reside in RAM for acceptable latency. When the index size grows beyond available memory, the OS begins paging the HNSW graph to disk, causing query latency to degrade from milliseconds to seconds and eventually OOM-killing the process.
Tradeoffs
- ·Quantization reduces memory by 4-8x but degrades recall slightly: evaluate recall impact before deploying
- ·IVFFlat has lower memory than HNSW but requires training (cluster computation) when adding new vectors
- ·Horizontal scaling (shard vectors across instances) reduces per-node memory at the cost of scatter-gather query overhead
Used In Architecture Scenarios
AI / RAG Application
A Retrieval-Augmented Generation (RAG) architecture that combines vector similarity search for semantic document retrieval with relational metadata filtering, using PostgreSQL with pgvector as the unified store for both embeddings and structured data. Redis provides a semantic cache to avoid redundant embedding model inference and reduce vector index query load for repeated or similar queries. Kafka manages the asynchronous embedding generation pipeline that keeps the vector index current as source documents are added or updated.
Realtime Collaboration
A real-time location tracking platform for moving entities: vehicles, delivery couriers, field workers, and assets: receiving position updates at 1–30 second intervals from thousands of simultaneously tracked objects. Redis geospatial indexes (GEOADD / GEOSEARCH) serve sub-10ms proximity queries against the live position surface; PostgreSQL stores durable entity metadata and historical location records; TimescaleDB stores high-frequency time-series location data with automatic hypertable chunking and retention policies; Kafka streams location events to downstream consumers (dispatch systems, customer tracking apps, analytics pipelines). Geofence evaluation runs at ingestion time: each incoming position update is tested against active geofences for the entity's region, and geofence entry/exit events are emitted as Kafka messages to downstream consumers.