В прошлом уроке три сервера хранили одни и те же данные. Это спасает от аварии, но не от роста: у каждой копии тот же предел диска и та же нагрузка на запись. Когда данных становится больше, чем тянет одна машина, коллекцию делят на части и раскладывают по разным серверам. Сегодня соберём маленький шардированный кластер и увидим главное: всё решает ключ, по которому делят данные.
Картотека в нескольких комнатах
Городской архив перестал помещаться в одну комнату. Карточки разнесли по двум: в одной фамилии от А до К, в другой от Л до Я. У входа сидит дежурный со схемой. Ты называешь фамилию, и он отправляет тебя в нужную комнату. Если ты спросишь «все карточки за 2026 год», дежурному придётся обойти обе комнаты и собрать ответ.
Теперь представь, что карточки разложили по дате поступления. Все новые карточки идут в последнюю комнату, а первая стоит без дела. Схема та же, архив тот же, а работает одна комната из двух. Правило раскладки важнее числа комнат.
Из чего состоит кластер
В шардированном кластере MongoDB три роли:
- Шарды. Комнаты с карточками. Каждый хранит свою долю данных, а в продакшене каждый шард это отдельный replica set из прошлого урока.
- Серверы конфигурации. Схема архива: какие диапазоны ключа на каком шарде.
- mongos. Дежурный у входа. Приложение подключается к нему как к обычному MongoDB и не знает, сколько за ним шардов.
Минимальный кластер для опыта помещается в пять контейнеров: сервер конфигурации, два шарда (каждый как replica set из одного узла) и маршрутизатор.
docker network create mgsh
docker run -d --name cfg1 --network mgsh mongo:8 --configsvr --replSet cfg --port 27017 --bind_ip_all
docker run -d --name sh1 --network mgsh mongo:8 --shardsvr --replSet sh1 --port 27017 --bind_ip_all
docker run -d --name sh2 --network mgsh mongo:8 --shardsvr --replSet sh2 --port 27017 --bind_ip_all
Каждому replica set нужен свой rs.initiate, на сервере конфигурации с флагом configsvr: true:
docker exec cfg1 mongosh --eval "rs.initiate({ _id: 'cfg', configsvr: true, members: [{ _id: 0, host: 'cfg1:27017' }] })"
docker exec sh1 mongosh --eval "rs.initiate({ _id: 'sh1', members: [{ _id: 0, host: 'sh1:27017' }] })"
docker exec sh2 mongosh --eval "rs.initiate({ _id: 'sh2', members: [{ _id: 0, host: 'sh2:27017' }] })"
Маршрутизатор запускается отдельной программой mongos и узнаёт про кластер из серверов конфигурации. Шарды к нему добавляют командой sh.addShard:
docker run -d --name mongos1 --network mgsh --entrypoint mongos mongo:8 --configdb cfg/cfg1:27017 --bind_ip_all --port 27017
docker exec mongos1 mongosh --eval "sh.addShard('sh1/sh1:27017'); sh.addShard('sh2/sh2:27017')"
Дальше вся работа идёт через mongos. Приглашение mongosh на нём выглядит как [direct: mongos] test>.
урок из курса
Урок из курса «MongoDB с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.