Как отслеживать производительность MongoDB

Автор выбрал Фонд открытого интернета/Свободы слова

Введение

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

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

Предварительные требования

Для выполнения этого руководства вам понадобятся следующие компоненты:

  • A server with a regular, non-root user with sudo privileges and a firewall configured with UFW. This tutorial was validated using a server running Ubuntu 20.04, and you can prepare your server by following this initial server setup tutorial for Ubuntu 20.04.
  • MongoDB, установленная на вашем сервере. Чтобы настроить это, следуйте нашему руководству по Установке MongoDB на Ubuntu 20.04.
  • Ваш экземпляр MongoDB на сервере защищенный с помощью аутентификации и создания административного пользователя. Чтобы обеспечить безопасность MongoDB, следуйте нашему руководству по Как защитить MongoDB на Ubuntu 20.04.
  • Знание запросов к коллекциям MongoDB и фильтрации результатов. Чтобы узнать, как использовать запросы MongoDB, следуйте нашему руководству по Как создавать запросы в MongoDB.

Примечание: Ссылочные руководства по настройке сервера, установке MongoDB и защите установки MongoDB относятся к Ubuntu 20.04. Это руководство сосредотачивается на самой MongoDB, а не на базовой операционной системе. Обычно оно работает с любой установкой MongoDB, независимо от операционной системы, при условии, что включена аутентификация.

Шаг 1 — Подготовка тестовых данных

Для объяснения того, как можно отслеживать производительность MongoDB, этот шаг описывает, как открыть оболочку MongoDB для подключения к вашему локально установленному экземпляру MongoDB и создать в нем образцовую коллекцию.

Для создания образца коллекции, использованной в этом руководстве, подключитесь к оболочке MongoDB в качестве вашего административного пользователя. В этом руководстве используются соглашения предварительного руководства по безопасности MongoDB и предполагается, что имя этого административного пользователя AdminSammy, а его база аутентификации – admin. Обязательно измените эти детали в следующей команде, чтобы они соответствовали вашей собственной настройке, если она отличается:

  1. mongo -u AdminSammy -p --authenticationDatabase admin

Введите пароль, установленный во время установки, чтобы получить доступ к оболочке. После ввода пароля вы увидите приглашение >.

Примечание: При свежем подключении оболочка MongoDB будет подключена к базе данных test по умолчанию. Вы можете безопасно использовать эту базу данных для экспериментов с MongoDB и оболочкой MongoDB.

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

  1. use database_name

Мониторинг базы данных не очень практичен или полезен при работе с небольшим набором данных, поскольку системе баз данных будет достаточно отсканировать несколько записей для любого заданного запроса. Чтобы проиллюстрировать функции мониторинга производительности MongoDB, вам понадобится база данных с достаточным количеством данных, чтобы MongoDB заняло значительное время на выполнение запросов.

Для этой цели примеры в этом руководстве относятся к образцовой коллекции с именем accounts, содержащей большое количество документов. Каждый документ представляет собой отдельный банковский счет с случайно сгенерированным балансом счета. Каждый документ в коллекции будет иметь структуру, подобную этой:

An example bank account document
{
    "number": "1000-987321",
    "currency": "USD",
    "balance": 431233431
}

Этот примерный документ содержит следующую информацию:

  • number: Это поле представляет номер счета для данного счета. В этой коллекции каждый номер счета будет иметь префикс 1000-, за которым следует увеличивающийся числовой идентификатор.
  • currency: Это поле указывает, в какой валюте хранится баланс каждого счета. Значение currency каждого счета будет либо USD, либо EUR.
  • balance: Это показывает баланс для каждого данного банковского счета. В этой примерной базе данных поле balance каждого документа будет иметь случайно сгенерированное значение.

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

  1. for (let i = 1; i <= 1000000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "1000-" + i,
  4. "currency": i > 500000 ? "USD" : "EUR",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Этот код выполняет цикл for, который запускается миллион раз подряд. Каждый раз, когда цикл итерируется, он выполняет метод insertOne() в коллекции accounts для вставки нового документа. В каждой итерации метод задает значение для поля number, состоящее из префикса 1000- с значением, содержащимся в переменной i для этой итерации. Это означает, что при первой итерации этого цикла значение поля number будет установлено на 1000-1; при последней итерации оно будет установлено на 1000-1000000.

Валюта всегда представлена как USD для счетов с номерами выше 500000 и как EUR для счетов с номерами ниже этого значения. Поле баланса использует функцию Math.random() для генерации случайного числа от 0 до 1, а затем умножает это случайное число на 100000, чтобы получить более крупные значения.

Примечание: Выполнение этого цикла может занять длительное время, даже более 10 минут. Безопасно дождаться завершения операции.

Вывод сообщит вам об успешном выполнении и вернет ObjectId последнего вставленного документа:

Output
{ "acknowledged" : true, "insertedId" : ObjectId("61a38a4beedf737ac8e54e82") }

Вы можете убедиться, что документы были правильно вставлены, запустив метод count() без аргументов, который вернет количество документов в коллекции:

  1. db.accounts.count()
Output
1000000

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

Шаг 2 — Проверка статистики использования сервера

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

Предупреждение: Команды мониторинга MongoDB, описанные в этом руководстве, возвращают потенциально чувствительную информацию о вашей базе данных и ее производительности. Из-за этого некоторые из этих команд требуют расширенных разрешений.

Конкретно, метод serverStatus(), описанный на этом этапе, а также команды mongostat и mongotop, подчеркнутые на следующем этапе, требуют, чтобы пользователи были наделены ролью clusterMonitor, чтобы выполнить их. Аналогично, метод setProfilingLevel(), описанный в Шаге 4, требует роль dbAdmin.

Предполагается, что вы следовали предварительному учебнику по Как Обеспечить Безопасность MongoDB на Ubuntu 20.04 и подключились к экземпляру MongoDB в качестве административного пользователя, созданного в этом руководстве. Вам необходимо предоставить этим дополнительные роли, чтобы следовать примерам в этом руководстве.

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

  1. use admin
Output
switched to db admin

Затем запустите метод grantRolesToUser() и предоставьте вашему пользователю роль clusterMonitor вместе с ролью dbAdmin над базой данных, где вы создали коллекцию accounts. В следующем примере предполагается, что коллекция accounts находится в базе данных test:

  1. db.grantRolesToUser(
  2. "AdminSammy",
  3. [
  4. "clusterMonitor",
  5. { role : "dbAdmin", db : "test" }
  6. ]
  7. )

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

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

  1. db.createUser(
  2. {
  3. user: "MonitorSammy",
  4. pwd: passwordPrompt(),
  5. roles: [ { role : "dbAdmin", db : "test" }, "clusterMonitor", "readWriteAnyDatabase" ]
  6. }
  7. )

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

  1. use test
Output
switched to db test

Начните с проверки общих статистических данных базы данных, выполнив метод stats():

  1. db.stats(1024*1024)

Аргумент этого метода (1024*1024) является масштабным коэффициентом и указывает MongoDB возвращать информацию о хранилище в мегабайтах. Если вы его опустите, все значения будут представлены в байтах.

Метод stats() возвращает краткий и содержательный вывод с некоторыми важными статистическими данными, относящимися к текущей базе данных:

Output
{ "db" : "test", "collections" : 3, "views" : 0, "objects" : 1000017, "avgObjSize" : 80.8896048767171, "dataSize" : 77.14365005493164, "storageSize" : 24.109375, "indexes" : 4, "indexSize" : 9.9765625, "totalSize" : 34.0859375, "scaleFactor" : 1048576, "fsUsedSize" : 4238.12109375, "fsTotalSize" : 24635.703125, "ok" : 1 }

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

  • Ключ objects показывает общее количество документов в базе данных. Вы можете использовать это для оценки размера базы данных и, при наблюдении со временем, ее роста.
  • avgObjectSize показывает средний размер этих документов, давая представление о том, оперирует ли база данных большими и сложными документами или маленькими. Это значение всегда показывается в байтах, независимо от того, указывается ли масштабный коэффициент.
  • Ключи collections и indexes показывают, сколько в данный момент определено коллекций и индексов в базе данных.
  • Ключ totalSize указывает, сколько места на диске занимает база данных.

Эта информация, возвращаемая методом stats(), может помочь вам представить, сколько данных в данный момент хранится в вашей базе данных, но она не дает представления о ее производительности или существующих проблемах. Для этого очень полезен гораздо более подробный метод serverStatus():

  1. db.serverStatus()

Вывод этого метода длинный и предоставляет много информации о использовании сервера:

Output
{ "host" : "ubuntu-mongo-rs", "version" : "4.4.6", "process" : "mongod", "pid" : NumberLong(658997), "uptime" : 976, . . . "ok" : 1 }

Хотя вся эта информация потенциально может быть полезной, в этом руководстве будет уделено внимание трем разделам в частности. Во-первых, найдите раздел connections в этом выводе:

Output
. . . "connections" : { "current" : 4, "available" : 51196, "totalCreated" : 4, "active" : 2, "exhaustIsMaster" : 1, "exhaustHello" : 0, "awaitingTopologyChanges" : 1 }, . . .

Каждый сервер баз данных может поддерживать только определенное количество соединений одновременно. Ключ current показывает количество клиентов, в настоящее время подключенных к базе данных, в то время как available – это количество неиспользуемых соединений, которые имеются в базе данных. Значение totalCreated хранит количество соединений, использованных с момента запуска сервера.

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

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

Затем найдите раздел globalLock в выводе. Этот раздел связан с глобальными блокировками на всем сервере баз данных:

Output
. . . "globalLock" : { "totalTime" : NumberLong(975312000), "currentQueue" : { "total" : 0, "readers" : 0, "writers" : 0 }, "activeClients" : { "total" : 0, "readers" : 0, "writers" : 0 } },

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

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

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

Наконец, найдите раздел opcounters:

Output
"opcounters" : { "insert" : NumberLong(10000007), "query" : NumberLong(6), "update" : NumberLong(6), "delete" : NumberLong(0), "getmore" : NumberLong(0), "command" : NumberLong(1298) },

Этот раздел вывода serverStatus() может помочь вам понять, используется ли сервер базы данных в основном для чтения или записи, или его использование хорошо сбалансировано. В этом примере, после вставки тестовых документов, счетчик операций insert гораздо выше, чем у операций query. В реальном сценарии эти значения вероятно будут отличаться.

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

Эта статистика может дать общее представление о том, как используется сервер, и есть ли проблемы с производительностью, такие как длинные очереди блокировок в момент доступа к ним. Однако они не предоставляют реальной информации о том, как используется сервер. Для этого полезны инструменты команды mongostat и mongotop.

Шаг 3 — Использование mongostat и mongotop для получения статистики базы данных в реальном времени

В то время как команды, используемые для доступа к статистике сервера MongoDB, могут предоставить представление о том, как сервер использовался в прошлом, они не могут предоставить информацию в реальном времени о том, какие коллекции используются наиболее активно в данный момент или какие виды запросов выполняются.

MongoDB предоставляет два полезных инструмента системы для мониторинга в реальном времени, которые анализируют активность базы данных и непрерывно обновляют предоставляемую информацию: mongostat и mongotop. mongostat предоставляет краткий обзор текущего состояния экземпляра MongoDB, а mongotop отслеживает, сколько времени экземпляр тратит на операции чтения и записи. Оба этих инструмента запускаются из командной строки, а не из оболочки MongoDB.

Для использования mongostat сохраните текущее соединение оболочки MongoDB и откройте еще одно окно терминала для доступа к оболочке вашего сервера. Во втором терминале сервера выполните команду mongostat:

  1. mongostat -u AdminSammy --authenticationDatabase admin

Как упоминалось ранее, mongostat требует расширенных привилегий. Если вы включили аутентификацию на вашем экземпляре MongoDB и настроили пользователя с соответствующими ролями, то вам нужно аутентифицироваться от имени этого пользователя, указав его имя пользователя и базу данных аутентификации (как показано в этом примере), а затем введите его пароль при запросе.

В стандартной конфигурации mongostat выводит счетчики текущих выполняемых запросов с интервалом в одну секунду:

Output
insert query update delete getmore command dirty used flushes vsize res qrw arw net_in net_out conn time *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.4k 7 Nov 28 15:40:40.621 *0 *0 *0 *0 0 2|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 224b 84.8k 7 Nov 28 15:40:41.619 *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.5k 7 Nov 28 15:40:42.621 *0 *0 *0 *0 0 3|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 365b 85.0k 7 Nov 28 15:40:43.619

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

Вам все равно следует оставить открытым первое окно терминала и подключиться к оболочке MongoDB. Вставьте еще несколько тестовых документов в коллекцию accounts и проверьте, заметит ли mongostat активность:

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "2000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Это цикл for, похожий на тот, который вы запускали на Шаге 1. На этот раз, однако, цикл вставляет только 10000 записей. Номера счетов префиксированы 2000, а валюта всегда USD.

Во время вставки новых документов проверьте вывод mongostat:

Output
. . . *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 112b 42.5k 4 Nov 28 15:50:33.294 *0 *0 *0 *0 0 0|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:34.295 755 *0 *0 *0 0 1|0 0.1% 38.8% 0 1.54G 210M 0|0 1|0 154k 79.4k 4 Nov 28 15:50:35.294 2853 *0 *0 *0 0 0|0 0.4% 39.1% 0 1.54G 211M 0|0 1|0 585k 182k 4 Nov 28 15:50:36.295 2791 *0 *0 *0 0 1|0 0.7% 39.4% 0 1.54G 212M 0|0 1|0 572k 179k 4 Nov 28 15:50:37.293 2849 *0 *0 *0 0 0|0 1.0% 39.7% 0 1.54G 213M 0|0 1|0 584k 182k 4 Nov 28 15:50:38.296 745 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 153k 79.2k 4 Nov 28 15:50:39.294 *0 *0 *0 *0 0 0|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:40.295 *0 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 167b 42.7k 4 Nov 28 15:50:41.293 . . .

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

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

Остановите выполнение mongostat в вашем втором окне терминала, нажав CTRL + C. Затем запустите mongotop в том же терминале. Снова, если у вас включена аутентификация, вам нужно будет аутентифицироваться как пользователь с соответствующими привилегиями:

  1. mongotop -u AdminSammy --authenticationDatabase admin

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

Output
2021-11-28T15:54:42.290+0000 connected to: mongodb://localhost/ ns total read write 2021-11-28T15:54:43Z admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms test.accounts 0ms 0ms 0ms . . .

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

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "3000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

На этот раз активность будет видна в статистике mongotop:

Output
. . . ns total read write 2021-11-28T15:57:27Z test.accounts 127ms 0ms 127ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms ns total read write 2021-11-28T15:57:28Z test.accounts 130ms 0ms 130ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms . . .

Здесь mongotop показывает, что вся активность базы данных произошла в коллекции accounts в базе данных test и что все операции в указанном временном окне были операциями записи. Все это должно соответствовать операции цикла for, которую вы выполнили.

Как и с mongostat, вы можете остановить выполнение mongotop, нажав CTRL + C.

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

Шаг 4 — Использование профилировщика базы данных MongoDB для идентификации медленных запросов

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

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

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

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

Прежде чем использовать профилировщик, выполните следующий запрос. Этот запрос извлечет один из вставленных вами аккаунтов, хотя это не так просто, как может показаться сначала:

  1. db.accounts.find({"number": "1000-20"})

Команда извлечет точный аккаунт, который вы запросили:

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

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

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

  1. db.setProfilingLevel(1, { slowms: 100 })

Метод setProfilingLevel() принимает два аргумента. Первый – это уровень профилирования, который может быть 0, 1 или 2:

  • 0 отключает профилировщик
  • 1 включает профилировщик только для медленных запросов, удовлетворяющих условию
  • 2 включает профилировщик для всех запросов

В этом примере профилировщик будет анализировать запросы, выполняющиеся дольше 100 миллисекунд, как определено вторым аргументом, { slowms: 100 }.

Примечание: Использование профилировщика снижает производительность, так как MongoDB теперь должен анализировать запросы, кроме их выполнения. Он должен использоваться осторожно при отслеживании узких мест производительности.

Можно дополнительно настроить подмножество запросов, которые профилировщик будет регистрировать, настроив его на профилирование только определенного процента запросов или фильтрацию по типу запроса. Чтобы узнать больше о том, каким образом вы можете иметь больший контроль над профилировщиком, обратитесь к официальной документации по этой теме.

Этот метод вернет сообщение об успешном выполнении:

Output
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

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

Попробуйте это, выполнив несколько разных запросов. Во-первых, используйте команду count, чтобы найти количество документов в коллекции accounts:

  1. db.accounts.count()

Эта команда быстро вернет количество документов в коллекции:

Output
1020000

Затем попробуйте найти первые три банковских счета, появляющихся в коллекции:

  1. db.accounts.find().limit(3)

Снова база данных быстро вернет результаты:

Output
{ "_id" : ObjectId("61ef40640f2ba52efc56ee17"), "number" : "1000-1", "currency" : "EUR", "balance" : 25393.132960293842 } { "_id" : ObjectId("61ef40640f2ba52efc56ee18"), "number" : "1000-2", "currency" : "EUR", "balance" : 63629.42056192393 } { "_id" : ObjectId("61ef40640f2ba52efc56ee19"), "number" : "1000-3", "currency" : "EUR", "balance" : 75602.12331602155 }

Наконец, выполните запрос поиска для конкретного банковского счета снова:

  1. db.accounts.find({"number": "1000-20"})

Этот запрос вернет результат, но, как и раньше, это займет немного больше времени, чем предыдущие операции:

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

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

Чтобы получить информацию о запросах, идентифицированных профилировщиком, вы должны выполнить запрос к коллекции system.profile следующим образом:

  1. db.system.profile.find().sort({ "ts" : -1 }).pretty()

Этот запрос использует метод find(), как обычно. Он также включает клаузу sort, содержащую { "ts" : -1 } в качестве аргумента. Это отсортирует набор результатов с последними запросами впереди. Наконец, метод pretty() в конце отобразит вывод в более читаемом формате.

Каждый медленный запрос представлен как обычный документ, и system.profile подобен любой другой обычной коллекции. Это означает, что вы можете фильтровать результаты, сортировать их и даже использовать их в конвейерах агрегации, чтобы дополнительно уменьшить или проанализировать список запросов, идентифицированных профилировщиком.

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

Output
{ "op" : "query", "ns" : "test.accounts", "command" : { "find" : "accounts", "filter" : { "number" : "1000-20" }, . . . }, "nreturned" : 1, "keysExamined" : 0, "docsExamined" : 1030000, . . . "millis" : 434, "planSummary" : "COLLSCAN", . . . }

Этот вывод предоставляет ряд деталей о выполнении медленного запроса:

  • Ключ op показывает, какого типа операцию представляет эта информация. Здесь это query, так как представляет собой операцию, в которой вы использовали find() для извлечения данных из базы данных.
  • Ключ ns указывает, с какой базой данных и коллекцией была связана операция. Как показывает вывод, эта операция запрашивала коллекцию accounts в базе данных test.
  • Ключ command предоставляет дополнительную информацию о самом запросе. В данном случае подключаемый ключ filter содержит весь фильтрующий документ. Используя информацию из полей op и command, вы можете восстановить данный запрос.
  • В поле millis вы найдете точное время, затраченное на выполнение запроса. В этом примере почти полсекунды.
  • Поле docsExamined предоставляет количество отсканированных документов для возврата результирующего набора.
  • nreturned представляет количество документов, возвращенных запросом. В данном примере вернулся только один документ из более чем миллиона отсканированных.
  • planSummary показывает метод, который MongoDB использовала для выполнения запроса. COLLSCAN соответствует полному сканированию коллекции, что означает, что он просматривал каждый документ в коллекции по одному для поиска соответствующего банковского счета.

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

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

Для завершения профилирования вы можете отключить профилировщик, установив уровень профилирования на ноль:

  1. db.setProfilingLevel(0)

Операция завершится с подтверждающим сообщением:

Output
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

Теперь база данных возвращается к нормальной работе без профилирования, происходящего за кадром.

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

Заключение

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

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

Source:
https://www.digitalocean.com/community/tutorials/how-to-monitor-mongodb-s-performance