Cache-aside для PostgreSQL и Redis

При cache-aside для Redis приложение находится между чтением и авторитетным хранилищем. При промахе оно читает PostgreSQL, возвращает значение и записывает его в Redis; при записи обновляет PostgreSQL и инвалидирует соответствующий ключ Redis. В руководстве по паттерну Redis описан этот поток, но он не делает кэш приложения транзакционно согласованным с PostgreSQL.

Для строки с ключом public.items.id схема выглядит так:

GET item:42
miss -> SELECT * FROM public.items WHERE id = $1
     -> SET item:42 <serialized row> EX <ttl>
write -> UPDATE public.items ...
      -> COMMIT
      -> DEL item:42

Используйте параметризованный SQL и пространство имён ключей. TTL ограничивает время, в течение которого сохранённое значение остаётся в Redis; он не доказывает свежесть относительно коммита PostgreSQL. Явное удаление обрабатывает обычные записи, но не устраняет каждую гонку.

Гонка инвалидации

Рассмотрим два запроса. Читатель R1 не находит ключ в Redis и читает старую строку из PostgreSQL. Записывающий сеанс W фиксирует новую строку и удаляет item:42. Затем R1 продолжает работу и сохраняет старое значение в Redis. Следующий читатель видит устаревшие данные, пока этот ключ не истечёт или другая запись его не удалит.

Возможные меры включают повторное удаление после завершения загрузчика, хранение версии базы данных и отклонение старых значений, сериализацию загрузок по ключу или публикацию зафиксированных изменений через outbox либо потребитель CDC. Каждая мера добавляет координацию и новые случаи отказа. В руководстве по инвалидации кэша показана аналогичная проблема позднего заполнения внутри PostgreSQL.

Где находится pg_local_cache

pg_local_cache — более узкий вариант внутри PostgreSQL для целых строк, адресуемых первичным ключом. local_cache.mget вызывается явно; обычный SELECT и произвольная форма запроса не читают кэш. Триггеры подключённых таблиц ограждают затронутые ключи или отношения на пути записи в базу, а подходящие чтения могут перейти к PostgreSQL, если правила транзакций или снимка запрещают попадание в кэш. Начните с руководства по пакетному чтению и технического контракта.

Это расширение не обеспечивает общую совместимость с Redis, TTL Redis или распределённый протокол кэша приложения. Его необязательная конечная точка RESP2 предоставляет ограниченный аутентифицированный набор команд через те же сопоставления и имеет собственную модель безопасности; TLS отсутствует. Используйте её, когда проблема — транзакционно согласованные чтения целых строк внутри PostgreSQL. Используйте Redis, когда нескольким экземплярам приложения нужны общие объекты, свежесть по TTL или структуры данных Redis. При совместном использовании нужны отдельные ключи, инвалидация и метрики для каждого слоя.

Запустите quickstart, сравните с обычным запросом клиента в примере node-postgres и изучите отдельные счётчики SQL и RESP. В руководстве по выбору кэширования перечислены другие варианты PostgreSQL.

Обновлено .