3. Шардирование и горизонтальное масштабирование
Шардированный кластер MongoDB распределяет данные по независимым шардам, чтобы масштабировать объём и пропускную способность записи/чтения сверх возможностей одного replica set. Критично спроектировать shard key: плохой ключ даёт hot shard и перекос нагрузки. Ниже — роли mongos, config servers, шарды, типы ключа (ranged / hashed), антипаттерны и короткие команды для лаборатории.
Когда шардировать
| Ситуация | Комментарий |
|---|---|
| Рост данных и I/O | Один replica set упирается в диск/RAM/лидер записи |
| Изоляция нагрузок | Разные диапазоны ключей можно косвенно разнести по шардам |
| Цена сложности | Больше узлов, мониторинг, бэкапы, миграции chunk — только когда есть измеренные причины |
Best practice: сначала индексы, схема, верный replica set и профиль запросов; шардирование — не замена оптимизации на одном кластере.
Архитектура sharded cluster
mongos (router)
- Точка входа для приложения: маршрутизирует операции к нужным шардам по метаданным из config servers.
- Можно поднимать несколько
mongosза балансировщиком для отказоустойчивости и масштабирования маршрутизации. - Production: не подключайтесь к отдельным
mongodшардов для обычных запросов — только черезmongos(или явно осознанные исключения).
Config servers (реплика из трёх членов)
- Хранят метаданные кластера: какие chunks к каким шардам относятся, настройки коллекций, версии конфигурации.
- Потеря кворума config servers — серьёзный инцидент; планируйте бэкапы и восстановление по гайдам MongoDB.
Шарды (обычно — replica set на шард)
- Каждый chunk данных физически живёт на одном шарде; balancer переносит chunks между шардами при перекосе.
- Production: каждый шард = отдельный replica set, не одиночный
mongod.
Схема (логически):
Приложение → mongos ─┬→ config servers (метаданные)
└→ shard A (RS) | shard B (RS) | …
Shard key: ranged vs hashed
Ключ задаётся при shardCollection и не меняется простой командой — смена ключа это тяжёлая операция (перенос данных). Проектирование «с первого раза» обязательно.
Ranged (префиксный / по диапазонам)
- Диапазоны значений ключа отображаются на chunks по порядку.
- Плюс: полезные targeted queries по префиксу ключа (могут идти на один/малый набор шардов).
- Минус: если ключ монотонно растёт (например
ObjectIdпо умолчанию на_idпри вставках «в конец»), все новые документы попадают в один активный chunk → hot shard на записи.
// Включить шардирование БД (один раз)
sh.enableSharding("shop")
// Ranged shard key по полю tenantId + orderId (пример)
sh.shardCollection("shop.orders", { tenantId: 1, orderId: 1 })
Hashed
- MongoDB хэширует значение поля и раскладывает по chunks равномернее при однородном распределении исходного поля.
- Плюс: сглаживает горячую точку для монотонных вставок, если единственный компонент ключа — хэшируемое поле.
- Минус: точечные запросы без включения hashed-поля часто становятся scatter-gather по всем шардам.
sh.enableSharding("shop")
// Hashed по одному полю (частый шаблон для равномерной записи)
sh.shardCollection("shop.events", { ingestId: "hashed" })
// С compound hashed в новых версиях смотрите актуальную документацию — правила менялись по релизам
Best practice: выбирайте поля с высокой кардинальностью и равномерным распределением; избегайте ключей, где 80% записей попадают в мало значений.
Почему «плохой» shard key ломает кластер
| Проблема | Следствие |
|---|---|
| Низкая кардинальность | Мало chunks, мало шардов реально задействовано |
Hot spot (время Date.now() без variance, счётчик, монотонный _id на ranged) |
Один шард получает почти всю запись |
| Неравномерное распределение | Balancer постоянно двигает данные; задержки, лишняя нагрузка |
| Запросы не содержат shard key | Broadcast на все шарды — latency и нагрузка растут |
Production: профилируйте распределение по значениям ключа до продакшена; согласуйте ключ с типичными фильтрами (find, агрегации).
Проверка распределения и состояния кластера
// Обзор шардов, balancer, версия конфига
sh.status()
// Статистика по коллекции (chunks, shard, примеры размеров) — детали зависят от версии
db.orders.getShardDistribution()
// Куда уйдёт запись/чтение — отладка маршрутизации (mongosh)
db.orders.find({ tenantId: "t1" }).explain("executionStats")
Смотрите: количество chunks на шард, нет ли огромного перекоса, включён ли balancer, нет ли зависших миграций.
Практика: поднять sharded cluster
Минимальный учебный кластер (идея):
- 1× config server replica set (в лаборатории исторически допускали упрощения; в production — полноценный replica set config).
- Несколько шардов (хотя бы по одному процессу на шард в учебнике; в production — RS на шард).
- Один или несколько
mongos, указывающих на config DB.
Типичная последовательность после запуска всех процессов:
// На mongos: зарегистрировать шарды (хосты — ваши; формат см. документацию)
sh.addShard("shard1/rs-shard1-1:27017,rs-shard1-2:27017")
sh.addShard("shard2/rs-shard2-1:27017,rs-shard2-2:27017")
sh.enableSharding("labdb")
sh.shardCollection("labdb.metrics", { sensorId: "hashed" })
// Наполнить тестовыми документами и снова проверить
sh.status()
db.metrics.getShardDistribution()
Точные команды и порты зависят от docker-compose / Helm / cloud — ориентируйтесь на официальные туториалы по развёртыванию.
Production checklist (sharding)
| # | Практика |
|---|---|
| 1 | Shard key измерять на репрезентативных данных; избегать hot spots |
| 2 | Каждый шард — replica set; mongos и config servers с мониторингом и резервным копированием |
| 3 | Наблюдать chunk migration, balancer, задержки; алерты на перекос |
| 4 | Миграции схемы и zone (гео/tenant affinity) — заранее по Zones |
| 5 | Тестировать восстановление config + шардов в staging |