Cache-aside без гонки: кэш строк внутри PostgreSQL

Когда чтения по первичному ключу становятся частыми, обычно рядом с PostgreSQL разворачивают Redis или Valkey и используют cache-aside: сначала читают кэш, при промахе читают PostgreSQL и заполняют кэш, а после каждой записи удаляют ключ. Всё работает, пока чтение и запись не пересекаются. Читатель, не нашедший ключ, может получить строку прямо перед коммитом писателя; DEL писателя приходит первым, заполнение читателя — следом, и старая строка остаётся в кэше, пока её что-нибудь не удалит. Ранее мы разбирали эту гонку позднего заполнения.

pg_local_cache переносит кэш внутрь PostgreSQL, поэтому кэш и записи, за которыми он должен следить, работают в одной транзакционной системе.

Как обеспечивается корректность

Затраты и преимущества

Эти цифры получены на версии 3.1.0 на двух виртуальных машинах с 16 vCPU (Xeon Gold 6354, 10 GbE), PostgreSQL 16 и клиентом Go/pgx. На странице бенчмарков приведены все таблицы, исходные файлы JSONL и шаги для воспроизведения.

Чтения при записи. 64 читателя, один ключ на чтение, равномерное распределение по 60k строк, 30,000 UPDATE/с:

Стек Чтений/с Доля попаданий Устаревшие записи
pg_local_cache 161,919 0.837 0
Valkey cache-aside 42,294 0.577 0
Подготовленный SQL 106,949 — —

При неограниченном числе писателей cache-aside на Valkey завершился с устаревшими записями (1 в смешанном прогоне; 2 и 1 в 120-секундных проверках). Во всех прогонах pg_local_cache завершал работу без них, в том числе после часовой проверки с 252M MGET и 72M UPDATE.

Накладные расходы на запись. Относительно обычной записи в таблицу пропускная способность UPDATE через pg_local_cache была ниже на 3.6–8.2%, а для UPDATE с последующим DEL в Valkey — на 28.9–63.7%.

Пропускная способность чтения. При ограничении сервера одной парой vCPU pg_local_cache обслуживал 210k чтений/с против 180k у однопоточного Valkey; при двух парах — 337k против 266k у Valkey с потоками ввода-вывода. При четырёх парах обе системы достигали плато около 360k из-за ограничения со стороны клиента; pg_local_cache использовал 5.2 vCPU сервера, Valkey — 8.0. Однопоточный Valkey расходовал меньше всего CPU на запрос. В тестах с одним ключом подготовленный SQL сильно отставал.

Когда это неподходящий инструмент

Попробуйте

pg_local_cache поддерживает PostgreSQL 14–18 и распространяется по лицензии MIT. Установите его из релизов GitHub (deb и rpm), PGXN или репозиториев Pigsty, затем выполните краткое руководство.