Мониторинг производительности MongoDB: основные команды и метрики
Научитесь проактивно отслеживать производительность MongoDB с помощью ключевых команд оболочки. В этом руководстве подробно описано, как отслеживать состояние подключений через `db.currentOp()` и `db.serverStatus()`, анализировать медленные запросы с помощью команд профилирования (`db.setProfilingLevel`) и интерпретировать важнейшие метрики, связанные с использованием ресурсов и состоянием индексов для оптимальной настройки базы данных.
Мониторинг производительности MongoDB: основные команды и метрики
Эффективное управление базами данных зависит от надежного мониторинга. Для MongoDB, ведущей NoSQL-документной базы данных, понимание показателей производительности имеет решающее значение для обеспечения высокой доступности и быстродействия. Медленные запросы, чрезмерное потребление ресурсов или неожиданные всплески подключений могут серьезно повлиять на производительность приложения.
Когда MongoDB замедляется, первый полезный вопрос — не «плохая ли база данных?». Он звучит так: «Что сейчас делает сервер, и отличается ли это от нормы?». Приведенные ниже команды — это те, которые я использую для первичной проверки перед изменением индексов, масштабированием оборудования или обвинением приложения.
Основные команды мониторинга в оболочке MongoDB (mongosh)
Основной интерфейс для выполнения этих команд — оболочка MongoDB Shell (mongosh) или устаревшая оболочка mongo. Все команды, показанные здесь, выполняются в этой среде оболочки.
1. Понимание текущих подключений: db.currentOp() и db.serverStatus()
Мониторинг активных подключений жизненно важен для предотвращения исчерпания подключений и выявления длительных операций, которые могут блокировать ресурсы.
db.currentOp()
Эта команда возвращает информацию об операциях, выполняющихся в данный момент в базе данных. Она незаменима для выявления медленных или блокирующих запросов в реальном времени.
Пример использования:
Чтобы увидеть все выполняющиеся в данный момент операции:
db.currentOp()
Чтобы специально найти операции, выполняющиеся дольше определенного порога (например, операции, выполняющиеся более 5 секунд):
db.currentOp({"secs_running": {$gt: 5}})
Вывод включает такие детали, как op, ns (пространство имен), query и secs_running.
db.serverStatus()
Хотя эта команда предоставляет всестороннюю информацию о состоянии, ее раздел connections имеет решающее значение для мониторинга пула подключений и лимитов.
Ключевые метрики в serverStatus (раздел Connections):
current: Количество активных подключений к серверу.available: Количество доступных подключений, которые могут быть установлены (на основе настроенного максимума).
db.serverStatus().connections
2. Анализ производительности запросов: db.getProfilingStatus() и db.setProfilingLevel()
MongoDB предоставляет встроенные инструменты профилирования, которые регистрируют детали выполнения операций с базой данных, что позволяет выявлять ресурсоемкие запросы.
Уровни профилирования
Уровни профилирования определяют, какие операции регистрируются:
- 0 (Выкл): Никакие операции не профилируются.
- 1 (Медленные операции): Регистрируются только операции, выполняющиеся дольше настроенного порога (
slowms). - 2 (Все операции): Регистрируются все операции, что создает значительную нагрузку на запись и должно использоваться только кратковременно для целенаправленного устранения неполадок.
Проверка статуса
Чтобы увидеть текущий уровень профилирования:
db.getProfilingStatus()
Установка уровня (пример)
Чтобы включить профилирование только для медленных операций (операций, превышающих 100 миллисекунд):
// Установить slowms в 100 миллисекунд (по умолчанию обычно 100)
db.setProfilingLevel(1, { slowms: 100 })
Совет: Всегда возвращайте профилирование на уровень 0 после сбора необходимой информации, чтобы предотвратить снижение производительности из-за чрезмерного логирования.
Просмотр профилированных медленных запросов
Профилированные операции хранятся в коллекции system.profile в конкретной отслеживаемой базе данных. Чтобы просмотреть 10 самых медленных запросов за последний час:
db.system.profile.find().sort({millis: -1}).limit(10).pretty()
3. Метрики использования ресурсов
Понимание того, как MongoDB использует ресурсы ЦП, памяти и ввода-вывода, необходимо для принятия решений о масштабировании.
Использование памяти и хранилища: db.serverStatus()
Разделы globalLock и storageEngine в serverStatus дают глубокое понимание управления ресурсами.
Индикаторы памяти:
resident: Объем физической памяти, используемый процессом.virtual: Общий объем виртуальной памяти, выделенный процессом.
db.serverStatus().globalLock
Мониторинг конкуренции за блокировки
MongoDB использует внутренние механизмы блокировки. Мониторинг захвата блокировок и ожиданий помогает выявить узкие места параллелизма.
Ключевые метрики в globalLock:
currentQueue.readers: Количество читателей, ожидающих блокировку.currentQueue.writers: Количество писателей, ожидающих блокировку.totalTime: Общее время, затраченное на ожидание блокировок во всех операциях.
Высокие значения в currentQueue часто указывают на отсутствие индексов или чрезмерно длительные операции записи, из-за чего читатели/писатели выстраиваются в очередь.
4. Использование и состояние индексов: db.collection.stats()
Плохо используемые или отсутствующие индексы являются наиболее распространенной причиной снижения производительности. Команда stats() помогает проанализировать эффективность индексов.
При выполнении для конкретной коллекции (например, users):
db.users.stats()
Ключевые метрики для проверки:
totalIndexSize: Общий объем дискового пространства, занимаемый всеми индексами этой коллекции.indexSizes: Разбивка использования пространства по каждому индексу.- Если индекс присутствует, но никогда не используется для чтения, это накладные расходы, которые следует рассмотреть для удаления.
5. Дисковый ввод-вывод и пропускная способность: db.serverStatus() (Сеть и операции)
Мониторинг сетевой активности и скорости операций дает представление о пропускной способности базы данных.
Скорость операций (из opcounters):
opcounters отслеживает общее количество операций, выполненных с момента последнего перезапуска сервера, с разбивкой по типам:
insert,query,update,delete,getmore,command.
Отслеживая изменения этих счетчиков с течением времени (например, сравнивая два последовательных вызова serverStatus), можно вычислить операционную пропускную способность (операций в секунду).
Пример сравнения:
- Выполните
db.serverStatus().opcountersв момент времени T1. - Выполните
db.serverStatus().opcountersв момент времени T2. - Вычтите значения T1 из значений T2, чтобы получить общее количество операций, выполненных за этот интервал.
Лучшие практики проактивного мониторинга
- Автоматизация — ключ к успеху: Полагаться исключительно на ручные команды оболочки неэффективно. Интегрируйте мониторинг с помощью таких инструментов, как MongoDB Cloud Manager/Ops Manager или сторонних решений для мониторинга, которые автоматически запрашивают эти конечные точки.
- Установите базовые показатели: Выполняйте команды, когда система работает нормально, чтобы установить базовый уровень производительности. Любое отклонение от этого базового уровня требует немедленного расследования.
- Сосредоточьтесь на задержке: Хотя количество операций полезно, при диагностике проблем с пользовательским опытом отдавайте приоритет метрикам задержки (например, времени, сообщаемому журналами профилирования), а не сырой пропускной способности.
- Часто проверяйте подключения: В приложениях с высоким трафиком лимиты подключений часто достигаются в первую очередь. Отслеживайте
db.serverStatus().connections.currentотносительно настроенного максимума.
Практический контрольный список для первой проверки
Когда кто-то говорит «MongoDB тормозит», не спешите сразу менять индексы. Начните с короткого контрольного списка и запишите, что вы видите.
Проверьте, не перегружен ли сервер активными операциями:
db.currentOp({
active: true,
secs_running: { $gt: 2 }
});
Несколько длительных операций могут быть нормой для аналитических заданий. Большая куча операций записи, сканирований коллекций или заблокированных операций — это другое дело. Посмотрите на пространство имен в ns, тип операции в op и форму запроса. Если многие операции ожидают завершения одного обновления или построения индекса, решение будет отличаться от случая отсутствующего индекса для запроса на чтение.
Затем проверьте подключения:
db.serverStatus().connections;
Быстрый рост current может означать, что пул подключений приложения настроен неправильно, при развертывании создано слишком много рабочих процессов или клиенты тайм-аутятся и переподключаются. Значение available, близкое к нулю, является критическим сигналом, поскольку новые клиенты могут не подключиться. Правильным решением может быть настройка пула в приложении, а не увеличение лимита сервера.
Затем дважды проверьте счетчики операций с небольшим интервалом:
const a = db.serverStatus().opcounters;
sleep(5000);
const b = db.serverStatus().opcounters;
printjson({
insertPer5s: b.insert - a.insert,
queryPer5s: b.query - a.query,
updatePer5s: b.update - a.update,
deletePer5s: b.delete - a.delete,
commandPer5s: b.command - a.command
});
Счетчики с момента запуска полезны для долгосрочного контекста, но разности за известный интервал говорят вам о том, что происходит сейчас. Если трафик команд высок, а запросов мало, возможно, вы имеете дело с проверками метаданных, шумом мониторинга или поведением драйвера, а не с обычными операциями чтения.
Использование explain() перед тем, как винить оборудование
Коллекция профиля может сказать вам, какие операции медленные. explain() помогает понять, почему запрос медленный, прежде чем добавлять ЦП или память.
db.users.find({ email: "[email protected]" }).explain("executionStats");
В выводе сравните totalDocsExamined с nReturned. Если MongoDB просматривает огромное количество документов, чтобы вернуть одного пользователя, запросу, вероятно, нужен лучший индекс или другой фильтр. Если totalKeysExamined высок, индекс существует, но может быть недостаточно селективным для шаблона запроса.
Для составного запроса важен порядок индексов:
db.orders.find({
accountId: "acct_123",
status: "open",
createdAt: { $gte: ISODate("2025-11-01T00:00:00Z") }
}).sort({ createdAt: -1 });
Полезным индексом может быть:
db.orders.createIndex({ accountId: 1, status: 1, createdAt: -1 });
Это не универсальное правило. Лучший индекс зависит от кардинальности, порядка сортировки и полного набора запросов, попадающих в коллекцию. Суть в том, чтобы заставить базу данных показать вам план выполнения, а не гадать.
Чтение данных профилирования без излишней реакции
Уровень профилирования 2 регистрирует каждую операцию и может создавать дополнительную нагрузку на загруженные системы. Используйте его только в течение короткого целенаправленного окна. Уровень 1 с разумным порогом slowms безопаснее для поиска медленных операций.
db.setProfilingLevel(1, { slowms: 200 });
После сбора данных проверьте самые медленные записи:
db.system.profile.find(
{},
{
ns: 1,
op: 1,
millis: 1,
command: 1,
keysExamined: 1,
docsExamined: 1,
nreturned: 1
}
).sort({ millis: -1 }).limit(20).pretty();
Один медленный запрос не всегда означает инцидент в продакшене. Плановый отчет, холодный кеш после перезапуска или редкая задача обслуживания могут оказаться наверху. Закономерности важнее, чем единичный пример. Если одна и та же форма запроса появляется повторно и просматривает гораздо больше документов, чем возвращает, у вас есть реальный кандидат для настройки.
Мониторинг наборов реплик и нагрузки на хранилище
Для наборов реплик производительность зависит не только от первичного узла. Вторичный узел, который отстает, может повлиять на уверенность в отказоустойчивости и рабочие нагрузки чтения, если клиенты используют чтение со вторичных узлов.
rs.status();
Ищите нездоровые узлы, неожиданные изменения состояния или задержку репликации, которая не восстанавливается. Точная допустимая задержка зависит от приложения. Рабочая нагрузка типа очереди может допускать небольшую задержку. Информационная панель, обещающая чтение, близкое к реальному времени, — возможно, нет.
Нагрузка на хранилище требует такого же контекста. db.serverStatus() может показывать метрики механизма хранения и WiredTiger, но инструменты уровня диска по-прежнему важны. Если MongoDB ожидает медленные диски, команды оболочки внутри базы данных будут показывать симптомы, а не первопричину. Соотносите с метриками хоста, такими как задержка диска, использование файловой системы, кража ЦП и давление памяти.
Превращение ручных проверок в оповещения
Ручные команды лучше всего подходят во время расследования. Для нормальной работы преобразуйте полезные сигналы в автоматические проверки: использование подключений, состояние репликации, частота медленных запросов, использование диска, сбои страниц или давление кеша (где доступно) и задержка операций. Оповещайте об устойчивом плохом поведении, а не о каждом минутном всплеске.
Хорошие оповещения включают контекст. «Высокая частота медленных запросов MongoDB» менее полезна, чем оповещение, которое включает базу данных, коллекцию, форму запроса, текущую частоту и ссылку на недавние образцы профиля или панели информационной панели. Цель — сократить первые десять минут инцидента.
Чего не следует делать во время замедления
Избегайте внесения нескольких изменений одновременно. Добавление индекса, увеличение лимитов подключений, перезапуск приложения и изменение размеров пула в рамках одного инцидента могут устранить симптом, но вы не будете знать, какое действие помогло. Внесите одно изменение, следите за метрикой, которая должна улучшиться, и делайте заметки.
Будьте осторожны с killOp. Он может быть полезен, когда одна операция явно вредна, но убийство случайных длительных операций может ухудшить поведение приложения. Если операция принадлежит миграции, резервному копированию, построению индекса или заданию по формированию отчетов, определите владельца, прежде чем останавливать ее, если только база данных уже не в серьезной беде.
Не относитесь к serverStatus() как к единой магической оценке здоровья. Это набор счетчиков и снимков. Высокое значение может быть нормой для большой загруженной системы, а низкое значение может быть плохим для небольшой системы, чувствительной к задержкам. Полезный вопрос — изменилось ли значение таким образом, который соответствует проблеме, видимой пользователю.
Также отделяйте симптомы базы данных от симптомов развертывания. Новый релиз, который меняет форму запроса, открывает более крупные пулы подключений или запускает фоновую миграцию, может сделать MongoDB похожей на первопричину. Сравните время медленных операций с развертываниями, расписаниями заданий, резервными копиями и изменениями трафика, прежде чем вносить исправления только в базу данных.
Мониторинг MongoDB работает лучше всего, когда вы сравниваете текущее поведение с известным базовым уровнем. db.currentOp(), db.serverStatus(), профилирование, explain() и проверки набора реплик дают вам достаточно доказательств, чтобы решить, является ли проблема запросом, индексом, поведением клиентского подключения, репликацией или хостом, лежащим в основе базы данных.