Данные: карта хранилищ и подходов

Навигатор по всему, что на сайте про данные: как выбрать хранилище под задачу, что у него внутри — storage engine, WAL, индексы — и что значит эксплуатировать его в проде

Статей про данные на сайте больше сотни, и в них легко потеряться: транзакции, индексы, WAL, PostgreSQL, MongoDB, ScyllaDB, Redis, OpenSearch, ClickHouse, CockroachDB, YDB, векторный и гео-поиск, пайплайны. Каждая хороша сама по себе, но вопрос читателя обычно не «расскажите про ClickHouse», а «мне нужно хранить и доставать вот такие данные — что брать и чего от этого ожидать». Эта страница — не новая статья про базы, а слой навигации над уже написанным.

Раскладка задаёт не хронологию публикаций, а логику выбора: сначала модель (что вообще за инструмент), потом что у него внутри (storage engine, WAL, индексы — именно они объясняют, почему инструмент ведёт себя так, а не иначе), затем гарантии, затем эксплуатация, и отдельно — данные за пределами одной базы, где хранилище уже не конечная точка, а звено пайплайна.

Карта живая: заметная часть материала выходит позже неё, и ссылки на невышедшее показаны плашкой «готовится» вместо рабочей ссылки. Так карта остаётся картой ландшафта, а не списком того, что успели написать к четвергу.

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

В статье

Что связывает этот хаб

Пять осей, по которым разложены статьи:

  • Модель — реляционные, документные, KV и in-memory, поисковые, аналитические, распределённые объектные: как устроено хранение и адресация данных и что из этого следует для запросов.
  • Что внутри — storage engine (LSM против B-tree), журнал упреждающей записи, индексы: механика, которая объясняет, почему одна база быстра на записи, а другая на чтении, и почему у них разные больные места.
  • Гарантии — транзакции, уровни изоляции, аномалии, консистентность: что конкретная система реально обещает, а что придётся достраивать самому.
  • Эксплуатация — отказоустойчивость, пулинг, партиционирование, шардирование, тюнинг: то, что отличает «поднял в docker-compose» от «работает в проде третий год».
  • Данные за пределами одной базы — пайплайны, моделирование, качество, доступ из кода: когда хранилище становится звеном конвейера.

Две оси задают квадрант, на котором видно, где по смыслу стоит каждая система: характер нагрузки (точечные операции OLTP против аналитических сканов OLAP) и разрезан ли набор данных по нодам. Вторую ось стоит прочитать внимательно: она про шардирование, а не про число машин. PostgreSQL с десятком реплик остаётся внизу — на каждой ноде лежит полная копия данных; MongoDB с шардированием поднимается вверх, потому что набор разрезан и ни на одной ноде его целиком нет.

Карта хранилищ: характер нагрузки × разрезан ли набор данныхточечные операции (OLTP)найти / вставить / обновить записьаналитика (OLAP)сканы и агрегацииданные целикомна одной ноденабор разрезанпо нодам (шардинг)SQLitePostgreSQLRedisMongoDBScyllaDBCockroachDB, YDBOpenSearchTimescaleDBDuckDBClickHouseYTsaurusПо вертикали — шардирование, а не реплики. Положение приблизительно: почти каждая система умеет и «не своё» — вопрос в цене

Квадрант — эвристика, а не паспорт. Почти каждая система умеет и то, что стоит не в её углу: PostgreSQL считает аналитику, ClickHouse отдаёт точечные строки, Redis переживает рестарт. Вопрос всегда не «может ли», а «какой ценой» — и вся карта ниже про эту цену.

Модель: что брать

Реляционные. Строгая схема, транзакции, целостность — умолчание, от которого стоит отходить осознанно. Практический слой начинается не с SQL, а с драйвера: Надёжная работа с PostgreSQL из Go, Java и Rust. Отдельный случай — когда сервер не нужен вовсе: SQLite и встраиваемые БДготовится, с 8 октября.

Когда одной ноды перестаёт хватать, а SQL отдавать не хочется, начинается распределённый SQL: Distributed SQL и NewSQLСкоро — обзор класса. Дальше две системы вглубь.

CockroachDB:

  • архитектура: ranges, Raft, leaseholderготовится, с 27 октября
  • MVCC, HLC и uncertaintyготовится, с 28 октября
  • распределённые транзакции и цена SERIALIZABLEготовится, с 29 октября
  • SQL поверх KV: DistSQL и оптимизаторготовится, с 30 октября
  • геораспределение и survival goalsготовится, с 31 октября
  • эксплуатация и миграция с PostgreSQLготовится, с 2 ноября
  • карта выбораготовится, с 3 ноября

YDB — с другим устройством транзакций:

  • архитектура: tablets и Distributed StorageСкоро
  • транзакции по CalvinСкоро
  • YQL и обработка запросовСкоро
  • row и column таблицы: HTAPСкоро
  • topics и CDCСкоро
  • эксплуатация и карта выбораСкоро

Документные. Гибкая схема и вложенность — за них платят на стыке с целостностью. Серия про MongoDB идёт от модели к продакшену: документная модель и схема-дизайн, WiredTiger: движок хранения, индексы вглубь: multikey, ESR, explain, aggregation pipeline вглубь, replica sets, oplog и concerns, sharding вживую, эксплуатация и карта выбора «Mongo или Postgres».

KV и in-memory. Скорость и структуры в памяти. Начать стоит с трезвого разговора о границах применимости: Redis: где помогает, а где только усложняет, затем подключение из кода: Redis из Go, Java и Rust.

Дальше Redis вглубь:

Рядом — вопрос лицензии и форка: Valkey: что изменилось после форкаСкоро.

Шире Redis тема разложена в отдельной серии — Вычисления в оперативной памяти: карта и компромиссы и дальше по системам: Redis как кэш, Tarantool и Picodata: вычисления рядом с даннымиготовится, с 23 сентября, Aerospike и Igniteготовится, с 24 сентября, etcd: координация, а не скоростьготовится, с 25 сентября, бенчмарк и карта выбораготовится, с 26 сентября.

Отдельный класс — wide-column, где распределённость не опция, а исходное условие. ScyllaDB: когда нужна и как думать данными, архитектура shard-per-core, compaction, tombstones и repair, consistency levels и LWT, от token ring к tablets: multi-DC, shard-aware драйверы, эксплуатация и когда она не нужна, плюс практическое: миграции для ScyllaDB в Go.

Поисковые. Полнотекст, релевантность, гео, семантика. Реляционная база это умеет — у PostgreSQL полноценный полнотекстовый поиск с ранжированием, словарями, индексами и подсветкой, и на своих масштабах его вполне достаточно. Специализированный движок берут не потому, что «в SQL нельзя», а за более богатые средства релевантности, горизонтальное масштабирование и эксплуатацию, заточенную под поиск. OpenSearch: индексы, маппинги и шаблоны, сбор данных: API, клиенты, bulk, полнотекстовый поиск: запросы и анализаторы, retention: ISM и rollover, семантический поиск: k-NN и эмбеддинги.

Гео — своя серия: основы: координаты и типы запросовСкоро, алгоритмы и пространственные индексыСкоро, PostgreSQL/PostGISСкоро, MongoDB: 2dsphereСкоро, Redis GEO, OpenSearch, H3/S2, Tile38Скоро, нагрузочный стенд и карта выбораСкоро.

Векторный поиск — тоже поиск, только по смыслу: векторные БД: зачем и когда не нужныготовится, с 25 сентября, ANN вглубь: HNSW, IVF, PQСкоро, pgvector вглубьСкоро, Qdrant, Milvus, WeaviateСкоро, гибридный поиск и rerankingСкоро, фильтрация и консистентность в ANNСкоро, pgvector или выделенная базаСкоро.

Аналитические. Агрегации по большим объёмам, где строковое хранение проигрывает колоночному. ClickHouse: когда нужен OLAP: ClickHouse против PostgreSQL, из Go и Java: MergeTree, вставки, запросы, драйверы: когда какой, материализованные представления и real-time, шардирование и репликация, эксплуатация и тюнинг: merges, mutations, многоуровневое хранение и S3, ClickHouse, TimescaleDB, DuckDB: что выбрать. Отдельно про временные ряды: Time-series БД: TimescaleDB и VictoriaMetricsСкоро.

Когда аналитика перерастает одну базу и становится платформой: YTsaurus: платформа и дерево CypressСкоро, static и dynamic tablesСкоро, вычисления: MapReduce и модель заданийСкоро, движки-мосты: YQL, CHYT, SPYTСкоро, когда YTsaurus честно ваш инструментСкоро.

Распределённые объектные. Не база, но то, на чём базы стоят: Распределённые хранилища: картаСкоро, S3: API и SDKСкоро, реализации S3 после MinIOСкоро, HDFS и когда он нуженСкоро, CDN поверх объектного хранилищаСкоро. Особняком — графовые: графовые БД и Go: где они правда полезныготовится, с 24 сентября.

Что внутри

Этого слоя обычно не хватает, когда выбор делают по табличке «фичи против фич». А он объясняет остальное.

Storage engine — первое, что предопределяет профиль системы: Storage engines: LSM-tree против B-treeСкоро. Тут стоит различать три разные вещи, которые часто валят в одну кучу:

  • LSM (ScyllaDB; Pebble под CockroachDB — он сменил RocksDB и с версии 21.1 остался единственным движком): запись копится в memtable и сбрасывается в SST-файлы. Быстро на записи, а платой идут compaction и усиление чтения и записи (read/write amplification). Отсюда же compaction с tombstones у ScyllaDB.
  • Heap + MVCC (PostgreSQL): таблица лежит кучей, а обновление не меняет строку на месте, а создаёт новую версию — старая остаётся мёртвой. Отсюда dead tuples, VACUUM и bloat. Это следствие MVCC и heap-хранения, а вовсе не B-tree.
  • B-tree в PostgreSQL — это прежде всего тип индекса, а не организация самой таблицы. Его цена своя: поддержка индекса при каждой записи, расщепление страниц и дополнительные записи поверх основной. Оговорка важна, потому что вообще-то B-tree умеет и хранить данные: WiredTiger представляет B-tree’ями сами таблицы, а InnoDB держит строки прямо в кластерном индексе — так что «B-tree» в двух разных базах может означать разное.

Так что и compaction у ScyllaDB, и VACUUM у PostgreSQL — не «недостатки продукта», а обратная сторона выбранной механики хранения.

Журнал упреждающей записи — механизм, который делает базу переживающей падение и заодно даёт репликацию и CDC: WAL: как устроен и как повышает надёжность, WAL и аналоги в разных БД, WAL на службе: репликация, CDC и PITR.

Слово «журнал» при этом означает в разных системах разное, и путать их не стоит — они решают три разные задачи:

  • Восстановление после падения — собственно WAL: журнал пишется до того, как изменение доедет до основных структур. Так устроен WAL у PostgreSQL и отдельный write-ahead journal у WiredTiger в MongoDB.
  • Логическая персистентность — AOF у Redis: это не write-ahead, а лог уже выполненных команд записи, который проигрывается при старте. Отсюда и его особые границы надёжности, разобранные в персистентности Redis.
  • Репликация — oplog у MongoDB: capped-коллекция, из которой реплики забирают изменения. За crash recovery он не отвечает; это работа journal’а WiredTiger.

Общее у всех трёх — идея «запиши, что сделал, отдельным логом». Но источником CDC служат не все: изменения вычитывают наружу из WAL PostgreSQL и из oplog MongoDB. У Redis для этого AOF не используется — репликация идёт своим потоком с backlog’ом. Готовой замены CDC там нет: keyspace notifications работают по принципу fire-and-forget и события терять могут, а Streams требуют, чтобы приложение само в них писало.

Индексы — то, из-за чего запрос идёт миллисекунды вместо минут, и то, из-за чего запись становится дороже: зачем нужны, какие бывают и как устроены, как выбирать и использовать, индексы в разных БД: PostgreSQL, MongoDB, Tarantool, паттерны и антипаттерны, индексы и языки/ORM.

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

Гарантии

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

В распределённых системах цена гарантий видна отчётливее всего: распределённые транзакции: parallel commits и цена SERIALIZABLEготовится, с 29 октября, consistency levels и LWT в ScyllaDB, детерминированные транзакции по CalvinСкоро.

Эксплуатация

Всё, что начинается после «оно работает у меня на ноутбуке». Плотнее всего слой разобран на PostgreSQL: HA: Patroni, репликация и PITRготовится, с 29 сентября, пулинг: PgBouncer и pgcatготовится, с 30 сентября, партиционирование, VACUUM и bloatготовится, с 2 октября, оптимизация запросов: EXPLAIN на практикеготовится, с 6 октября.

Шардирование как отдельная дисциплина — с выбором ключа и болью ре-шардинга: Шардирование на практике: shard key и ре-шардинг. У конкретных систем оно своё: sharding в MongoDB, шардирование ClickHouse, token ring и tablets в ScyllaDB.

И приём, который экономит целый брокер, пока нагрузка позволяет: Postgres как очередь: SKIP LOCKED.

Данные за пределами одной базы

Здесь хранилище перестаёт быть конечной точкой. Серия про инженерию данных: батч-пайплайны и оркестрация: ETL vs ELT, Airflow, dbtСкоро, dimensional modeling: star schema, факты, измеренияСкоро, open table formats: Iceberg, Delta, HudiСкоро, data quality и контракты данныхСкоро, data observability и lineageСкоро.

Как данные попадают в поток — это уже соседняя территория: захват изменений из базы разобран в CDC через Debezium: PostgreSQL → Kafka, а механика, на которой он держится, — в WAL на службе: репликация, CDC и PITR.

И то, чем всё это выглядит из кода: Доступ к данным в разных языках: ORM, query-builder или SQLСкоро.

С чего начать

Четыре маршрута — по тому, с каким вопросом пришли:

Соседние карты

Данные — не единственный хаб. Рядом:

Обсуждение в Telegram

Присоединиться →

Комментарии