Я запускаю приложение Service Fabric в кластере в Azure. Кластер имеет два набора шкал:
- 4x узлы B2ms, в которых тип сервиса с состоянием размещен с Ограничениями размещения (первичный набор масштабов)
- 2x F1-узла, где размещен тип сервиса без сохранения состояния.
В приложении есть два типа услуг
- WebAPI - служба без сохранения состояния, используемая для получения статусов из системы через HTTP и отправки их в StatusConsumer.
- StatusConsumer - служба с отслеживанием состояния, которая обрабатывает статусы и сохраняет последний. Экземпляр службы создается для каждой системы. Общается через RemotingV2.
Для своих тестов я использую Application Insights и Service Fabric Analytics для отслеживания производительности. Я соблюдаю следующие параметры:
Метрики для установленного масштаба: процент загрузки ЦП, операции чтения / записи диска / с
Applicaiton Insights: время отклика сервера - соответствует времени выполнения метода, который получает статусы в StatusConsumer с состоянием.
Service Fabric Analytics: счетчики производительности с агентом анализа журналов на узлах с отслеживанием состояния - используются для наблюдения за использованием ОЗУ узлами.
Каждая моделируемая система отправляет свой статус каждые 30 секунд.
В начале теста использование ОЗУ на каждом узле составляет около 40%, время отклика сервера Avg составляет около 15 мс, загрузка ЦП составляет около 10%, а операции чтения / записи менее 100 / с.
Сразу после начала теста использование ОЗУ начинает медленно нарастать, но в других наблюдаемых показателях нет никакой разницы.
Примерно через час моделирования 1000 систем использование оперативной памяти составляет около 90-95%, и проблемы начинают проявляться в других показателях - пики времени отклика сервера Avg со значениями примерно 5-10 секунд, а операции чтения / записи диска достигают примерно 500 / сек.
Это продолжается в течение 1-3 минут, затем использование оперативной памяти падает, и все возвращается в нормальное состояние.
На изображениях видно, что пик ОЗУ соответствует пику времени отклика сервера. В конце графика ОЗУ использование является плоским, чтобы показать, каково поведение без моделирования каких-либо систем.
Количество моделируемых систем только уменьшает или увеличивает время, необходимое ОЗУ для достижения критических уровней - в одном из тестов было смоделировано 200 систем, и рост использования ОЗУ был медленнее.
Что касается кода: в первых тестах код был более сложным, но чтобы найти причину проблемы, я начал удалять функциональность. Все еще не было никакого улучшения. Единственный раз, когда использование оперативной памяти не увеличивалось, это когда я комментировал весь код, а в теле метода, который получает статус, были только блок try / catch и return. В настоящее время код в 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 ГБ ОЗУ. Однако я не знаю, является ли это полезной информацией в этом случае.