MongoDB хранит данные не в таблицах, а в документах BSON, и умеет масштабироваться горизонтально через репликацию и шардирование. В статье — рабочая база: установка, запросы, индексы, replica set из трёх узлов, проверка failover и бэкап, который действительно восстанавливается.
Документная модель
Запись в MongoDB — документ с полями и вложенными структурами. Коллекция объединяет документы по смыслу, но не требует одинаковой схемы. Это удобно для заказов, каталогов и событий, где состав полей меняется. Цена гибкости — дисциплина на стороне приложения: валидацию схемы лучше включить через $jsonSchema, иначе база превратится в свалку.
Вложенные документы хороши, когда данные читаются вместе. Ссылки на отдельные коллекции нужны, когда сущность живёт долго и используется многими документами. Правило простое: встраивайте то, что не растёт без предела, и ссылайтесь на то, что обновляется независимо.
Репликация и шардирование решают разные задачи: replica set повышает доступность и даёт переключение, а шардирование распределяет данные по узлам. Начинать почти всегда стоит с replica set; шардирование добавляет маршрутизацию, ключ шарда и заметно усложняет эксплуатацию.
Установка и первый запуск
Официальный репозиторий MongoDB подключается ключом и списком пакетов. В примере — ветка 8.0 для Ubuntu 24.04; для новой версии замените номер в URL и списке репозитория согласно документации.
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update && sudo apt install -y mongodb-org
sudo systemctl enable --now mongod
sudo systemctl status mongod --no-pager
До включения авторизации создайте администратора: иначе после перезапуска некому будет управлять базой. Пароль вводите через passwordPrompt(), а не открытым текстом в истории shell.
Запросы и индексы
Выборка с проекцией и сортировкой выполняется в mongosh. Индекс строится по полям, которые реально участвуют в фильтре и сортировке; лишние индексы замедляют запись и занимают память.
use shop
db.orders.insertMany([
{orderId: 101, status: "paid", total: 4200, createdAt: new Date()},
{orderId: 102, status: "new", total: 900, createdAt: new Date()}
])
db.orders.find({status: "paid"}, {_id: 0, orderId: 1, total: 1}).sort({total: -1}).limit(5)
db.orders.createIndex({status: 1, createdAt: -1})
db.orders.find({status: "paid"}).sort({createdAt: -1}).explain("executionStats")
В выводе explain смотрите на stage и на отношение totalDocsExamined к nReturned. Если документов просмотрено в десятки раз больше, чем возвращено, индекс не подходит. Порядок полей удобно проверять правилом ESR: сначала Equality, затем Sort, потом Range.
Replica set: три узла
Репликация включается именем набора в конфигурации и одинаковым keyfile на всех узлах. Keyfile обеспечивает аутентификацию между членами набора; права на файл должны быть только у пользователя mongodb.
openssl rand -base64 756 | sudo tee /etc/mongodb.key
sudo chmod 400 /etc/mongodb.key
sudo chown mongodb:mongodb /etc/mongodb.key
# /etc/mongod.conf
replication:
replSetName: rs0
security:
keyFile: /etc/mongodb.key
authorization: enabled
net:
bindIp: 127.0.0.1,192.168.10.11
После запуска все три узла инициируются одной командой с primary. Адреса должны быть доступны друг другу по именам, а не только с вашей машины.
rs.initiate({
_id: "rs0",
members: [
{_id: 0, host: "db1.example.lan:27017", priority: 2},
{_id: 1, host: "db2.example.lan:27017", priority: 1},
{_id: 2, host: "db3.example.lan:27017", priority: 1}
]
})
rs.status()
rs.conf()
Приоритет выше у основного кандидата. Арбитр экономит диск, но не хранит данные и не спасает от отказа единственного оставшегося узла с данными; для продакшена обычно нужны три полноценных члена.
Согласованность и failover
Запись с w: "majority" подтверждается большинством членов набора и переживает потерю primary. Чтение с readConcern: "majority" видит только подтверждённые данные. Для критичных операций задавайте оба параметра явно.
db.orders.insertOne(
{orderId: 103, status: "paid", total: 1500},
{writeConcern: {w: "majority", j: true, wtimeout: 5000}}
)
db.getMongo().setReadPref("secondaryPreferred")
rs.stepDown(60)
db.hello().isWritablePrimary
rs.stepDown(60) уступает роль primary на минуту и запускает выборы. Проверьте, что приложение переподключилось: драйвер должен знать строку с replicaSet=rs0, иначе он будет ходить в один узел и переживёт failover только случайно.
Резервное копирование
mongodump снимает логическую копию. Для replica set указывайте набор в URI, чтобы подключение шло к активному узлу; для восстановления на момент времени нужны oplog или снапшоты диска.
mongodump --uri="mongodb://backup@db1.example.lan:27017/?authSource=admin&replicaSet=rs0" --gzip --archive=/backup/mongo-$(date +%F).gz
mongorestore --gzip --archive=/backup/mongo-2026-11-06.gz --nsInclude="shop.*"
mongosh --quiet --eval 'db.orders.countDocuments()' "mongodb://admin@db1/?authSource=admin"
Проверяйте бэкап восстановлением в отдельную базу, а не только размером файла. Пароль backup-пользователя храните вне скрипта и ограничьте его роль чтением нужных баз.
Диагностика
Смотрите соединения, медленные операции и отставание secondary. mongostat и mongotop дают быстрый срез нагрузки, а currentOp помогает найти зависший запрос.
db.serverStatus().connections
db.currentOp({active: true, secs_running: {$gte: 5}})
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()
mongostat --uri="mongodb://admin@db1/?authSource=admin" --rowcount=5
Если secondary отстаёт, проверьте диск, сеть и размер oplog. Маленький oplog приводит к полной ресинхронизации после короткого простоя — это дорого и заметно по нагрузке.
Чек-лист
- Авторизация включена, администратор создан до открытия порта наружу.
- Индексы покрывают реальные запросы, explain проверен.
- Replica set из трёх узлов, приоритеты и keyfile настроены.
- Write concern majority для критичных операций.
- Бэкап регулярно восстанавливается в тестовую среду.
Итог
MongoDB удобна для гибких документов, но требует тех же дисциплин, что и реляционная база: схема, индексы, контроль согласованности и проверенные бэкапы. Репликация не заменяет резервное копирование, а majority-write не спасёт от ошибки в приложении. Начните с одного узла, затем добавьте набор и прогоните failover на стенде.