Я запускаю приложение Service Fabric в кластере в Azure. Кластер имеет два набора масштабов:
- 4 узла B2ms, на которых тип службы с отслеживанием состояния размещается с ограничениями размещения (основной масштабируемый набор)
- 2 узла F1, на которых размещается тип службы без сохранения состояния.
В приложении есть два вида услуг
- WebAPI — служба без сохранения состояния, используемая для получения статусов из системы через HTTP и отправки их в StatusConsumer.
- StatusConsumer - сервис с отслеживанием состояния, который обрабатывает статусы и сохраняет последний. Экземпляр службы создается для каждой системы. Он взаимодействует через RemotingV2.
В своих тестах я использую Application Insights и Service Fabric Analytics для отслеживания производительности. Я наблюдаю следующие параметры:
Метрики для масштабируемого набора с отслеживанием состояния: процент использования ЦП, количество операций чтения/записи на диск/сек.
Applicaiton Insights: время ответа сервера — соответствует времени выполнения метода, который получает статусы в StatusConsumer с отслеживанием состояния.
Аналитика Service Fabric: счетчики производительности с агентом аналитики журналов на узлах с отслеживанием состояния — используются для наблюдения за использованием ОЗУ узлами.
Каждая смоделированная система отправляет свой статус каждые 30 секунд.
В начале теста использование оперативной памяти составляет около 40% на каждом узле, среднее время отклика сервера составляет около 15 мс, использование ЦП составляет около 10%, а операции чтения/записи — менее 100/с.
Сразу после начала теста использование оперативной памяти начинает медленно нарастать, но разницы в остальных наблюдаемых метриках нет.
Примерно через час моделирования 1000 систем использование ОЗУ составляет около 90-95%, и проблемы начинают проявляться в других показателях - среднее время отклика сервера достигает пиковых значений около 5-10 секунд, а операции чтения/записи диска достигают около 500/сек. .
Это продолжается в течение 1-3 минут, затем использование ОЗУ падает, и все возвращается в норму.
На изображениях видно, что пик оперативной памяти соответствует пику времени отклика сервера. В конце графика ОЗУ использование плоское, чтобы показать, каково поведение без моделирования каких-либо систем.
Количество смоделированных систем только уменьшает или увеличивает время, необходимое для достижения критического уровня оперативной памяти - в одном из тестов было смоделировано 200 систем, и рост использования оперативной памяти был медленнее.
Насчет кода: В первых тестах код был сложнее, но чтобы найти причину проблемы я начал убирать функционал. И все же улучшения не было. Единственный раз, когда использование оперативной памяти не увеличилось, это когда я закомментировал весь код, и в теле метода, который получает статус, были только блок try/catch и возврат. В настоящее время код в StatusConsumer таков:
public async Task PostStatus(SystemStatusInfo status){
try{
Stopwatch stopWatch = new Stopwatch();
IReliableDictionary<string, SystemStatusInfo> statusDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, SystemStatusInfo>>("status");
stopWatch.Start();
using (ITransaction tx = this.StateManager.CreateTransaction())
{
await statusDictionary.AddOrUpdateAsync(tx,"lastConsumedStatus",(key) => { return status; },(key, oldvalue) => status);
await tx.CommitAsync();
}
stopWatch.Stop();
if (stopWatch.ElapsedMilliseconds / 1000 > 4) //seconds
{
Telemetry.TrackTrace($"Queue Status Duration: { stopWatch.ElapsedMilliseconds / 1000 } for {status.SystemId}", SeverityLevel.Critical);
}
}
catch (Exception e) {Telemetry.TrackException(e);}
}
Как я могу диагностировать и/или исправить это?
PS: После подключения к узлам с удаленным рабочим столом в Диспетчере задач я вижу, что при использовании ОЗУ около 85% «Память» процесса SystemStatusConsumer, который «держит» экземпляры микросервиса, составляет не более 600 МБ. Это максимальное потребление, но все же не такое высокое — нода с 8 ГБ ОЗУ. Однако я не знаю, полезна ли эта информация в данном случае.