2. Архитектура: replica set и WiredTiger
Replica set — минимально осмысленная топология MongoDB в production: отказоустойчивость и основа для бэкапов и обновлений без длинного простоя. Отдельный mongod без репликации годится разве что для локальной разработки. Ниже — роли узлов, выборы лидера (election), write/read concern, движок WiredTiger и практика с тремя узлами.
Зачем replica set в production
| Идея | Комментарий |
|---|---|
| Высокая доступность | При падении primary кластер сам выбирает нового лидера |
| Чтение с вторичных | Распределение read-only нагрузки (read preference) — с оговорками по задержке репликации |
| Rolling updates | Обновление версии MongoDB по узлу, пока кворум жив |
| Операционная дисциплина | Бэкапы, точки восстановления — проектировать отдельно; реплика не заменяет бэкап |
Один инстанс без репликации: любой сбой диска/хоста = простой и риск потери данных при неверном writeConcern.
Роли узлов: Primary, Secondary, Arbiter
Primary
- Принимает записи (в типичной схеме приложение пишет только в primary).
- Записи попадают в oplog; вторичные тянут oplog и применяют изменения.
Secondary
- Копирует данные с primary (через oplog).
- Может обслуживать чтения, если драйвер/запрос настроены на
secondary/secondaryPreferredи это осознанно (см. stale reads).
Arbiter (голосует, данных не хранит)
- Участвует только в голосовании за primary, чтобы набрать нечётное число голосов при двух data-узлах.
- Production: по возможности избегайте «primary + secondary + arbiter» как единственной схемы: при падении одной data-ноды остаётся один носитель данных — нет избыточности копии. Предпочтительнее три data-узла (или 2 data + arbiter только как компромисс с пониманием рисков).
Election: что происходит при падении primary?
Кратко:
- Узлы перестают получать heartbeat от primary.
- Условия кворума и приоритетов проверяются; secondary инициирует выборы.
- Один узел становится новым primary (часто за несколько секунд, зависит от сети и настроек).
- Драйвер с SRV/seed list узнаёт нового primary и перенаправляет записи.
Вопрос уровня middle+: что будет с приложением?
| Аспект | Практика |
|---|---|
| Записи во время переключения | Краткое окно: NotWritablePrimary / сетевые ошибки — драйверы часто повторяют запись после появления нового primary |
| Уже «подтверждённая» запись | Зависит от writeConcern: w: "majority" + journal там, где нужна устойчивость к падению узла |
| Чтения с secondary | Возможны устаревшие данные до догона вторичной за новым oplog |
| Split-brain / partition | Настройки кворума и сеть между узлами критичны; «один узел думает, что он primary» в изолированной партиции — отдельная тема (см. документацию по election и priority) |
Best practice: в connection string указывайте все члены replica set (или SRV), включите разумный retryWrites там, где поддерживается, и явно задайте writeConcern для доменно важных операций.
Пример: явный write concern при записи
// Вставка с ожиданием подтверждения на majority узлов (типично для критичных данных)
db.orders.insertOne(
{ orderId: "ORD-2001", total: 10 },
{ writeConcern: { w: "majority", wtimeout: 5000 } },
)
Read Concern и чтение с вторичных
| Значение | Смысл (упрощённо) |
|---|---|
local |
Данные как видит узел локально; для secondary — могут быть ещё не реплицированы все записи primary |
majority |
Чтение только подтверждённой majority записи (сильнее для согласованности, дороже по задержке) |
available |
Оптимизация для шардов; для реплик детали см. документацию |
// Пример: чтение с согласованностью majority (mongosh; в приложении — опции драйвера)
db.orders.find({ orderId: "ORD-2001" }).readConcern("majority")
Production: если читаете с secondary, документируйте допустимую рекламацию (lag) и используйте readConcern / readPreference согласно продуктовым требованиям.
Storage Engine: WiredTiger
Современный движок по умолчанию — WiredTiger.
| Компонент | Комментарий |
|---|---|
| Кэш | Внутренний cache WT; на выделенном сервере часто ориентируются на ~50% RAM под WiredTiger (не жёсткое правило — смотреть метрики и конкуренцию с ОС page cache) |
| Сжатие | Коллекции/индексы могут использовать snappy / zstd — экономия диска, небольшой CPU overhead |
| Журнал (journaling) | Гарантия durability при некорректном выключении; в production journaling обычно включён |
Best practice: не отключайте journaling на боевых узлах; подбирайте RAM и мониторьте использование cache, slow ops, cache pressure.
Практика: три узла replica set (локально)
Упрощённая схема — три mongod в одной сети Docker с общим ключом и одним именем replica set rs0.
1. Запуск трёх инстансов (идея)
На каждом узле: один и тот же --replSet rs0, разные порты/имена, общий keyFile для внутренней аутентификации членов (в production обязательно).
# Пример ключя (права 400) — только для лаборатории
openssl rand -base64 756 > rs-keyfile
chmod 400 rs-keyfile
Типичные флаги процесса (концептуально):
mongod --replSet rs0 --bind_ip_all --port 27017 --keyFile /path/to/rs-keyfile
# второй узел: порт 27018, третий: 27019 — на разных контейнерах/хостах
2. Инициализация и проверка
Подключитесь к одному узлу и выполните:
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo1:27017", priority: 2 },
{ _id: 1, host: "mongo2:27017", priority: 1 },
{ _id: 2, host: "mongo3:27017", priority: 1 },
],
})
// Статус: кто primary, кто secondary, здоровье
rs.status()
// Конфигурация (priority, votes, hidden и т.д.)
rs.conf()
3. Симуляция: падение primary
- Остановите контейнер/процесс текущего primary (смотрите
rs.status().members→stateStr: "PRIMARY"). - Через несколько секунд другой узел станет PRIMARY;
rs.status()покажет смену. - Запишите приложением в паузу — ожидайте краткие ошибки, затем восстановление после reconnect.
4. Симуляция: network partition
- Изолируйте primary от остальных (iptables / отдельная Docker network без маршрута к majority).
- Узел в меньшинстве не должен обслуживать записи как primary долго (поведение зависит от сценария); majority сторона выберет нового primary.
- Production-урок: избегайте топологий, где один ЦОД = «ровно половина» голосов без продуманного Replica Set Across Datacenters.
Production checklist (replica set)
| # | Практика |
|---|---|
| 1 | Минимум три голосующих узла с пониманием, где живут данные (не только arbiter) |
| 2 | Явный writeConcern для критичных путей; readConcern / readPreference — по SLA |
| 3 | Мониторинг repl lag, elections, oplog window, CPU/RAM WiredTiger |
| 4 | TLS, аутентификация, keyFile или x509 между членами; секреты из vault |
| 5 | Регулярные бэкапы (filesystem snapshots / mongodump + policy RTO/RPO) и тест восстановления |