Моя база данных mongodb имеет размер около 50 Ги. Есть приблизительно 45K коллекций, варьирующихся по размеру. самый большой имеет порядка <1 миллиона документов. </p>
Я использую версию mongodb 3.6.8 в AWS на r5.xlarge (32 Ги памяти, 4 vCPU) с SSD-диском 500Gi gp2, установленным в качестве постоянного тома. Он не огражден, но реплицируется с 1 основным и 2 вторичными узлами.
Большую часть времени запросы выполняются достаточно хорошо. Тем не менее, очень часто запросы (вставки, обновления, выборки - это не имеет значения) занимает «очень много времени» для завершения. Я пытаюсь выяснить, что является причиной этого.
Я включил профилирование для запросов, которые занимают более 10 секунд.
Вот пример, который поражает воображение. Это обновление коллекции с 5 документами, где квалификация находится в свойстве _id. Требуется 20 секунд, чтобы бежать. Профилировщик показывает:
{
"op" : "update",
"ns" : "bar.PumpStatus__PumpEventDrivenAppNS",
"command" : {
"q" : {
"_id" : ObjectId("5e43f4b9aae591154193999a")
},
"u" : {
"$inc" : {
"foo_version" : 1
},
"$set" : {
"PumpId" : "Pump1",
"Temp" : NumberLong(197),
"RPMS" : NumberLong(3885),
"Time" : ISODate("2020-03-04T20:39:11.065Z"),
"foo_modifiedAt" : ISODate("2020-03-04T20:39:11.946Z"),
"foo_modifiedBy" : "439b96af-558e-4372-a7b9-d245f48d3d3d"
}
},
"multi" : true,
"upsert" : false
},
"keysExamined" : 1,
"docsExamined" : 1,
"nMatched" : 1,
"nModified" : 1,
"writeConflicts" : 1,
"numYield" : 1,
"locks" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(3),
"w" : NumberLong(3)
}
},
"Database" : {
"acquireCount" : {
"w" : NumberLong(3)
}
},
"Collection" : {
"acquireCount" : {
"w" : NumberLong(2)
}
},
"oplog" : {
"acquireCount" : {
"w" : NumberLong(1)
}
}
},
"millis" : 20001,
"planSummary" : "IDHACK",
"execStats" : {
"stage" : "UPDATE",
"nReturned" : 0,
"executionTimeMillisEstimate" : 20008,
"works" : 3,
"advanced" : 0,
"needTime" : 1,
"needYield" : 1,
"saveState" : 1,
"restoreState" : 1,
"isEOF" : 1,
"invalidates" : 0,
"nMatched" : 1,
"nWouldModify" : 1,
"nInvalidateSkips" : 0,
"wouldInsert" : false,
"fastmodinsert" : false,
"inputStage" : {
"stage" : "IDHACK",
"nReturned" : 1,
"executionTimeMillisEstimate" : 18351,
"works" : 1,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 2,
"isEOF" : 1,
"invalidates" : 0,
"keysExamined" : 1,
"docsExamined" : 1
}
},
"ts" : ISODate("2020-03-04T20:39:31.948Z"),
"client" : "10.10.158.164",
"appName" : "io.myorg.mongodb",
"allUsers" : [
{
"user" : "foo",
"db" : "bar"
}
],
"user" : "foo@bar"
}
mongodb оценка того, что для поиска документа с помощью IDHACK потребуется 18,351 секунды и что общее выполнение займет 20,008 секунды. И вот, время казни наступило в 20.001.
Мне трудно поверить в эти цифры. можно ли им доверять? и если так, что могло бы произойти, чтобы вызвать такое медленное время выполнения?
коллекция очень мала, ожидаемое время ожидания блокировки отсутствует, если я запускаю эквивалентный поиск вручную, он мгновенно возвращается. насколько я могу судить, метрики CloudWatch для тома не указывают на очень медленные операции чтения или записи. задержки минимальны, и количество операций ввода-вывода в секунду не достигает предела.
области, которые, как я знаю, могут быть улучшены:
- позволяют
directoryForIndexes
разделять коллекции и индексы на 2 тома - используйте
XFS
на томе - убедитесь, что огромные страницы отключены (я думаю, что они есть)
Я скептически отношусь к тому, что любое из вышеперечисленного уменьшит боль. я подозреваю, что я делаю что-то (еще) совершенно неправильно c.
есть мысли о том, что здесь может происходить?