Устранение задержки репликации MongoDB: причины и решения

Узнайте, как диагностировать и устранять задержки репликации в наборах реплик MongoDB. Это руководство охватывает распространенные причины, включая высокие нагрузки на запись, узкие места оборудования и проблемы с сетью. Откройте для себя практические методы мониторинга с использованием `rs.printReplicationInfo()` и практические решения для поддержания синхронизации данных, обеспечивая высокую доступность и согласованность чтения на всех узлах базы данных.

Устранение задержки репликации MongoDB: причины и решения

Задержка репликации MongoDB обычно начинается как небольшая операционная неприятность. График начинает расти. Вторичный узел отстает на 15 секунд, затем на 2 минуты. Кто-то спрашивает, не устарели ли данные чтения. Кто-то другой предлагает перезапустить узел. Прежде чем сделать это, замедлитесь и выясните, какая часть репликации теряет позиции.

Вторичные узлы MongoDB копируют операции из oplog первичного узла и применяют их локально. Задержка репликации означает, что вторичный узел не применял операции так же недавно, как первичный. Это может повлиять на чтения со вторичных узлов, резервное копирование, выполняемое со вторичных узлов, аналитические задачи и отказоустойчивость. Это также может скрывать более серьезный риск: если вторичный узел отстает дальше, чем окно oplog, он может вообще не иметь возможности догнать из oplog.

Самый быстрый путь устранения неполадок — ответить на три вопроса:

  • Отстает ли каждый вторичный узел или только один?
  • Является ли задержка временной, постоянной или растущей?
  • Находится ли вторичный узел все еще в пределах окна oplog?

Эти ответы определяют, что делать дальше.

Измерьте задержку без догадок

Начните в mongosh:

rs.status()

Найдите первичный узел и сравните его optimeDate с optimeDate каждого вторичного узла. Также обратите внимание на нездоровые члены, сообщения heartbeat и члены, застрявшие в состояниях, таких как RECOVERING или STARTUP2.

Для более удобной сводки выполните:

rs.printSecondaryReplicationInfo()

В некоторых старых материалах используется rs.printSlaveReplicationInfo(). Если вы поддерживаете старые системы, вы все еще можете увидеть этот помощник. Современная формулировка — «secondary».

Затем проверьте окно oplog:

rs.printReplicationInfo()

Окно oplog — это объем истории, который в настоящее время хранится в oplog. Если ваш вторичный узел отстает на 40 минут, а окно oplog составляет несколько дней, у вас есть время для устранения неполадок. Если ваш вторичный узел отстает на 40 минут, а окно oplog составляет 1 час во время пикового трафика, вы близки к ситуации перестроения.

Не полагайтесь только на значения типа SecondsBehind из одного инструмента. Расхождение часов, задержанные члены и кратковременные всплески могут сделать одно число вводящим в заблуждение. Сравнивайте вывод статуса с графиками мониторинга объема записи, задержки диска, ЦП и пропускной способности сети.

Если все вторичные узлы отстают

Когда каждый вторичный узел отстает примерно в одно и то же время, причина обычно находится выше по потоку от любого отдельного вторичного узла. Сначала посмотрите на нагрузку записи на первичном узле.

Распространенные триггеры включают:

  • Массовые импорты или обратные заполнения.
  • Большие операции updateMany или deleteMany.
  • Очистка TTL после периода отставания.
  • Развертывания приложений, изменившие объем записи.
  • Построение индексов или обслуживание схемы.
  • Внезапное увеличение количества мелких записей, создающих много записей oplog.

Спросите, что изменилось в то же время, когда началась задержка. Всплеск, который начинается точно в момент запуска ночного задания, редко является загадкой MongoDB.

На первичном узле проверьте активные операции:

db.currentOp({ active: true })

Если вы обнаружите пакетное задание, рассмотрите возможность его регулирования вместо того, чтобы позволить ему завершиться на максимальной скорости. Например, обрабатывайте документы в диапазонах _id, делайте паузы между пакетами и следите за задержкой. Это особенно полезно для заданий по очистке, где завершение за 30 минут менее важно, чем поддержание работоспособности набора реплик.

Если постоянный объем записи просто выше, чем может обработать набор реплик, вам потребуется изменение емкости или архитектуры. Лучшие диски, больше ЦП, другой класс экземпляра, оптимизация пути записи или шардирование могут быть правильным ответом. Изменение предпочтения чтения не исправит первичный узел, который производит больше работы, чем может применить набор.

Если отстает только один вторичный узел

Один отстающий вторичный узел обычно указывает на локальную проблему. Войдите на этот хост и проверьте основы:

iostat -xz 1
vmstat 1
top

Внутри MongoDB используйте:

mongostat --host secondary.example.com:27017
mongotop --host secondary.example.com:27017

Диск является частым виновником. Вторичный узел, использующий более медленное хранилище, чем первичный, может нормально работать при обычном трафике и отставать во время всплесков. Облачные тома также могут достигать пределов пропускной способности или IOPS. Ищите высокую загрузку, высокое время ожидания и очереди.

ЦП может иметь значение, когда рабочая нагрузка включает много обновлений, сжатие, шифрование или интенсивный трафик запросов на том же члене. Память важна, когда вторичный узел не может удерживать горячие данные и индексы в кеше, одновременно применяя записи.

Также проверьте, что еще работает на хосте. Резервное копирование, сканирование антивирусом, снимки файловой системы, сжатие журналов и отчетные запросы могут конкурировать с репликацией. Если отстающий узел также является «безопасным местом», где все запускают ad-hoc аналитику, вы, вероятно, нашли проблему.

Чтения со вторичных узлов могут создавать задержку

Чтения со вторичных узлов не бесплатны. Они используют тот же кеш, ЦП и диск, которые необходимы для репликации. Одной агрегации, сканирующей большую коллекцию, может быть достаточно, чтобы заставить вторичный узел отставать в загруженный период.

Ищите длительные чтения:

db.currentOp({ active: true })

Если приложение отправляет чтения на вторичные узлы, проверьте предпочтение чтения. secondary может заставлять чтения на отстающие члены. secondaryPreferred все еще может возвращать устаревшие данные. Для пользовательских потоков, которые должны читать свои собственные записи, используйте первичный узел. Для чтений с конечной согласованностью установите maxStalenessSeconds, чтобы драйвер избегал вторичных узлов, которые слишком сильно отстают.

Для отчетных нагрузок рассмотрите скрытый вторичный узел или отдельный конвейер аналитики. Скрытые члены все еще могут реплицироваться, но драйверы не будут выбирать их для обычных чтений. Это делает их лучшим местом для резервного копирования или контролируемых отчетных заданий, при условии, что вы правильно их размеряете.

Размер oplog — это запас для восстановления, а не исправление скорости

Слишком маленький oplog обычно сам по себе не вызывает задержку. Он делает задержку опасной. Если вторичный узел отстает и необходимые записи oplog перезаписываются, он не может нормально догнать.

Ваше окно oplog должно быть длиннее, чем ваши реалистичные сценарии простоя и обслуживания. Если вторичный узел может быть отключен на 6 часов во время установки исправлений, окна oplog в 4 часа недостаточно. Если ежеквартальный импорт сжигает oplog за несколько часов, увеличьте размер для этой рабочей нагрузки или измените способ выполнения импорта.

В поддерживаемых версиях измените размер с помощью replSetResizeOplog на каждом члене, которому нужен больший oplog:

use admin
db.adminCommand({ replSetResizeOplog: 1, size: 20480 })

Этот пример запрашивает около 20 ГБ. В управляемых платформах используйте метод управляемой конфигурации. Избегайте старых советов, которые удаляют и воссоздают oplog, если только вы не следуете тщательно протестированной процедуре восстановления.

После увеличения oplog продолжайте устранять основную причину задержки. Больший oplog дает вам больше времени; он не устраняет насыщение диска, ограничения сети или чрезмерные всплески записи.

Проверки сети, которые действительно помогают

Проблемы с сетью более вероятны, когда задержка затрагивает удаленный вторичный узел, одну зону доступности или один путь центра обработки данных. Начните с простого:

ping primary.example.com
traceroute primary.example.com

Затем посмотрите за пределы задержки. Репликации требуется надежная пропускная способность. Потеря пакетов, проверка брандмауэром, ограничения VPN, ограничения пропускной способности между регионами или перегруженные сетевые интерфейсы могут создавать задержку, даже если ping выглядит приемлемым.

Если отстает только член в другом регионе, сравните его с локальным вторичным узлом при той же нагрузке записи. Возможно, вам понадобится другая топология, более крупный канал или более четкое ожидание того, что удаленные члены предназначены для аварийного восстановления, а не для свежих чтений.

Расхождение данных и индексов

Члены набора реплик должны иметь одинаковые индексы. Если это не так, применение oplog может замедлиться или завершиться ошибкой. Обычно это происходит из-за ручных изменений, неудачного обслуживания или члена, восстановленного из несогласованного источника.

Сравните индексы в горячих коллекциях:

db.orders.getIndexes()

Выполните его на первичном и на отстающем вторичном узлах. Если определения различаются, исправьте расхождение намеренно. Перестроение большого индекса может добавить дополнительную нагрузку, поэтому планируйте его осторожно или перестройте член из чистого источника, если различия широко распространены.

Расхождение данных более серьезно. Если ошибки репликации показывают отсутствующие записи или дублирующиеся ключи, задержка — уже не единственная проблема. Вам нужно проверить ошибку, сравнить данные и решить, является ли восстановление на уровне таблицы, повторная синхронизация или полное перестроение самым безопасным путем.

Будьте консервативны с перезапусками и начальной синхронизацией

Перезапуск отстающего вторичного узла иногда помогает, если процесс застрял из-за временной проблемы. Это не универсальное исправление. Если член находится близко к краю окна oplog, перезапуск может стоить достаточно времени, чтобы перевести его в невосстановимое состояние.

Перед перезапуском проверьте:

  • Текущую задержку.
  • Текущее окно oplog.
  • Синхронизируется ли член.
  • Существуют ли другие здоровые вторичные узлы.
  • Может ли набор реплик выдержать отключение члена.

Начальная синхронизация — это чистый ответ, когда вторичный узел не может догнать или его данные ненадежны. Она также тяжелая. Она копирует данные, строит индексы и потребляет ресурсы от другого члена. Перестраивайте по одному члену за раз и убедитесь, что ваша конфигурация голосования все еще поддерживает безопасные выборы, пока узел перестраивается.

Когда не следует спешить с исправлением

Некоторая задержка ожидаема во время контролируемой работы. Если вы выполняете плановое обратное заполнение, восстанавливаете вторичный узел или импортируете исторические данные, полезный вопрос заключается в том, догоняет ли вторичный узел с приемлемой скоростью. График задержки, который растет в течение 20 минут, а затем неуклонно падает, может не требовать вмешательства. График задержки, который растет каждый день и никогда не возвращается к базовому уровню, требует.

Это различие важно, потому что некоторые исправления являются разрушительными. Убийство пакетного задания может оставить данные приложения частично обновленными. Перезапуск вторичного узла может стоить тепла кеша и замедлить догон. Перестроение члена может потреблять больше сети и диска, чем просто позволить ему применить отставание.

Для плановых заданий установите бюджет задержки до начала задания. Например, вы можете решить, что обслуживающее обратное заполнение может создать до 10 минут задержки на отчетном вторичном узле, но не на кандидате на отказоустойчивость. Следите за задержкой, окном oplog и скоростью записи во время выполнения задания. Если задание приближается к бюджету, приостановите его или уменьшите размер пакета.

Также полезно разделять реплики, ориентированные на пользователя, и реплики для обслуживания. Вторичный узел, используемый для чтений приложения, должен иметь более жесткий допуск по задержке, чем скрытый член, используемый для резервного копирования. Если каждый вторичный узел имеет разную задачу, пороги оповещений должны отражать эти задачи вместо использования одного числа для всего набора.

Что записывать во время инцидента

Инциденты репликации гораздо легче понять постфактум, если вы сохраните правильные доказательства. Перед изменением конфигурации запишите:

rs.status()
rs.conf()
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()

Также сохраните метрики уровня хоста с первичного и отстающего вторичного узлов: задержку диска, ЦП, память и пропускную способность сети. Если выполнялось пакетное задание или развертывание, запишите время его начала и команду или версию релиза.

Это не бумажная работа ради самой бумажной работы. Без временной шкалы следующий инцидент начинается с нуля. С временной шкалой вы можете заметить, что задержка всегда следует за определенным экспортом, резервным копированием или задачей очистки. Это превращает расплывчатую проблему базы данных в планируемую проблему емкости.

Практическая карта исправлений

Используйте симптом, чтобы выбрать следующее действие:

Симптом Вероятная область Следующее действие
Все вторичные узлы отстают во время пакетного задания Всплеск записи Регулировать или разделить задание
Один вторичный узел всегда отстает Локальная проблема ресурсов Проверить диск, ЦП, память и локальные чтения
Задержка растет только на удаленном члене Сеть/топология Проверить пропускную способность, потерю пакетов и дизайн между регионами
Задержка близка к окну oplog Риск восстановления Увеличить oplog и уменьшить источник задержки
Вторичный узел обслуживает устаревшие чтения Предпочтение чтения Использовать первичный узел для свежих чтений или установить maxStalenessSeconds
Член не может догнать после простоя Отсутствующая история oplog Перестроить из резервной копии или начальной синхронизации

Хорошее устранение неполадок репликации MongoDB — это в основном дисциплинированное наблюдение. Выясните, производит ли первичный узел слишком много работы, применяет ли вторичный узел слишком медленно или связь между ними ограничена. Затем измените то, что на самом деле ограничивает репликацию, вместо применения общего перезапуска, повторной синхронизации или настройки конфигурации.