Comments 10
нажал педаль — машина тормозит. Это контракт. Он не зависит от того,правильно ли вы настроили тормозную жидкость этим утром
Извините , но аллегория выбрана неудачно. Тормоза нуждаются в настройке и мониторинге . и только при 100% исправности тормозной системы контракт будет выполнен. К тому, же при одном важном условии - на сухой поверхности и на льду контракт будет выполнен по разному , с разными итоговыми результатами. Как тормозит это очень важно.
Если перенести аллегорию на СУБД - контракт это операционная доступность - СУБД работает и выдаёт данные. Но, не менее важные и производительность - как СУБД выдаёт данные. Хотя конечно производительность в рамки контракта очень сложно поместить(по крайней мере, я пока не встречал примеров). Ну просто потому, что как правило никто и не задумывается - а производительность это что и как её считать. Работает и ладно.А будет , как кажется тормозить- накидают ядер и памяти и диски HiOPS.
P.S.
формализован — можно проверить программно, не только "на глаз";
Вряд ли удастся выполнить в реальном мире. Но будет интересно следить за развитием.
ро «лед» — это вы очень точно подметили. Эта аналогия даже лучше раскрывает суть, чем я планировал.
Смотрите: когда машина тормозит на льду (экстремальная нагрузка), контракт тормозной системы не в том, чтобы остановить машину мгновенно (это физически невозможно). Контракт — это ABS. Система понимает, что сцепления нет, и начинает «отбивать» педаль, сохраняя управляемость.
В мире СУБД «лед» — это спайк нагрузки или lock contention.
Обычная СУБД без контракта: Блокирует колеса. Процессы встают в очередь, память кончается (OOM), админ не может зайти в консоль. Машина летит в кювет.
СУБД с контрактом: Включает «ABS» (Load Shedding / Backpressure). Она говорит: «Я не могу обработать 10k запросов, я обработаю 5k, а остальным отдам ошибку сразу, не тратя ресурсы». Управляемость сохраняется.
Вы правы, формализовать производительность в реальном мире сложно. Но для современного приложения Latency = Availability. Если база отвечает 30 секунд вместо 50 мс — для бизнеса она «лежит», даже если технически процессы живы.
Поэтому моя идея не в том, чтобы обещать бесконечную скорость на любом железе, а в том, чтобы поведение системы при перегрузке было предсказуемым и заложенным в дизайн, а не случайным.
Контракт БД — это проверяемые гарантии, которые либо выполняются всегда,либо система явно сообщает об отказе
7 историй о том, как p99 "срывается"
это не OLTP, а другой класс баз данных - Real Time. Всё, что вы описали решается в представителе этого класса - Oracle Times Ten, которая использует SQL как в Oracle Database. То есть изобретать велосипед не нужно. Проблема еще в том, что бизнесу это не нужно. В 2013 году в 11 версии TimesTen перестал развиваться, его хотели закрыть как не пользующийся спросом. Потом в ~2018 воскресили, дали версию 18 и TimesTen даже жив, но это скорее венчурная цель: вдруг где-то пригодится. Успешными были другие технологии и идеи.
Разные No/NewSQL базы тоже стабильные точечные запросы обеспечивают. А вот произвольный SQL не могут, и не видно как это было бы возможно.
В чем-то сходно с Rust, какие-то ограниченные структуры владения объектами можно описать и он гарантирует безопасность. А вот произвольный связи как в плюсах не сделать.
Выбор, и там и там, между универсальностью и гарантиями. В общем для обоих есть применения, но универсальность нужна чаще конечно.
Аналогия с Rust — в точку. Но выводы я делаю ровно противоположные.
Rust не запрещает писать сложную логику («произвольные связи»). Он запрещает писать логику, которая приведет к Undefined Behavior (segfault, data race). Да, он бьет по рукам компилятором (borrow checker), но взамен вы получаете систему, которая не падает в ран-тайме от случайного null pointer.
Моя идея ровно в этом же: СУБД должна вести себя как компилятор Rust, а не как C++. Она не должна запрещать SQL (универсальность). Она должна запрещать Undefined Behavior в эксплуатации:
Запрос без
LIMIT, который вычитывает всю таблицу в RAM -> OOM -> Crash.Транзакцию, которая висит 4 часа и держит вакуум.
Full Scan по таблице в 10ТБ в интерактивном потоке.
Это не «отказ от универсальности», это «отказ от права выстрелить себе в ногу». Мы хотим оставить SQL, но наложить на него Borrow Checker ресурсов (CPU, IO, Memory). Если запрос не укладывается в контракт — он не должен «компилироваться» (исполняться), вместо того чтобы положить прод.
На Rust нельзя описать нормально многие структуры. Нужны либо unsafe, либо проверки в рантайме. Borrow checker ограничен в том, безопасность чего он может доказать. Довольно большой класс безопасных структур он не пропустит, из-за чего в том же Rust много библиотечных классов реализовано на unsafe.
Вы необходимо столкнетесь с чем-то подобным, буду ждать следующих статей как вы это решили.
Тот же full scan нормален на 1 мегабайте, не ОК на допустим 10 Тб. Но где граница, и как сделать так чтобы самый важный запрос не упал, когда самая главная таблица вдруг превысила этот порог на один байт?
«Вы правы, и это — самый "больной" вопрос архитектуры. Проблема "границы" (Threshold Problem) — это именно то, на чем ломаются простые квоты.
Если отвечать в терминах Rust, то решение видится не в одном лишь "компиляторе" (статическом анализе запроса), а в комбинации трех механизмов:
Resource-Aware Planning (Статика): Мы не просто строим план, а оцениваем его "стоимость" в конкретных единицах (IOPS, CPU-cycles, Memory pages). Если оптимизатор видит, что Full Scan на 10 ТБ потребует ресурсов, выходящих за лимит интерактивного класса нагрузки — запрос отклоняется еще до старта. Это аналог Borrow Checker.
Runtime Guardrails (Динамика): Чтобы не падать из-за "лишнего байта", система должна поддерживать мягкую деградацию. Если запрос в процессе выполнения начинает потреблять больше, чем предсказал оптимизатор, он не убивается мгновенно, а переводится в "фоновый" режим с низким приоритетом (throttle) или получает сигнал на прерывание с сохранением промежуточного состояния (если это возможно).
Explicit Contracts (Явность): Самое важное — граница не должна быть сюрпризом. В контракте API разработчик явно указывает: "этот запрос — интерактивный, лимит 100мс". Если таблица выросла и запрос перестал укладываться — это ошибка проектирования схемы, которую база подсвечивает сразу, а не когда сервер падает в OOM.
В следующей статье я как раз планирую разобрать, как мы пытаемся реализовать этот "Resource Budgeting" внутри движка, чтобы избежать ситуации "вчера работало, сегодня — нет". Буду рад вашему фидбеку там!»
«По поводу ограничений Rust — вы правы, "чистый" Borrow Checker не всесилен. Но Rust как мне кажется ценен не тем, что он запрещает сложные структуры, а тем, что он делает явными места, где гарантии могут нарушиться (через unsafe или runtime-проверки вроде RefCell).
Про TimesTen — пример отличный, но выводы, как мне кажется, другие. TimesTen стагнировал не потому, что бизнесу не нужна предсказуемость. Он стагнировал, потому что это было дорого (Oracle), сложно и In-Memory (ограничение по объему). Бизнес не хотел платить цену «спец-решения» за обычные задачи.
Мой тезис в том, что в 2026 году граница между RT и General Purpose OLTP стирается. Бизнесу (финтех, ритейл) критически нужен Soft Real-Time (SLA p99 < 50ms). Сейчас они решают это наймом армии DBA, которые «крутят ручки» Postgres. Я предлагаю решить это архитектурно.
я написал, чтобы уберечь от тупиковых идей, а не обесценить. Если идею развивает изобретатель (мало ресурсов), то обычно он не получает прибыль (первый блин комом), ее получает делающий вторую попытку. В случае компаний с ресурсами (oracle) если им не удалось, то обычно это бесперспективно.
дорого (Oracle), сложно и In-Memory
патенты и наработки TimesTen ушли в опцию IMDB Oracle Database, которая ест на порядок больше памяти )
p99 нужен программистам, бизнес таких слов то не знает. Классу баз RealTime десятки лет и до сих пор граница не стерлась, а представителей баз RealTime почти нет. Но возможно, именно в 2026 граница сотрется )) Идея избавления от армии DBA была тоже у Oracle когда вводили автоматизации (AWR, ADDM). Правда спикеры Oracle были умнее и не «избавляли бизнес от DBA”, а грозились избавить DBA от рутины. )) Но кончилось всё тем, что DBA пришлось, ко всему прочему, еще и их изучать и сложность администрирования только возросла. Но, возможно, вы сможете реализовать то, что никому не удавалось или, что более реально, создать видимость для части потенциальных клиентов, соблазнив тех, кто не знает про «дешево-быстро-качественно» и «кроилово ведет к попадалову». ;) Ручки DBA не «крутят», обычно сразу всё стандартно настраивается, редко когда что-то новое и интересное обнаруживается. «Ручки крутят» там, где нет DBA или не смогли найти квалифицированного или испольщуют неподхдящие опции неподходящим образом и как следствие кажется, что PostgreSQL темный лес и непредсказуем. В реальности с PostgreSQL очень приятно работать - предсказуем, красив, приятно видеть, что все решения, применяемые сообществом идеальны. Вот даже в соседней статье хаба PostgreSQL про pgBackRest сетуют, что pgbasebackup (и startup, на него тоже бывает сетуют) однопроцессны и однопоточны. И у стороннего наблюдателя возникает впечатление, как все DBA сплошняком страдают, что они однопоточны, а «злое сообщество» никак не применяет патчи, чтобы распараллелить хотя бы резервирование.
Олег, спасибо за развернутый ответ и предостережение. Я ценю опыт и понимаю скепсис — "очередная убийца Oracle" звучит наивно.
Но давайте уточним пару моментов, где мы, возможно, говорим о разном:
"Бизнес не знает слов p99". Бизнес знает слова "пользователи уходят, потому что чекаут крутится 10 секунд". p99 — это просто техническая метрика этого бизнес-риска. Если для вас RealTime — это только управление ядерным реактором (Hard RT), то да, граница четкая. Но я говорю про Soft Real-Time в массовом сегменте (финтех, ритейл), где "зависание" на секунды уже стоит денег.
"Ручки крутят там, где нет DBA". Мой тезис ровно в этом: большинству проектов не нужен выделенный DBA, если база данных предоставляет жесткий контракт. Postgres прекрасен, но он "Permissive by default". Он по умолчанию позволит одному тяжелому запросу вымыть кэш или забить IO, из-за чего "встанут" соседние критичные транзакции. Я предлагаю подход "Restrictive by default" — когда база гарантирует изоляцию и просто не даст одной операции забрать ресурсы у других, даже если план запроса внезапно изменился.
Про ресурсы и Oracle. Oracle (и TimesTen) шли путем "добавим еще фич и автоматизации поверх". Это путь усложнения. Я предлагаю путь упрощения: выкинуть всё, что мешает предсказуемости. Rust здесь не панацея всего лишь инструмент, но он позволяет писать безопасный многопоточный код дешевле, чем на C/C++ 20 лет назад.
Я не пытаюсь сделать "Postgres, но лучше". Я делаю инструмент для конкретной ниши: когда предсказуемость важнее широты фич. И да, возможно, это "тупиковая ветвь", но проверить это можно только кодом :)
Контракт вместо настроек: чего я жду от OLTP-БД