Прямой ответ
Выбор хранилища — архитектурное решение с долгим сроком действия: миграция данных дороже почти любого другого изменения в системе. Поэтому критерии стоит формулировать до сравнения конкретных продуктов.
Пять критериев, которые определяют выбор:
1. Модель данных. Как связаны сущности и как к ним обращаются?
| Характер данных | Подходящая модель |
|---|---|
| Связи «один ко многим», транзакции, отчёты по строкам | Реляционная |
| Глубокие обходы связей, поиск по графу | Графовая |
| Самодостаточные записи с вложенностью | Документная |
| Доступ по точному ключу, кэш, счётчики | Key-value |
| Запросы по ключу с сортировкой внутри партиции | Wide-column |
| Массовые агрегации по колонкам | Колоночная |
2. Профиль нагрузки. Соотношение чтения и записи, размер читаемого набора, требования к задержке. Операционные и аналитические нагрузки конфликтуют в одной системе — см. OLTP и OLAP.
3. Требования к согласованности. Нужна ли строгая согласованность после записи, допустима ли временная несогласованность, что происходит при сетевом разделении. Теоретические ограничения — в статье про CAP-теорему.
4. Объём и рост. Данные на одной машине или требуют распределения. Вертикальное масштабирование проще, пока не исчерпано.
5. Стоимость эксплуатации. Знакомство команды, зрелость инструментов, резервное копирование, мониторинг, найм. Этот критерий чаще всего недооценивают и именно он определяет итоговую стоимость владения.
Порядок вопросов при выборе:
- Какие запросы будут выполняться? Выпишите их с фильтрами, сортировкой и ожидаемым объёмом результата.
- Какие гарантии нужны для каждого типа данных? Платёж и счётчик просмотров требуют разного.
- Какой объём сейчас и через два года?
- Какая система уже есть в стеке и что она умеет?
- Что произойдёт при отказе хранилища и как восстанавливаться?
Практическое правило: начинайте с реляционной базы, если нет измеримой причины поступить иначе. PostgreSQL покрывает широкий спектр задач, включая JSON, полнотекстовый поиск, геопространственные данные и оконные функции.
Практика: как принимать решение
1. Проверяйте, достаточно ли основной базы. Прежде чем добавлять новую систему, убедитесь, что задача не решается средствами текущей: специализированные типы индексов, партиционирование, материализованные представления.
2. Добавляйте систему под конкретный класс запросов. Правильный повод — измеримая деградация конкретного сценария. Неправильный — «нам нужен Redis, потому что он быстрый».
3. Считайте стоимость согласованности между системами. Каждая дополнительная система добавляет задачу синхронизации: задержка, расхождения, поведение при сбое, мониторинг. Это постоянные расходы, а не разовые.
4. Прототипируйте на реальных данных. Оценка по документации ошибается в обе стороны. Прогон типовых запросов на копии данных занимает дни и снимает большую часть неопределённости.
5. Фиксируйте решение. Запись «выбрали X вместо Y, потому что измерили Z» экономит месяцы споров позже. О практике фиксации решений — в статье про документацию и ADR.
Типичные ошибки:
- Выбор по популярности. Технология, хорошо работающая в масштабе крупной компании, не обязательно подходит проекту с миллионом записей.
- Преждевременное распределение. Кластеризация до исчерпания возможностей одной машины добавляет сложность без выгоды.
- Полиглотная персистентность без необходимости. Пять систем хранения для одного сервиса — это пять резервных копий, пять мониторингов и пять способов потерять данные. О последствиях такого роста — в статье про технический долг.
- Игнорирование операции восстановления. Система, из которой нельзя восстановить данные за приемлемое время, не подходит независимо от скорости запросов.
- Отсутствие плана выхода. Если через год окажется, что выбор неверен, насколько дорого перенести данные обратно?
Рекомендации:
- Разделяйте данные по критичности. Платежи, пользовательские данные и телеметрия имеют разные требования; хранить их в одной системе с одинаковыми настройками — компромисс в обе стороны.
- Держите источник истины в одном месте. Дополнительные системы должны быть производными и восстанавливаемыми из источника.
- Измеряйте до и после. Без измерений невозможно понять, решило ли новое хранилище исходную проблему.
- Ограничьте число систем в стеке. Каждая новая технология должна заменять класс задач, а не добавляться к существующим.
- Проверяйте сценарий отказа. Отключение хранилища на десять минут — тест, который стоит провести до запуска, а не во время инцидента.
Практический сценарий: разбор стека из семи хранилищ
Контекст: за три года в сервисе накопились PostgreSQL, MongoDB, Redis, Elasticsearch, Cassandra, ClickHouse и очередь на Kafka. Команда тратила значительную часть времени на синхронизацию данных между ними.
- Аудит. Для каждой системы выписали: какие данные хранит, какие запросы обслуживает, можно ли восстановить данные из другой системы.
- Находка 1. MongoDB хранила 2,1 млн документов, из которых 94 % имели одинаковую структуру и использовались в запросах с соединениями. Данные перенесли в PostgreSQL, где соединения работали быстрее.
- Находка 2. Cassandra обслуживала один сценарий — чтение последних событий устройства. Запрос воспроизвели в PostgreSQL с партиционированием по времени; производительность оказалась приемлемой при текущем объёме.
- Находка 3. Redis использовался как кэш и как единственное хранилище для части данных о сессиях. Хранение привели к основному источнику, Redis оставили только в роли кэша.
- Что оставили. PostgreSQL как источник истины, Redis как кэш, Elasticsearch для поиска, ClickHouse для аналитики, Kafka для обмена событиями. Семь систем сократились до пяти, причём каждая имеет ясную роль.
- Результат. Число задач синхронизации сократилось с одиннадцати до четырёх, время восстановления системы после сбоя уменьшилось, число инцидентов с расхождением данных снизилось.
Вывод: каждая дополнительная система хранения — это постоянная работа по согласованию данных. Сокращение стека почти всегда даёт больший выигрыш, чем добавление очередной специализированной базы.
FAQ
С чего начинать новый проект? С реляционной базы, если нет измеримой причины иначе. Она покрывает транзакции, соединения, JSON, полнотекстовый поиск и геопространственные задачи, а её инструменты резервного копирования и мониторинга наиболее зрелые.
Когда точно нужна отдельная система? Когда есть измеримая деградация конкретного сценария, которая не устраняется настройкой текущей базы: глубокие обходы графа, полнотекстовый поиск с высокой нагрузкой, массовые аналитические агрегации, доступ по ключу с сотнями тысяч операций в секунду.
Что такое полиглотная персистентность? Подход, при котором разные данные хранятся в разных системах, подобранных под задачу. Он оправдан при наличии разных профилей нагрузки и становится проблемой, когда системы добавляются без ясной роли.
Как оценить готовность команды к новой технологии? Проверить, есть ли опыт эксплуатации: резервное копирование, обновление версий, восстановление после сбоя, мониторинг. Отсутствие ответов на эти вопросы означает, что технология будет эксплуатироваться в аварийном режиме.
Источники: PostgreSQL docs (index types), Redis docs (data types), Wikipedia (polyglot persistence) — ссылки в шапке.