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

Сегодня мы, команда платформы данных в Yandex Cloud, хотим рассказать о SPQR — нашем опенсорс‑инструменте, который создавался как ответ на «боль» шардирования и эксплуатации крупных OLTP‑систем. Под катом — история о том, что стало отправной точкой для его создания, какие задачи он помогает решать, на чём основано наше решение и что позволяет ему быть довольно простым в эксплуатации. 

Почему шардирование для PostgreSQL — это боль

PostgreSQL — отличная база данных: популярная, расширяемая. Однако у неё есть фундаментальное ограничение — «из коробки» она не поддерживает горизонтальное масштабирование. Многие сервисы рано или поздно достигают пределов одного экземпляра Postgres, после чего начинается «танец с бубном». При достижении одной базой данных объёма в несколько терабайт и с нагрузкой более 100 000 запросов в секунду (QPS) вертикальное масштабирование перестаёт быть эффективным.

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

  • Сложные миграции. Вернуться из монолита к кластерам и обратно без простоя почти невозможно.

  • Не хватает готовых инструментов. Vitess отлично работает с MySQL, но попытки привнести его в Postgres оказались слишком трудоёмкими. К этому времени многие компании (в том числе Яндекс) писали собственные мини‑фреймворки для роутинга. В целом это странная ситуация: у MySQL есть готовое решение, а у Postgres нет.

  • Проблемы с балансировкой и переносом данных. Без автоматизации дежурным приходилось ночью переносить «горячие» ключи вручную, чтобы избежать переполнения или перегрузки отдельных шардов. Шардов может быть сотни, и любая ошибка грозит отказом.

  • Метаданные не масштабируются. При хранении сведений о каждом ключе метаданные быстро разрастаются и перестают помещаться в один экземпляр Postgres, становясь новым узким местом системы.

Инженеры из Data Platform Yandex Cloud решили, что мириться с этими недостатками нельзя. Так появилась система SPQR (Stateless Postgres Query Router) — опенсорс‑решение для горизонтального масштабирования Postgres, оптимизированное под OLTP‑нагрузки и плавные миграции.

Как работает SPQR

Мы не сразу пришли к текущему дизайну SPQR. Сначала были эксперименты с FDW‑подходом (Foreign Data Wrapper) — классическим способом связать несколько PostgreSQL‑инстансов через внешние таблицы. Это выглядело естественным: минимум внешнего кода, можно использовать стандартный планировщик запросов. Но довольно быстро выяснилось, что при большом числе шардов и высоком QPS такая схема даёт слишком большие накладные расходы. 

Следующим шагом стала попытка реализовать CustomNode‑based sharding — расширение на C, которое встраивалось в планировщик Postgres. Производительность улучшилась, но не было ясно, что делать с апгрейдом мажорных версий PostgreSQL. В итоге мы решили написать proof‑of‑concept proxy‑решения — и у нас получилось!

Роутер вместо кастомных драйверов

Главная идея SPQR — поставить между приложением и шардами лёгкий прокси‑роутер. Приложения подключаются к нему по обычному протоколу PostgreSQL, «не догадываясь», что работают не с базой данных, а с Golang‑приложением. Такой подход позволяет на уровне роутера перенаправлять запросы, распределять их между репликами, не модифицируя код приложения.

Роутер анализирует первый запрос в транзакции и решает, на какой шард отправить транзакцию целиком. SPQR поддерживает как одноколоночные шард‑ключи, так и композитные ключи. При необходимости разработчик может указать ключ явно в SQL‑комментарии, например:

INSERT INTO orders(id, data) VALUES (10, '...') /*__spqr__sharding_key: 1, 100*/;

Если подходящего ключа в запросе нет, можно настроить default shard — роутер отправит транзакцию на него по умолчанию.

Координатор и QDB

Один роутер неизбежно стал бы узким местом и единой точкой отказа, поэтому система SPQR изначально спроектирована так, что можно запускать сколько угодно роутеров параллельно. 

Правила шардирования хранятся в памяти каждого роутера, но синхронизируются через отдельный сервис — координатор. Координатор записывает метаданные в небольшую базу QDB (внутри работает кластер etcd) и раздаёт актуальные правила всем роутерам. 

Благодаря этому можно динамически добавлять и удалять роутеры, не беспокоясь о рассогласованности конфигурации.

Решение проблемы балансировки

Одна из главных трудностей при шардировании — неравномерная нагрузка. Когда один шард перегружен, а другие простаивают, администраторам приходилось переставлять данные вручную. SPQR предоставляет балансировщик, который делает это автоматически.

Схема ε‑split
Схема переноса данных реализована методом ε‑split: от перегруженного шарда «отрезается» небольшой фрагмент диапазона ключей и переносится на менее загруженный шард

Вместо того чтобы полностью копировать данные с одного шарда на другой, как предлагают многие решения на основе логической репликации, координатор SPQR делает ε‑split: «отрезает» от перегруженного диапазона маленький «кусочек» (ε) и переносит его без долгих блокировок. Этот процесс повторяется до тех пор, пока нагрузка не выровняется. Подход с ε‑split минимизирует время, в течение которого мигрируемый диапазон находится в режиме read‑only, и позволяет переносить данные даже на сильно загруженных кластерах.

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

Работа с транзакциями и кросс-шардовые запросы

Прежде всего система SPQR рассчитана на single‑shard OLTP‑сценарии, поэтому кросс‑шардовые запросы поддерживаются только в ограниченном объёме. Разрешены, например, SELECT * FROM… без WHERE и DDL‑команды (CREATE TABLE и пр.) — такие запросы выполняются по принципу best effort и могут вернуть несогласованный срез данных. В продакшене этот режим отключён по умолчанию, но его можно включить, установив в конфигурации query_routing.default_route_behaviour = BLOCK

В планах — поддержать более богатые кросс‑шардовые запросы, но это долгосрочная задача.

Для транзакций на нескольких шардах SPQR поддерживает двухфазный коммит. Специальный комментарий в запросе _spqr_commit_strategy определяет стратегию фиксации: 1pc (однофазная фиксация без координации) или 2pc (двухфазная фиксация). 

В режиме 2pc изменения на всех шардах применяются атомарно, но важно понимать, что двухфазный коммит не обеспечивает полной изоляции — это принципиальное ограничение всех СУБД, использующих 2pc. То есть в межшардовых транзакциях возможны аномалии из‑за отсутствия глобального уровня snapshot isolation.

В планах — добавить поддержку CSN (Commit Sequence Number), чтобы обеспечить глобально согласованный порядок транзакций и тем самым устранить часть аномалий, присущих двухфазной фиксации.

Отказоустойчивость и интеграция без модификации СУБД

Без состояния — максимум надёжности. SPQR не хранит состояние: все правила маршрутизации лежат в QDB, поэтому число роутеров не ограничено. Это позволяет запускать сотни экземпляров роутеров одновременно, обеспечивая горизонтальную масштабируемость и отказоустойчивость.

Умная маршрутизация и отказоустойчивость шардов. Для каждого шарда можно указать несколько серверов. SPQR автоматически распределяет read‑only‑запросы по репликам и при недоступности любого из них перенаправляет трафик. Кроме того, предусмотрен режим dedicated read‑only router: в нём SPQR отвечает true на SHOW transaction_read_only и принимает только запросы на чтение — аналогично обычной реплике PostgreSQL.

Интеграция без кастомных драйверов. Приложения подключаются к SPQR по стандартному PostgreSQL‑протоколу, никаких модификаций или специальных библиотек не требуется. Для администрирования предусмотрен отдельный порт: через psql можно выполнять служебные команды вроде SHOW shards; или SHOW clients; для мониторинга состояния кластера.

Простая эксплуатация. SPQR поддерживает все типы аутентификации PostgreSQL (trust, md5, scram, ldap, gss) и имеет готовый quickstart: кластер можно запустить через Docker за пару минут. Достаточно скачать образ роутера и задать конфигурацию шардов — и полноценный тестовый шардинг‑кластер готов к работе.

Отличия от других решений

При разработке SPQR мы сформулировали несколько принципов, которые отличают систему от большинства инструментов шардирования PostgreSQL:

  • Использование проверенных HA‑кластеров как строительных блоков. Для каждого шарда подходят Patroni, Stolon, PgConsul или управляемые облачные сервисы. SPQR не изобретает собственную репликацию и опирается на уже существующие решения высокой доступности.

  • Без простоя при миграциях. Монолитная база становится первым шардом, затем добавляются новые узлы, и данные переносятся без остановки сервиса. Тем же механизмом можно «схлопнуть» шарды обратно в монолит.

  • Лёгкая установка. Dev‑кластеры должны подниматься на ноутбуке за минуты, а не часы. Для этих целей есть готовый Docker‑образ.

  • Оптимизация под OLTP. SPQR добавляет к запросу всего ~ 1–2 мс накладных расходов, что приемлемо для кратких транзакций.

  • Перенос данных небольшими диапазонами. Данные можно «переливать» между шардами пропорционально нагрузке. Большие диапазоны ключей автоматически разбиваются на маленькие, чтобы минимизировать время блокировок при переносе данных.

  • Без головной боли с лицензией. SPQR использует открытую лицензию PostgreSQL.

Кому подходит SPQR

Система SPQR рассчитана преимущественно на OLTP‑нагрузки. Она особенно эффективна, когда большинство транзакций укладывается в рамки одного шарда. Вот её основные сценарии использования:

  • Электронная коммерция и финтех. Интернет‑магазин можно разделить по customer_id или product_category и обрабатывать десятки тысяч заказов в секунду.

  • Контент‑платформы. Блоги, новостные порталы и CMS‑разработки часто шардируются по author_id или типу контента, при этом комментарии и связанный контент остаются на одном шарде.

  • Хранилища микросервисов. Каждый микросервис получает свой логический шард, но физически всеми данными управляет единый роутер — это упрощает архитектуру хранения без множества отдельных баз данных.

  • Пользовательские сервисы, IoT, high‑traffic OLTP. SPQR обеспечивает низкие задержки, поддерживает до 100 000 запросов в секунду и терабайты данных, поэтому подходит для сервисов с большим потоком коротких транзакций (онлайн‑игры, платёжные системы, телеметрия IoT и тому подобное).

При этом SPQR не пытается заменить полноценные распределённые СУБД (такие, как YDB или CockroachDB): если вам нужны строго консистентные кросс‑шардовые транзакции или сложные аналитические запросы, лучше обратить внимание на HTAP‑решения. Но если ваша нагрузка хорошо шардируется, а переписывать приложение или городить собственный роутинг не хочется, SPQR станет удобным решением.

Текущий статус проекта и планы

SPQR развивается как открытый проект на GitHub под лицензией PostgreSQL Global Development Group. Код можно свободно использовать и модифицировать без ограничений (никакого AGPL). Команда Data Platform уже использует SPQR в проде. А ещё нашим инструментом пользуются Яндекс ID, Яндекс Пэй и Едадил.

Из наших планов на будущее:

  • дальнейшее развитие балансировщика и метрик мониторинга;

  • поддержка более богатых кросс‑шардовых запросов;

  • развитие административного API и инструментов наблюдения за кластером.

SPQR развивается не только внутри Yandex Cloud — в проект уже активно вносят вклад внешние контрибьюторы. У нас есть несколько внешних коммитеров, которые добавляют полноценные фичи среднего масштаба — из последнего, например, поддержку default shard. Команда рада любой обратной связи: код полностью открытый и независимый — никаких enterprise features за paywall. Будем рады вашим комментариям, пул‑реквестам и звёздочкам в репозитории. А также заглядывайте на трансляцию нашего Open Source Jam — поговорим о PostgreSQL и не только.


SPQR — попытка сделать PostgreSQL по‑настоящему масштабируемым без компромиссов.
Лёгкий роутер на Go распределяет нагрузку по шардам, координатор следит за целостностью правил, а балансировщик переносит данные микропорциями, избегая долгих блокировок. Несмотря на ограничения — транзакции в основном внутри одного шарда и пока ограниченную поддержку cross‑shard‑запросов — проект уже успешно работает в продакшене и доказывает, что шардированный Postgres может быть одновременно простым и надёжным.

В отличие от «настоящих» распределённых СУБД, система SPQR не пытается во что бы то ни стало обеспечить глобальные ACID‑гарантии. Её цель — сохранить привычный Postgres и дать ему возможность расти горизонтально, без отказа от знакомых инструментов и контроля над данными. 

Комментарии (1)


  1. fo_otman
    24.11.2025 13:20

    Вроде делали ведь уже про это доклад на Highload++.