Skip to content
EL
Contents

Database reliability engineering

How databases actually go down

ConceptExpert6 min read10 min hands-on#operations#concurrency

The idea in 30 seconds

Reliability starts as a number you agree on: how often the database may be unavailable or slow, how much data you may lose, and how fast you must recover. Most database incidents are not hardware failing but the database doing exactly what it was told: a migration queueing every query behind it, a forgotten transaction stopping cleanup, connections running out. PostgreSQL ships a guard for each, all switched off by default.

Helps to know first: Locks and locking strategies (coming soon), Vacuum, autovacuum and bloat (coming soon), Connection management and pooling (coming soon), Backups, restore and point-in-time recovery (coming soon)

On this page

Reliable means a number

“The database should be reliable” cannot be checked. A target can. Site reliability engineering uses three words for this:

  • SLI, a service level indicator: something you measure, such as the share of queries that finish under 100 ms.
  • SLO, a service level objective: the target for it, such as 99.9% of them over 30 days.
  • SLA, a service level agreement: a contract with consequences if you miss.

For a database, four indicators cover most of what users feel:

IndicatorQuestion it answersTypical way to state it
AvailabilityCan the application connect and run queries?Share of minutes with successful health queries
LatencyAre queries fast enough?99th percentile of key queries under a threshold
RPO, recovery point objectiveHow much committed data may we lose in a disaster?“At most 5 minutes of writes”
RTO, recovery time objectiveHow long may recovery take?“Back in service within 1 hour”

The SRE book is blunt that 100% is the wrong target: it is unrealistic, and chasing it stops you from ever changing anything. The gap between the target and 100% is an error budget: the amount of failure you can spend on deploys, migrations and experiments.

RPO and RTO are the two people forget until they are needed. They are promises about backups and failover, and a promise you have never tested is a guess.

Most incidents are self-inflicted

Disks and servers do fail, and replication and backups exist for that. But the incidents a team actually lives through are mostly the database doing exactly what it was asked:

  • A migration waits for a lock, and every query behind it waits too.
  • A forgotten transaction stays open for hours, and vacuum cannot clean up anything newer than it.
  • Connections run out because each app instance opened its own pool.
  • A runaway query reads a whole table every few seconds.

None of these crash PostgreSQL. They make it unavailable to the application while it is perfectly healthy.

The lock queue

Locks are granted in order. A plain SELECT takes the weakest table lock, ACCESS SHARE, which conflicts with only one mode: ACCESS EXCLUSIVE, the lock many forms of ALTER TABLE take. So a migration that adds a column needs, for a moment, the table to itself.

PredictOne slow report, one tiny migration

A report has been reading the orders table for 20 seconds and holds its lock until it finishes. A migration runs ALTER TABLE orders ADD COLUMN note text, which on its own takes under a millisecond. One second later, five normal application queries run SELECT count(*) FROM orders on a 12-row table. How long do those five queries take?

The guards, all off by default

PostgreSQL has a timeout for each of these failures. Every one defaults to zero, meaning “wait forever”:

SettingStopsEnds
lock_timeoutA statement waiting too long for a lockThe statement
statement_timeoutA statement running too longThe statement
idle_in_transaction_session_timeoutA transaction left open with nobody using itThe session
transaction_timeout (PostgreSQL 17+)Any transaction lasting too long overallThe session

The documentation recommends against setting most of these in postgresql.conf, because they would apply to every session, including the backup and the maintenance jobs that legitimately run for hours. Set them per role instead, where each kind of work has a sensible limit:

ALTER ROLE app        SET statement_timeout = '5s';
ALTER ROLE app        SET idle_in_transaction_session_timeout = '30s';
ALTER ROLE migrations SET lock_timeout = '2s';
ALTER ROLE reporting  SET statement_timeout = '5min';

Each new session of that role starts with those values. A migration with lock_timeout = '2s' fails after two seconds instead of holding the queue for as long as the slowest query; it can then be retried. You will measure the difference in the lab.

Check yourself

  1. Why is “99.99% available” not by itself a complete database reliability target?

    Show answer

    It says nothing about data loss or recovery. A database can be available almost all the time and still lose six hours of data in a disaster. RPO and RTO cover that, and they only mean something if restores and failovers are tested.

  2. In the lock queue experiment, which session actually blocked the five reads, and why?

    Show answer

    The migration. It was waiting for an ACCESS EXCLUSIVE lock, which conflicts with the reads’ ACCESS SHARE lock, and it was ahead of them in the queue. The report alone would not have blocked them.

  3. Why set statement_timeout with ALTER ROLE rather than in postgresql.conf?

    Show answer

    A server-wide value applies to every session, including backups, vacuum jobs and reports that legitimately run long. Per-role values let the application have a tight limit while other kinds of work get limits that suit them.

Finished reading?

Saved in this browser only.

Sources

Where each claim on this page comes from.

  1. 1.
    Site Reliability Engineering, Chapter 4: Service Level Objectives
    ReferenceChris Jones, John Wilkes, Niall Murphy, Cody Smith (Google)· Chapter 4: Service Level Terminology; Defining Objectives

    Definitions of SLI, SLO and SLA; insisting on meeting an SLO 100% of the time is unrealistic and undesirable; error budgets.

  2. 2.
    Postmortem of database outage of January 31
    SecondaryGitLab· Broken recovery procedures; Data loss impact

    A wrong command deleted about 300 GB on the primary; the pg_dump backups had been failing silently because of a 9.2/9.6 version mismatch and their failure emails were rejected; about six hours of data were lost and recovery took over 18 hours.

  3. 3.
    PostgreSQL documentation: 13.3 Explicit Locking
    Primary· §13.3.1 Table-Level Locks: ACCESS EXCLUSIVE

    ACCESS EXCLUSIVE conflicts with every other lock mode and is the only mode that blocks a plain SELECT; many forms of ALTER TABLE take it.

  4. 4.
    PostgreSQL documentation: 9.27 System Information Functions and Operators
    Primary· §9.27.1 Session Information Functions: pg_blocking_pids

    A process is blocked both by locks held (hard block) and by conflicting lock requests ahead of it in the wait queue (soft block).

  5. 5.
    PostgreSQL documentation: 19.11 Client Connection Defaults
    Primary· §19.11.1 Statement Behavior

    statement_timeout, lock_timeout, idle_in_transaction_session_timeout and transaction_timeout all default to zero (disabled); setting statement_timeout, lock_timeout or transaction_timeout in postgresql.conf is not recommended; an open idle transaction prevents vacuum removing recently-dead rows.

  6. 6.
    PostgreSQL documentation: ALTER ROLE
    Primary· Description

    ALTER ROLE ... SET makes a value the session default for every new session of that role.

  7. 7.
    PostgreSQL documentation: Release 17
    Primary· Changes: Server Configuration

    transaction_timeout was added in PostgreSQL 17.

Go further

What to read next, and why it is worth the time.

  1. 1.
    Site Reliability Engineering, Chapter 4: Service Level Objectives
    ReferenceChris Jones, John Wilkes, Niall Murphy, Cody Smith (Google)

    The clearest short explanation of SLIs, SLOs and error budgets. Read it before setting any database target.

  2. 2.
    Database Reliability Engineering
    ReferenceLaine Campbell, Charity Majors· Chapter 2, Service-Level Management· O'Reilly Media, 2017· location not yet verified

    The book-length treatment of running databases as an engineering discipline, written for people who already know the basics.

Applies to PostgreSQL 18. Draft: not yet fact-checked end to end.