ХабрПостыНовостиМегапосты?

Очереди сообщений в Postgres Pro: отказ от внешних брокеров ради транзакционной надёжности

В эпоху распределённых систем, где каждая компонента должна быть не только эффективной, но и предсказуемой, вопрос надёжности обмена данными становится критическим. Представьте: пользователь нажимает кнопку «Сгенерировать отчёт», и в этот момент должны синхронизироваться десятки процессов — от создания документа до его отправки по email. Но что если почтовый сервер временно недоступен? Или обработчик задач падает, не завершив операцию? Именно здесь на сцену выходят очередь сообщений — механизм, который превращает хаотичные запросы в управляемый поток, гарантируя, что ни одна задача не потеряется в пути.

История создания расширения встроенных очередей в PostgreSQL началась с простой боли: внешние брокеры вроде RabbitMQ или Kafka, хотя и мощные, добавляли слои сложности. Управление ими требует выделенных ресурсов: отдельные серверы, настройка кластеров, мониторинг доступности. В enterprise-среде, где системы развертываются тысячами экземпляров, каждый новый компонент увеличивает риски и административную нагрузку.

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

Два подхода к очередям: Log-based и AMQP/JMS

В мире распределенных систем сформировались два подхода к обработке сообщений:

  1. Log-based-очереди (например, Kafka). Работают как непрерывный журнал событий. Данные записываются строго последовательно, и потребители читают их в том же порядке. Это идеально для синхронизации данных между микросервисами или репликации баз данных. Однако их сила — в линейности — становится слабостью, когда нужна гибкость: выборка сообщений по приоритету или фильтрам здесь невозможна.

  2. AMQP/JMS-брокеры (например, RabbitMQ). Позволяют не просто передавать сообщения, но и управлять их жизненным циклом: устанавливать приоритеты, фильтровать по условиям, обрабатывать ошибки. Такие очереди позволяют имитировать асинхронное RPC, где задача может быть повторена при сбоях. Но их главная слабость — фундаментальная проблема, общая для любого внешнего брокера, включая Kafka: невозможно гарантировать транзакционную целостность с базой данных.

Проблемы внешних брокеров: транзакционность и сложность

Использование внешних брокеров, таких как Kafka или RabbitMQ, в enterprise-средах часто сопряжено со скрытыми сложностями:

Postgres Pro Enterprise Queues: транзакционность и автоматизация с pgpro_queue

Новое расширение pgpro_queue — это ответ на «боль» разработчиков, уставших бороться с рассогласованием данных. Интеграция очередей непосредственно в СУБД устраняет необходимость во внешних компонентах. Сообщения хранятся в обычных таблицах, реплицируются через стандартные механизмы PostgreSQL и участвуют в тех же транзакциях, что и бизнес-логика приложения.

Установка и настройка

Интеграция pgpro_queue начинается с простых шагов, знакомых любому DBA:

  1. Добавление в shared_preload_libraries. В файле postgresql.conf необходимо добавить расширение в список предварительно загружаемых библиотек:

    shared_preload_libraries = 'pgpro_queue'
  2. Создание расширения. В нужной базе данных выполняется команда:

    CREATE EXTENSION pgpro_queue;
  3. Инициализация. Для хранения служебных объектов (таблиц метаданных, очередей) создаётся отдельная схема pgpro_queue_data. Это делается с помощью функции:

    SELECT queue_initialize();

    Такое разделение обеспечивает корректную работу pg_dump и репликации.

Ключевые возможности и их реализация

1. Retry-on-rollback (автоматический повтор при откате).
Это главная особенность pgpro_queue. Если транзакция, в которой было прочитано сообщение, откатывается (например, из-за недоступности внешнего сервиса), сообщение не теряется, а автоматически возвращается в очередь для повторной обработки.

2. Фильтрация и приоритеты.
pgpro_queue позволяет гибко управлять потоком сообщений:

3. Поддержка форматов JSON и XML.
Расширение предоставляет отдельные функции для работы с разными форматами данных, что упрощает интеграцию с различными системами:

4. Отложенная обработка.
При вставке сообщения можно указать параметр q_msg_enable_time, чтобы задача стала доступна для обработки только при наступлении указанного времени.

Что мы положили под капот?

В основе расширения pgpro_queue лежит простой и надёжный принцип: сообщения хранятся в обычных таблицах PostgreSQL. Такой подход позволяет использовать всю мощь стандартных механизмов СУБД, включая репликацию и восстановление через WAL-файлы. Каждое сообщение, попавшее в очередь, записывается в WAL, что гарантирует его восстановление даже после аварийного отключения сервера. Ключевая особенность pgpro_queue — это глубокая интеграция с транзакционной моделью PostgreSQL, реализующая механизм retry-on-rollback. Он работает как страховка: если транзакция, обработавшая сообщение, откатывается из-за любой ошибки, pgpro_queue автоматически возвращает это сообщение в очередь для повторной попытки. Это гарантирует, что задача будет считаться выполненной только тогда, когда вся связанная с ней работа успешно зафиксирована в базе данных.

Ещё одна сильная сторона pgpro_queue — синергия со встроенным в Postgres Pro Enterprise планировщиком фоновых задач (Scheduler). Этот компонент, работающий как cron внутри базы данных, может запускать периодические родительские задачи, которые, в свою очередь, наполняют очередь подзадачами для асинхронного выполнения. Например, массовую генерацию отчётов для клиентов из разных часовых поясов можно разбить на этапы: основная задача в планировщике создаёт подзадачи для каждого региона, а те, в свою очередь, помещают сообщения в очередь с учётом локального времени.

Внешние брокеры, такие как Kafka, справедливо славятся своей «непотопляемостью»: они действительно спроектированы выдерживать серьёзные сбои. Однако эта надёжность относится к самому брокеру в изоляции. В реальной системе слабое звено появляется в точках интеграции, и общая стабильность оказывается зависима от внешних факторов: сети, конфигурации, транзакционной согласованности с базой данных. Но pgpro_queue исключает эти риски: очереди живут в той же экосистеме, что и данные приложения. Сообщения не теряются при сбоях, так как их сохранность гарантируется механизмами репликации и восстановления СУБД. Администраторам больше не нужно настраивать отдельные системы мониторинга для очередей: всё управляется через знакомые инструменты PostgreSQL.

Важные технические особенности

Для корректной работы с pgpro_queue специалистам следует учитывать несколько моментов:

Что ждет встроенные очереди: дорожная карта

Развитие pgpro_queue сфокусировано на расширении сценариев использования. Уже в ближайших версиях появятся две ключевые возможности:

  1. Система подписок (Pub/Sub). Будет реализован механизм, аналогичный Exchange в RabbitMQ. Продюсер сможет отправлять сообщение в «тему», а не в конкретную очередь. Все потребители, подписанные на эту тему, получат свою копию сообщения. Это открывает путь к созданию полноценных событийно-ориентированных архитектур.

  2. Callback-уведомления. Появится возможность настроить «обратный вызов» — HTTP-запрос к внешнему сервису при появлении сообщения в очереди. Это позволит СУБД самой инициировать обработку, а не ждать, пока приложение опросит очередь.

Функциональность Dead Letter Queue (DLQ) для «отравленных» сообщений также остаётся в планах, но на более долгосрочную перспективу.

Заключение

Для корпоративных клиентов ключевое преимущество — предсказуемость. Каждое сообщение обрабатывается в рамках транзакций СУБД, что исключает рассогласование данных. Инфраструктура становится проще: вместо набора разнородных сервисов — единая база данных, где очереди, бизнес-логика и планировщик работают как части одного организма.

Такие решения идеальны для проектов, где цена ошибки высока: банковские транзакции, медицинские системы, государственные реестры. Если вашему приложению критически важны атомарность операций и минимизация ручного вмешательства, встроенные очереди PostgreSQL — не выбор, а необходимость. Они не просто обрабатывают сообщения, а становятся страховкой от хаоса в мире распределённых систем.

@slonik_pg
12.11.2025 20:32 UTC
Первоисточник

Комментарии

@impwx
12.11.2025 16:47 UTC
+10

Есть сравнительные данные о производительности, условно говоря - какое сообщений в секунду потянет kafka, rmq и ваше решение на одинаковом железе?

@Debrainer
12.11.2025 23:13 UTC
+4

Если уж оракл не справляется со своим advanced queue на серьезных нагрузках, то не стоит надеяться что постгрес справится. Для небольших монолитов идущих в сторону распила, но не готовых ввязываться в распределенный блудняк может и подойдёт. Но предел производительности БД очевиден особенно при пиковых вбросах. Делить функциональную основную бизнес нагрузку с нагрузкой по очередям на одном сервере такое себе. А стоимость железа под БД обычно выше чем стоимость железа под кластерные брокеры. Короче есть плюсы, но есть и масса минусов, особенно для растущих по нагрузке баз.

@green_whirlpool
13.11.2025 05:05 UTC
+2

Краткий пересказ статьи: изобрели аналог MS SQL Service Broker для PostgreSQL 😏😏😏

@alexanderfedyukov
13.11.2025 06:38 UTC
-1

Подскажите пожалуйста, какие есть планы на шардирование этих очередей? Будет ли этот функционал только в PostgresPro или появится и в shardman тоже? Какой выбран протокол взаимодействия с очередями?

P.S.: ваш пример в ачале статьи с транзакионным разрывом между брокером и бд некорректен: все зависит от последовательности "коммитов", при правильной последовательности мы таску\сообщение не теряем, но должны быть готовы к обработке дубля. Что может быть дешевле 2pc или просто остается единственным вариантом, когда 2pc не возможен (kafka+db).

13.11.2025 19:56 UTC
0

По расширению функциональности на shardman, всё будет зависеть от потребностей клиентов.

13.11.2025 19:59 UTC
+1

P.S.: ваш пример в ачале статьи с транзакионным разрывом между брокером и бд некорректен: все зависит от последовательности "коммитов", при правильной последовательности мы таску\сообщение не теряем, но должны быть готовы к обработке дубля. Что может быть дешевле 2pc или просто остается единственным вариантом, когда 2pc не возможен (kafka+db).

Суть примера — показать фундаментальный разрыв атомарности между брокером и БД без 2PC: outbox/CDC и «сначала коммит БД, затем публикация» снимают риск потери, но оплачиваются сложностью идемпотентности, дедупликации и возможными повторными доставками. pgpro_queue решает это иначе: сообщение и бизнес‑данные находятся в одной транзакции СУБД, где откат гарантированно возвращает сообщение в очередь, то есть нет разрыва и нет необходимости отдельно проектировать анти‑дубль логику на уровне интеграции.

@XelaVopelk
13.11.2025 06:55 UTC
+1

Рассогласование данных. Представьте сценарий: приложение отправляет сообщение в RabbitMQ и начинает транзакцию в базе данных. Сообщение уже ушло в брокер, но в момент коммита транзакции в БД происходит сбой. Результат — рассогласование:...

А почему взяли заранее калеченый пример? Есть же паттерн outbox, есть cdc (с дебезиум). Почему бы не сравнить с ними?

13.11.2025 08:32 UTC
-2

откровенно говоря само утверждение авторов из профессионального постгреса спорное, есть распределенные (многофазные) транзакции для java чтоб сделать единый комит для базы и очереди, все это стандартизировано было еще лет 20 назад (если не 30) и продавалось заинтересованным лицам, тк проблема очевидная.

а " паттерн outbox, есть cdc (с дебезиум) " это решение что называется "для бедных". второй раз за месяц замечаю что авторы тут словно в танке сидят

@manyakRus
13.11.2025 08:18 UTC
0

1) для этого надо покупать платный Postgres Pro ?

2) есть такие же очереди и для бесплатного PostgreSQL :-)
тоже через расширения устанавливаются.

13.11.2025 19:45 UTC
0

Расширение pgpro_queue является частью Postgres Pro Enterprise. То есть для использования именно этого решения нужна подписка на коммерческий дистрибутив Postgres Pro Enterprise. Оно тесно интегрировано с их механизмами, включает управляемые ретраи на откате и работу с планировщиком задач.

@swa111
13.11.2025 10:13 UTC
0

По описанию внутренне похож на mbus, очередь так же хранится на таблицах. В mbus есть проблема, что при большом объеме (количесвтенном) передаваемых сообщений деградирует скорость чтения сообщений из-за большого числа мертвых записей (т.е. их удалили, но они остались на диске, автовакум не пришел еще или не может выполнить очистку). Как решили подобную проблему?

13.11.2025 19:53 UTC
0

Эта проблема решается стандартными, но целенаправленно настроенными средствами самого PostgreSQL, так как очередь представляет собой обычную таблицу. Предполагается, что для высоконагруженных таблиц-очередей администратор базы данных настроит более агрессивный autovacuum, чтобы минимизировать раздувание таблиц и поддерживать высокую производительность чтения.

@diderevyagin
13.11.2025 10:37 UTC
+1

Для небольшого потока событий в определенных условий (переходный период и так далее) - в принципе можно. А целом - надо все-же использовать выделенные решения типа Kafka.

13.11.2025 19:50 UTC
+1

Вы правы, Kafka незаменима для больших потоков событий, но pgpro_queue решает другую ключевую задачу — обеспечение 100% транзакционной надёжности. В отличие от внешних брокеров, оно гарантирует атомарность операции "задача + данные", полностью исключая риск рассогласования при сбоях. Поэтому для критически важных систем, где цена ошибки высока, это не компромиссное, а стратегически верное решение для упрощения архитектуры и повышения её предсказуемости.

@bigtrot
13.11.2025 15:32 UTC
+2

Можно дождаться фиксации транзакции, выполнить запрос данных и отправить их в брокер, а сам брокер разошлет данные всем подписчикам.

13.11.2025 20:01 UTC
0

Так можно, но это не устраняет транзакционный разрыв между БД и брокером. Последовательность «сначала фиксация БД, затем публикация» с идемпотентностью снижает риск потери, но допускает дубли и требует дополнительной инфраструктуры (outbox/CDC, мониторинг, повторная доставka). В pgpro_queue сообщение и данные живут в одной транзакции: при откате оно автоматически возвращается в очередь, без внешних механизмов согласования.

@eugeneyp
15.11.2025 12:56 UTC
0

А можно расшифровать кто страдает при таком решении? Сервер БД или Java сервер?

Как уже говорили есть есть готовые решения с распределенными транзакциями (там решение основано на двухфазном комитте). Есть паттерны которые нивелируют разрыв транзакций. У них есть готовые решения, известные и описанные проблемы.

Чем ваше решение лучше например запуска JMS брокера в одной JVM с бизнес приложением и пере использованием одной транзакции?

@IgorM23
17.12.2025 16:19 UTC
0

Добрый день!

Скажите, пожалуйста: как создать таблицу для хранения очередей (аналог ораклового dbms_aqadm.create_queue_table)?

В документации написано: "CREATE_QUEUE - Создаёт очередь в существующей таблице очереди".

Эту таблицу нужно заранее создать прямым DDL? Какая структура этой таблицы требуется?

Cпасибо.