Postgres-пулер закрыл дыру, через которую сессия клиента утекает в чужую

Включи PgBouncer в режиме транзакций, и SET, который ты выполнил на одном соединении, может незаметно всплыть в чужом запросе. PgDog предлагает не отказываться от пулера, а перестать молча терять функции Postgres, которые он ломает.

Вкратце

PgDog встроил собственный SQL-парсер: он отслеживает SET, LISTEN/NOTIFY и подготовленные запросы для каждого клиента, восстанавливая их перед каждым запросом — именно то, от чего приходится отказываться в режиме транзакций PgBouncer. По словам Кокотова, год в продакшене на 2 млн запросов в секунду.

Истории из треда подтвердили: цена реальна. Инженер, недавно перенёсший Django-приложение за PgBouncer, обнаружил, что серверные курсоры queryset.iterator() не переживают пулинг, а statement_timeout в параметрах libpq молча игнорируется.

Почему «просто добавить пулер» незаметно меняет работу с Postgres

PgDog от автора PgCat Льва Кокотова начинается с признания, до которого каждая ops-команда доходит на собственном опыте: пулер соединений ведёт себя как протекающая абстракция. Поставь PgBouncer или RDS Proxy перед Postgres, и «ты добавил кусок инфраструктуры, который меняет то, как ты используешь базу данных». Самое неприятное изменение незаметно. Поскольку пулеры переиспользуют соединения между клиентами, состояние, заданное одним клиентом, может проявиться в запросе другого. По словам Кокотова, «состояние соединения одного клиента ‹утекает› в состояние соединения другого».

Хитрость: пулер, который читает твой SQL

Ответ PgDog: перестать считать трафик непрозрачными байтами. Встроенный SQL-парсер замечает SET, сохраняет это состояние для каждого клиента и восстанавливает его через пайплайнинг запросов перед следующим стейтментом, сохраняя возможности вроде Row Level Security, от которых иначе пришлось бы отказаться в транзакционном режиме. LISTEN/NOTIFY, ещё одна жертва транзакционного режима, пересобран внутри на Tokio broadcast-каналах и выделенных соединениях, так что pub/sub работает, не теряя транзакционной семантики. Под капотом пулер многопоточный, а не шардированный по процессам, и, по словам Кокотова, уже больше года работает в продакшене на 2 млн запросов в секунду.

Миграционный налог, о котором никто не предупреждает

Тред заполнился не столько похвалой, сколько шрамами именно от тех утечек, на которые нацелен PgDog. Самая конкретная история пришла от инженера, который за несколько дней до этого перевёл Django-приложение на транзакционный пулинг PgBouncer:

«Сюрпризом оказался не SET, а queryset.iterator(). Он полагается на серверные курсоры, которые не переживают пулинг, так что пришлось отключить его везде... ещё пришлось вынести statement_timeout из настроек соединения приложения в собственный connect-запрос пулера, потому что параметры запуска libpq за ним просто молча игнорируются». — инженер, только что перенёсший Django-приложение

Для тех, кого это ещё не коснулось, шоком стала сама утечка состояния:

«Ого, это очень плохо. Это правда происходит в типичных конфигурациях Postgres?» — инженер по машинному обучению

Даже похвала пришла с оговоркой

Людей убедила не пропускная способность, а подготовленные запросы: стена, из-за которой раньше отпадала очевидная альтернатива.

«Поддержка подготовленных запросов сама по себе делает PgDog убедительным вариантом. Это было ограничением старых версий pgpool-II, из-за которого он не подходил там, где иначе вполне мог бы пригодиться». — инженер, отказавшийся от pgpool-II именно из-за этого пробела

А заявление про pub/sub вызвало единственный по-настоящему скептический вопрос треда:

«Разве это исправление производительности NOTIFY не означает, что оно больше не транзакционное?» — читатель, который надавил на гарантию транзакционности

Одна деталь была принята вообще без оговорок: PgDog выходит под AGPL, и комментатор, уставший от релицензирования под BSL назвал это облегчением: «а не очередным ужасным вариантом BSL, которые сейчас повсюду».

Всё вместе тред читается как настоящее техзадание для продукта. Почти никто не спорил о скорости: люди спрашивали, переживёт ли PgDog именно их частный случай, будь то серверные курсоры, роутинг схема-на-тенанта или транзакционный NOTIFY. Вот где сейчас реальная конкуренция пулеров: не в запросах в секунду, а в том, сколько строк кода приложения можно удалить, взяв пулер на вооружение.

Получайте такие разборы каждый день

Главные истории Hacker News — на email, в Telegram или RSS.

Следующая новость · 27 из 29 Читать дальше
🚀Tech

Инструкция кричит: НЕ ПАРСИ ВРУЧНУЮ. Claude всё равно парсит вручную

Решение — не более удачный промт. Автор оборачивает модель в парсеры, сгенерированные Ragel, и даёт ей самой писать скрипты-страховки на JavaScript: в следующий раз, когда Claude потянется парсить руками, детерминированный инструмент уже сделает эту работу за неё.

★ 106 · 💬 50 · replicated.live · 5 мин