Обновить

Мы знаем как готовить БД. Но индустрия изменилась: что бы я заложил в OLTP-БД с нуля

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели7.3K
Всего голосов 2: ↑1 и ↓1+1
Комментарии18

Комментарии 18

Статья хорошая но вопросы странные. Замочить от бизнеса. Например, в одной конторе процессинг real time и все помешаны на p95-p99 и latency в миллисекундах. В другой MSSQL более "бэкендный" уже после кафок всяких и там запросы уже с таймаутом 30 сек ок. А read-only реплика этого вообще для кубов и там запросы по часу.

@Tzimie, спасибо — полностью согласен, что “обязательность” сильно зависит от профиля нагрузки и SLO: где-то считают миллисекунды на p99, а где-то 30с таймаут норм, и отдельная RO-реплика живёт своей жизнью.

Моя цель этими вопросами как раз собрать разные “минимальные контракты продакшена” по классам (условно: latency‑critical OLTP / “обычный” backend OLTP / тяжёлые чтения и реплики) и понять, что люди считают ядром, а что — “обвязкой”. В продолжении, похоже, стоит явно разнести это по сценариям и задавать вопрос не “в целом”, а “для такого-то профиля”.

Если не сложно: для вашего самого “болючего” сценария (процессинг/latency‑critical или наоборот) какие 3 вещи вы бы назвали самыми критичными?

Для real time critical это работа resource governor (он слишком сложен и при большом потоке коннекций начинает добавлять overhead), я бы ввел некешируешие операции (ленивый скан который не должен забирать себе кеш), стабильность планов (по real time переключение на другой план как минимум не надо делать днём под нагрузкой)

На самом деле MSSQL стоит своих денег (про особенности одной страны пока не говорим). Query store, resource governor, parameter sniffing... Ну в 2022 есть полипланы для разных параметров. Все из коробки. И люди кто работает с Постгрес как то странно смотрят когда их хотят навязать миграцию базы с MSSQL... Ну терабайт так 90...

А что думаете вы, раз столкнулись и с тем и с другим? Я все хочу уйти на PostgresSQL но слишком много работы по MSSQL пока, нет времени. И слышал что много людей приходят в состояние шока. Как с машины пересел нас велосипед

Да, SQL Server во многих местах реально выглядит как более “собранная машина” из коробки: Query Store, Resource Governor, много диагностики/управления планами, зрелые инструменты — и это экономит кучу времени и нервов, особенно на больших инсталляциях.

И это, кстати, прямо ложится в мой тезис про “конструктор”: в Postgres похожие свойства часто достигаются комбинацией ядра + расширений + внешних компонентов + практик эксплуатации. Работает, но требует дисциплины и “обвязки” — и на миграции это ощущается особенно остро.

Про “терабайт 90”: я бы не воспринимал переход как “просто захотели — переехали”. На таком объёме миграция обычно оправдана только при очень конкретной бизнес‑причине (стоимость лицензий/вендор‑лок, требования к платформе/деплою, унификация стека, дефицит MSSQL‑экспертизы и т.п.). На практике чаще заходят не big‑bang, а с новых сервисов/контуров, постепенно наращивая долю Postgres — и вместе с долей растёт и экспертиза, как управлять им на таком объёме.

Про “велосипед после машины”: соглашусь, но шок у людей обычно не от SQL как языка, а от разных “продакшен‑дефолтов” (соединения/пуллинг, vacuum и bloat, наблюдаемость/diagnostics, политики ресурсов).

При этом если запускаешь новый проект и продакшином ещё не пахнет, мне часто проще и приятнее поднять Postgres, чем поднимать SQL Server.

OLTP нагрузка конечно бывает "разной", но если это "реальный" OLTP профиль он должен "по универсальности" приближаться к Oracle. К примеру (без "перекручивания" десятка параметров) оптимально поддерживать R/W нагрузку и как 1/9 и 3/7. Кэшировать данные один раз на множество сессий, не выделять один "тяжелый объект" в системных "словарях" БД на 10000 пользовательских сессий и т.п.
Дисковый IO давно уже не главный "тормоз" OLTP нагрузки. Oracle "тормозит" только на блокировках (важна частота/латенси памяти и CPU), а в PG эти блокировки и тормоза "умножаются" за счет vacuum и analyze. Сбор статистики это конечно не плохо, но произвольное/автоматическое изменение планов исполнения "на лету" - попытка упростить "тупым" разработчикам/администраторам работу с БД.

Спасибо — тут во многом согласен, и как раз это хороший “приземляющий” контекст к моему тезису.

  • Про “реальный OLTP” и универсальность уровня Oracle: да, если говорить про один инстанс, много сессий, R/W, предсказуемый tail, то ожидания часто именно такие: общие кэши/словари “один раз на всех”, минимальный per-session overhead, без сюрпризов на 10k сессий. И это не вопрос “фич”, это вопрос архитектурных инвариантов (память, конкуренция, контроль фоновой работы).

  • Про дисковый I/O vs CPU/память/локи: согласен, в современных OLTP-профилях bottleneck часто уезжает в конкуренцию и координацию (locks/latches, cacheline contention, latency памяти). И да — в PostgreSQL vacuum/analyze добавляют ещё один измеритель “конкуренции вокруг жизненного цикла данных/статистики”, который оператору приходится держать в голове.

  • Про auto-изменение планов “на лету”: я бы сформулировал мягче. Сбор статистики сам по себе полезен, но проблема начинается там, где для продакшена нет явных рамок стабильности: “вот так система может менять поведение, вот так — не может”, и это наблюдаемо и управляемо. Не потому что разработчики “тупые”, а потому что цена регрессии плана в OLTP — это p99 для бизнеса.

Если интересно, уточню вопрос: вы больше за модель “план должен быть стабилен, а изменения — только через явные действия (pin/force/approve)”, или за модель “автоматика ок, но должна быть ограничена guardrails + быстрый откат”?

В терминах MSSQL я бы предложил оставить все как есть по умолчанию но в процедуры добавил бы WITH REALTIME чтобы менять поведение

Идея WITH REALTIME как явного переключателя поведения мне понятна, но мой опыт с MS SQL Server как раз про то, что “по умолчанию” часто не хватает предсказуемости: сегодня запрос летает, завтра внезапно упирается из‑за кэшированного плана/parameter sniffing и начинает тормозить, а дальше начинаются типичные пляски со статистикой и план‑кэшем.
​Поэтому я бы предпочёл не разрастающийся набор хинтов в процедурах (которые потом сложно поддерживать как техдолг), а встроенный механизм стабильности/контрактов: realtime‑режим = фиксируемость плана и управляемые условия его пересборки; batch‑режим = оптимизатор может быть более “агрессивным” и чаще адаптироваться.

Да, я и имел в виду что к with REALTIME ещё иметь механизм более контролируемого переключения планов

Не думаю, что о базах, любых, стоит вот так говорить в отрыве от общей архитектуры системы. Думаю все уже достаточно за последние десятилетия походили по граблям, что бы воспринимать базу данных в контексте "должна вытянуть любые нагрузки". Нет, не должна. Большинство нагрузок должны быть подхвачены слоями выше (кеширование, поддерживаемые рид онли сэты данных в KV и прочее).

Согласен. База почти никогда не существует “в вакууме”, и попытка требовать “вытяни любые нагрузки” — это прямой путь к разочарованию и неправильным ожиданиям.

Я бы только добавил нюанс, который для меня и является ключевым:

  • Да, слои выше (cache, KV, read models, CQRS-подобные схемы) обязаны брать часть нагрузки.

  • Но ядро БД всё равно должно иметь контракт поведения под стрессом: когда кеш промахнулся, когда случился всплеск соединений, когда фоновые процессы догоняют хвост, когда multi-tenant “шумит”. Если в эти моменты БД деградирует хаотично, то “слои выше” часто лишь маскируют проблему до первого большого промаха.

То есть я за позицию: архитектура системы задаёт профиль нагрузки, а контракт БД задаёт предсказуемое поведение внутри этого профиля (и честный отказ/ограничение за его пределами).

Если вы согласны, то вопрос: какие “слои выше” вы считаете обязательными по умолчанию для OLTP в 2026 (кеш, queue, read-only projections, rate limiting), а какие — строго “по ситуации”?

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

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

Да, это прям в точку, согласен.

Если продукт и нагрузка по природе стационарные (нет взрывного роста, функционал/схема меняются редко, пользовательская база предсказуема), то действительно нет смысла с v1 городить “платформу на стероидах”. В таких задачах зачастую выигрывает простота и минимальная операционная поверхность.

А вот когда есть риск “взрывов” и мульти-акторности, я бы тоже начал с двух базовых вещей:

1) Кэширование с контролируемым прогревом

Чтобы не устраивать stampede на БД при рестартах/релизах/инвалидациях, и чтобы прогрев был наблюдаемым и дозированным.

2) Контролируемая очередь на запись в “жирные” таблицы

Фактически — admission control/backpressure на write‑путь: лучше заранее и управляемо ограничивать скорость записи (и иметь понятную деградацию), чем ловить хаотичные блокировки/очереди ожиданий уже внутри БД.

Если уточнить: под “очередью на запись” вы имеете в виду в приложении/шине (Kafka/Redis/DB-backed queue), или именно внутри слоя БД (типа write-admission + bounded queue per table/tenant)?

С LLM какой версии я веду переписку? =)

Я ждал этого вопроса :)

Pitr, autofailover, poller transaction mode, чтение с реплики, мониторинг - минимальный набор

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации