Originally published on Habr

Введение

Привет, я Костя Осипов и занимаюсь разработкой СУБД. На Хабре опубликовано несколько моих статей о MySQL, Tarantool и смежных темах. Я также веду Telegram-канал с инсайтами по управлению базами данных. Сегодня выступаю как основатель Picodata — открытой СУБД и управляющий директор ПАО Arenadata по исследованиям и разработке. Это вольный пересказ доклада на HighLoad о будущем СУБД и месте резидентных баз данных в современных архитектурах.

Picodata

Бэкграунд: эволюция аппаратного обеспечения и СУБД

Когда десять лет назад предсказывали тренды СУБД, становится смешно вспомнить неудачные прогнозы. Прогнозировали снижение стоимости оперативной памяти, её увеличение, появление энергонезависимой памяти, исчезновение дисков и SSD. Активно говорили о переходе на облачные, горизонтально масштабируемые системы с полной контейнеризацией.

Главной идеей эпохи Webscale стало горизонтальное масштабирование. Типичная СУБД будущего виделась как горизонтально масштабируемая, облачная, резидентная система. Но будущее оказалось совсем другим — и оно уже наступило.

Эволюция оборудования

Современное оборудование

Компания Pascari анонсировала жёсткий диск на 122 TB. Аналогичные диски планирует выпускать Solidigm. Важны не только объёмы, но и производительность: один диск обеспечивает 3 млн IOPS на чтение и 35 тыс IOPS на запись. Восемь таких дисков содержат более петабайта данных, а дополненные процессорами на 96–128 ядер (например, AMD EPYC 9xxxx), дают мини-дата-центр в двухъюнитовом сервере. Заполнение диска данными требует 12+ часов.

Если большие накопители столь доступны, нужно ли горизонтальное масштабирование? Многие современные СУБД, оптимизированные под многопоточность и большие объёмы памяти (OrioleDB как форк PostgreSQL), показывают результаты, сравнимые с многомашинными кластерами.

Современные накопители

Также существуют горизонтально масштабируемые системы, извлекающие из одного узла на порядок большую скорость. ScyllaDB на трёх средних узлах (32 ядра, 3,5 Ghz, 256 GB RAM) с фактором репликации 3 показывает 500 000 запросов в секунду.

ScyllaDB benchmark

Вывод: противопоставление горизонтальной и вертикальной масштабируемости менее важно, чем внутреннее устройство СУБД, адекватное современному оборудованию.

Тренды в мире СУБД

1. Разделение compute и storage

Идея разделения вычислений и хранения противоречит принципу локальности данных (девиз Tarantool: “bring compute close to storage”), но экономически оправдана в облачах. Масштабировать вычисления проще, хранение-как-сервис подешевело. С ростом данных приоритет смещается на снижение стоимости хранения, даже в ущерб производительности.

Кластерные СУБД отстают от реальности: масштабирование кластера, работа в Kubernetes считаются “особенными” операциями. Лидеры тренда — Trino, DuckDB с MotherDuck, Neon; есть контртренд типа Turso. В 5–10 лет эволюция вернёт конвергентные архитектуры, так как аналитика требует минимальной задержки и near-real-time-анализа.

2. Закрытие исходного кода и облака

Закрытие исходного кода

Вендоры переходят на проприетарные лицензии: MongoDB, Elasticsearch, ScyllaDB, Greenplum, CockroachDB, Timescale. Одни защищаются от облачных провайдеров, другие строят модель DBaaS. Деглобализация наносит удар по Open Source: гонения разработчиков, глубокие форки в Китае, консервативность мейнтейнеров.

Фрагментация лицензий: AGPL, BSL, SSPL. Переиспользование кода между non-free-лицензиями невозможно, что фрагментирует ресурсы сообщества.

Привязка к облакам: многие СУБД поставляются как managed service и теряют возможности вне этого окружения.

На этом фоне по-настоящему открытыми останутся только платформенные игроки — те, кто предлагает экосистему решений для работы с данными, а не одну конкретную СУБД.

3. Специализация и модульность

Тренд polyglot persistence (15 лет развития от Cassandra и Kafka) не привёл к консолидации. Напротив, появляются всё новые специализированные СУБД для AI, аналитики, встраиваемых решений.

Новый тренд: модульность баз данных. 10 лет назад “строительные блоки” считались редкостью: RocksDB, SQLite, H2. Их преимущество — не разрабатывать всё с нуля. RocksDB используется в MySQL, ArangoDB, TiDB, Yugabyte; FoundationDB построен на SQLite. Ключевые части (оптимизатор запросов) были немодульными.

Ситуация меняется:

  • Apache DataFusion Kernel — аналитический оптимизатор запросов для разных продуктов
  • etcd-raft — модуль репликации в etcd и CockroachDB
  • cassandra-accord — алгоритм транзакций Cassandra как отдельный проект
  • DuckDB применима далеко не только в DuckDB Labs
  • Turso переписал SQLite на Rust для Rust-экосистемы
  • Dremio/Apache Iceberg переопределяют работу с холодными данными

Модульность СУБД

Изменяется бизнес-ландшафт: CIO/CDO ставят на экосистему целиком (Amazon, Google, в России — Sber Platform V, Yandex, Arenadata), а разработчикам предоставляют выбор инструмента в пределах экосистемы.

Место резидентных СУБД

Обзор выше обосновывает видение Picodata. Большие быстрые диски означают, что скорость доступа к диску не может быть фактором выбора резидентной СУБД. Закрытие вендоров требует удобного инструмента для разработчиков. Тренд разделения compute/storage и эластичность означают, что добавление/удаление узлов и работа в Kubernetes должны быть рутиной, не влияя на производительность и troubleshooting.

Почему in-memory?

Резидентные СУБД ускоряют не просто размещением в памяти. Достаточно было бы дать PostgreSQL больше кэша. Кратное ускорение даёт:

  • Специализированные структуры данных
  • Менеджеры транзакций
  • Управление многопоточностью
  • Архитектурный подход shard-per-core: данные по ядрам, без блокировок и конкуренции

Нужны ли эти усилия, если диски достаточно быстры?

Цифры: SSD даёт 10–20 микросекунд, RAM — 10–20 наносекунд. Хотя диски в 100 раз быстрее, чем HDD, разница с памятью три порядка. Но между чтением и пользователем стоит ОС и сеть:

  • Накладные расходы ОС: ~50 микросекунд (квант планировщика Linux)
  • Передача в дата-центре: ~200–300 микросекунд

Сам диск/память становится несущественным в микросервисной архитектуре.

Латентность: RAM vs SSD vs сеть

Размещение логики внутри СУБД

Что если разместить логику приложений внутри СУБД в виде плагина/хранимой процедуры? Вернёмся к ускорению на 3–5 порядков от прямого доступа.

Сценарии оправданности:

  • Интеграция данных в высокодоступную витрину (личный кабинет федерального масштаба)
  • Тарификация, высокочастотная торговля, real-time bidding, таргетинг, скоринг
  • Компрессия IoT данных на лету, промышленные платформы
  • Ускорение ERP, расчёты себестоимости, отчётность, зарплата для вертикально интегрированных компаний

“Чуть быстрее” = “существенно выигрываем в бизнесе”.

Вертикально масштабируемые СУБД набирают популярность с ростом мощности серверов; IMDG подход не потерял релевантность.

Хранимые процедуры и микросервисы

В высоконагруженных проектах хранимые процедуры — антипаттерн. Близкий родственник SQL/PSM (стандартный PL/SQL) — язык ADA (1980). Дело не в архаичном синтаксисе, а в:

Сложность управления разработкой

В микросервисах/DevOps код в системе контроля версий, stateless-контейнеры, CI/CD, A/B-тестирование. Аналогов в хранимых процедурах нет (или о них никто не говорит).

Сложность отладки и тестирования

Как запустить интерактивный отладчик, изолировать ошибку, избежать hot spots на production? Нужны функциональные и performance-тесты. Тестирование миграций схемы и логики СУБД не распространено; проще schema-less JSON (теряется производительность и качество).

Сложность обновлений

Как консистентно обновить логику в распределённом кластере без простоя? Flyway/Liquibase работают со схемой, но не с логикой распределённой базы. Версии схемы и кода должны совпадать; откат может быть невозможен.

Picodata предлагает инструменты и методы работы с этими ограничениями.

Домены отказа, тиры и Rust-плагины

Архитектура кластера

Задача кластерной СУБД — разделить данные между узлами, представляя их единым целым, используя мощности всех узлов.

Подход:

  1. Шарды — разделение данных между процессами СУБД на ядрах. Каждый шард хранит данные всех таблиц; распределение определяется при создании.

  2. Репликация — при отказоустойчивости шард обслуживают несколько процессов (инстансов/узлов) в разных дата-центрах, копируя данные. Набор инстансов одного шарда — репликасет.

  3. Бакеты — вторичное разбиение внутри шарда. Шард — десятки/сотни GB, бакет — десятки MB. Позволяет гибко балансировать нагрузку, перемещать части данных.

Архитектура кластера

Подход масштабируется горизонтально и вертикально: множество ядер = множество СУБД-процессов, максимизируя утилизацию.

Упрощение для операторов

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

Шаги:

  1. Встроенный state provider — аналог etcd, часть каждого узла, хранит состояние в системных таблицах. Метаданные кластера консистентно реплицируются (используется raft-rs). Позволяет восстановить топологию/схему при аварии. Встроенная репликация быстрее, облегчает развёртывание больших кластеров.

  2. Домены отказа — концепция для описания конфигурации. Домен — пара ключ/значение, описывающая расположение узла (например, datacenter: msk). DBA указывает только расположение; кластер-менеджер копирует состояние, определяет репликацию, перераспределяет данные.

Домены отказа

Управление кластером

Две операции: добавить инстанс (add) или удалить (expel). Все СУБД-процессы доступны для запросов, автоматически маршрутизируя вычисления к узлу с данными. Восстановление и перебалансировка — автоматические.

Домен отказа необязательно описывает дата-центр; может быть сервером или стойкой.

Пример: два сервера в одном DC, 100% зарезервированные копии.

Управление кластером

  • Picodata автоматически распределяет реплики между доменами
  • При падении машины или DC система работает (при нужном числе реплик)

Тиры

Тиры

Типовые кластеры — одинаковые инстансы, одна задача. Сложные сценарии требуют разных типов.

Сценарии:

  • Часть ресурсов для вычислений/балансировки
  • Развёртывание 1+1 или 2+2: два DC, при падении одного данные остаются доступны на запись в другом (без третьего DC)
  • Разные данные с разным уровнем надёжности
  • Данные > RAM; для некоторых таблиц нужен движок vinyl

Каждый инстанс принадлежит одному домену отказа и одному тиру. Вместе они описывают топологии: симметричные (каждый домен содержит все тиры) или асимметричные (арбитр в выделенном домене, не хранит данные, обеспечивает 100% доступность).

Управление кодом: Blue-Green Deploy для плагинов

Домены/тиры упрощают управление, но не помогают версионировать хранимые процедуры. Они — фундамент отказоустойчивого кластера, но для blue/green-развёртывания нужны два кластера, соединённые репликацией.

Blue-Green Deploy

Зачем Blue-Green Deploy?

Blue-Green Deploy — практика параллельного разворачивания новой версии, live-тестирования, откатывания без простоя. Picodata распространяет принцип на код в СУБД.

Почему:

  1. Кластерная среда усложняет обновления — в обычной СУБД обновление на одном сервере; в распределённой всё должно обновляться согласованно на всех узлах (избежать рассинхронизации версий схемы/кода).

  2. “Аккуратная” миграция — транзакционные данные привязаны к структурам, меняющимся с версией. Сначала мигрировать схему/данные, затем включать новую логику.

  3. Безопасный откат — новая версия может содержать ошибки, вести себя непредсказуемо. Blue-Green даёт понятные шаги откатки (Rollback).

Picodata использует Blue-Green не только для плагинов, но для любой пользовательской логики. Процесс:

  1. Миграция схемы (SQL)
  2. Конфигурация новой версии плагина
  3. Включение нового кода во всём кластере
  4. При ошибке — откат всей операции

Компоненты Blue-Green Deploy

1. Версия плагина

У каждого плагина версия (1.0, 1.1); в кластере не может быть >2 разных версий одного плагина (Blue — старая, Green — новая).

2. Манифест (manifest)

Файл с описанием плагина, сборки, функционала, SQL-миграций:

name: weather_cache
description: That one is created as an example of Picodata's plugin
version: 0.1.0
services:
  - name: weather_service
    default_configuration:
      openweather_timeout: 5
migration: migrations/0001_weather.db

3. Миграции (up / down)

SQL-файлы с секциями:

-- pico.UP
CREATE TABLE "weather" (
    id UUID NOT NULL,
    latitude NUMBER NOT NULL,
    longitude NUMBER NOT NULL,
    temperature NUMBER NOT NULL,
    PRIMARY KEY (id)
)
USING memtx
DISTRIBUTED BY (latitude, longitude);

-- pico.DOWN
DROP TABLE "weather";
  • up — при установке/обновлении (новые таблицы/поля)
  • down — при откате (убрать изменения)

4. Конфигурация (configuration)

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

5. Enable / Disable

После миграции/настройки — “включить” (enable) новую версию или “выключить” (disable) старую. Синхронно на всех нодах.

Процесс обновления плагина

  1. Ставим/загружаем новую версию — Picodata получает манифест, собирает/распаковывает плагин, регистрирует как “возможный”.

  2. Выполняем миграцию — Запускается up-скрипт, меняет схему. Атомарно на всех узлах. Успех — сохраняем. Ошибка — откат + лог.

  3. Настраиваем и привязываем к тирам — Указываем, на каких тирах/узлах работает плагин, параметры. Конфигурация реплицируется.

  4. Enable новой версии — Система включает новую версию, она обслуживает запросы. Старая существует до уверенности.

  5. Disable/Remove старой версии — Отключаем старую. Если проблема — откат (rollback), запуск down, возврат к коду.

Ouroboros и асинхронная репликация

Для отладки новых версий без влияния на production реализован ouroboros — плагин логической асинхронной репликации между кластерами Picodata. Позволяет:

  • Создать копию кластера
  • Реплицировать все данные или выборочно (только таблицы)
  • Для сложных приложений — только таблицу входящих запросов
  • Выполнить новую версию логики на резервном кластере независимо
  • После отладки — переключить трафик на резерв (swap blue/green) или установить обновление на основном

Модульность и доставка кода

Picodata использует Rust для расширений, модульную архитектуру языка. Внутри плагина — множество модулей/зависимостей; при создании бандла — один бинарный файл.

Несколько плагинов взаимодействуют через общие данные (таблицы), не код. Защищает production от карнавала несовместимых версий зависимостей. Аналогия — go build в Go.

Создана утилита pike, автоматизирующая разработку и поставку плагина в кластер.

Все инструменты и методы вместе делают размещение логики рядом с данными управляемым.

SQL в Picodata

Плагины имели бы ограниченный функционал без кластерного SQL. Picodata сделала SQL максимально эффективным.

Протокол и инструменты

Основной протокол — PostgreSQL. Работают многие инструменты экосистемы PostgreSQL: psql, DBeaver; многие драйверы.

Проблема коллокации

В CockroachDB/TiDB данные в едином пространстве key-value (RocksDB, TiKV); SQL поверх NoSQL. Удобно для автошардирования, но порождает ненужные перемещения данных между узлами при JOIN.

Коллокация данных

Picodata передаёт управление коллокацией в руки разработчика.

При создании схемы для сценариев клиента — все данные одного клиента на одном узле, глобальные справочники идентичны на всех узлах. Результаты:

  • Большинство бизнес-сценариев без перемещения между узлами
  • Большинство транзакций локально на одном узле (нет конфликтов, блокировок)
  • Нагрузку можно распараллелить

Коллокация по ключу

По умолчанию данные разбиваются между узлами по ключу распределения:

CREATE TABLE ITEM (
    I_ID INTEGER NOT NULL,
    I_IM_ID INTEGER,
    I_NAME VARCHAR(24),
    I_PRICE NUMBER,
    I_DATA VARCHAR(50),
    PRIMARY KEY (I_ID)
)
USING MEMTX DISTRIBUTED BY (I_ID);

Управление коллокацией — расширение SQL DISTRIBUTED BY. Синтаксис из Greenplum. DISTRIBUTED BY (client_id) для таблиц orders, payments, sessions — все записи клиента на одном узле.

Глобальные таблицы

Для данных на всех узлах — глобальное (global) распределение:

CREATE TABLE WAREHOUSE (
    W_ID INTEGER NOT NULL,
    W_NAME VARCHAR(10) NOT NULL,
    W_TAX DOUBLE,
    W_YTD DOUBLE,
    PRIMARY KEY (W_ID)
)
USING MEMTX DISTRIBUTED GLOBALLY;

В аналитике глобальные таблицы для “small dimension table”: факты распределены, измерения глобальны.

Итоги

Picodata — попытка переосмыслить in-memory-базы в эпоху, когда современное “железо” (миллионы IOPS, сотни TB на сервере) делает горизонтальное масштабирование не всегда оправданным. Цель — удобный инструмент для разработчиков высоконагруженных проектов.

В эпоху смены лицензий и закрытия возможностей Picodata:

  • Сохранила открытую лицензию BSD
  • Продолжает инвестиции в Open Source
  • Для корпоративных клиентов — версия с сертификатом ФСТЭК, коммерческие расширения: промышленные данные, миграция с проприетарных СУБД, замена Redis/Cassandra

Развитие: каждый день появляются возможности. Версия 25.1 реализует оконные функции. Среднесрочные планы: материализованные представления, стоимостный оптимизатор, колоночное хранение.

Если in-memory-СУБД заместят классические системы (PostgreSQL, Oracle), Picodata будет в локомотиве этого движения.