Cache-aside without the race

When primary-key reads get hot, the usual move is to put Redis or Valkey next to PostgreSQL and use cache-aside: read the cache, on a miss read PostgreSQL and fill the cache, and delete the key on every write. It works until a read and a write overlap. A reader that missed can fetch the row just before a writer commits; the writer’s DEL arrives first, the reader’s fill arrives second, and the old row stays in the cache until something else removes it. We walked through this late-fill race earlier.

pg_local_cache moves the cache into PostgreSQL itself, so the cache and the writes it must follow live in the same transaction system.

How it stays correct

What it costs and what it buys

These numbers come from 3.1.0 on two 16-vCPU VMs (Xeon Gold 6354, 10 GbE) with PostgreSQL 16 and a Go/pgx client. The benchmark page has every table, the raw JSONL and the reproduction steps.

Reads while writing. 64 readers, one key per read, uniform keys over 60k rows, 30,000 UPDATE/s:

Stack Reads/s Hit ratio Stale entries
pg_local_cache 161,919 0.837 0
Valkey cache-aside 42,294 0.577 0
Prepared SQL 106,949 — —

With unlimited writers, Valkey cache-aside ended with stale entries (1 in the mixed run; 2 and 1 in the 120-second probes). pg_local_cache ended every run with none, including a one-hour soak of 252M MGET and 72M UPDATE.

Write overhead. Throughput relative to plain table writes was 3.6–8.2% lower for UPDATE through pg_local_cache, and 28.9–63.7% lower for UPDATE followed by Valkey DEL.

Read throughput. With the server pinned to one vCPU pair, pg_local_cache served 210k reads/s against 180k for single-threaded Valkey; with two pairs, 337k against 266k for Valkey with I/O threads. At four pairs both reached a client-bound plateau near 360k, with pg_local_cache using 5.2 server vCPU and Valkey 8.0. Single-threaded Valkey used the least CPU per request. Prepared SQL was far behind in the single-key tests.

When it is the wrong tool

Try it

pg_local_cache supports PostgreSQL 14–18 and is MIT-licensed. Install it from the GitHub releases (deb and rpm), PGXN or the Pigsty repositories, then follow the quick start.