Service Fabric Stateful Service в Azure — использование ОЗУ продолжает расти. Возможная утечка памяти

Я запускаю приложение 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 ГБ ОЗУ. Однако я не знаю, полезна ли эта информация в данном случае.




Ответы (1)


После разговора со службой поддержки Azure и нескольких тестов я резко сократил потребление памяти службами.

Главное, что я понял из общения со службой поддержки, это то, что на самом деле не стоит иметь большое количество сервисов, содержащих небольшое количество данных каждый! Дампы памяти приложения показали, что каждый сервис имел около 20 КБ фактических данных и 700 КБ журналов изменений в надежных коллекциях, накопленных Service Fabric. Это могут быть не точные цифры, но разница была огромной.

Чтобы уменьшить количество сервисов, я объединил обработку и сохранение статусов нескольких систем в один сервис, используя своего рода партиционирование. Я также пытался использовать Актеры. Все методы работали хорошо.

Есть несколько других настроек, которые я использовал для уменьшения потребления памяти, но большая разница была достигнута за счет изменения архитектуры самих сервисов:

В Settings.xml самого сервиса:

  • CheckpointThresholdInMB = 1

  • LogTruncationIntervalSeconds = 1200 (Установка этого значения меньше 120 на самом деле ничего не делает или делает хуже. Попробуйте использовать значения больше 300)

  • MaxAccumulatedBackupLogSizeInMB = 1

В коде самой службы:

  • ServicePointManager.DefaultConnectionLimit = 200

  • MaxConcurrentCalls = 512 (RemotingListener и клиент)

Настройки кластера:

  • AutomaticMemoryConfiguration - 0 (Если вы не установите этот параметр, другие не будут работать)
  • WriteBufferMemoryPoolMinimumInKB — 16 МБ.
  • WriteBufferMemoryPoolMaximumInKB — 32 МБ.
person Zapo    schedule 29.11.2019
comment
Не возражаете, если я спрошу, что вы смогли уменьшить занимаемую площадь? Я вижу множество сервисов на своей стороне от 30 МБ до 100 МБ, и в них почти нет кода. Я собираюсь исследовать реорганизацию кода сервиса, но у меня всегда было впечатление, что микросервисы должны быть очень хороши в очень малом. - person Matthew Hartz; 30.01.2020
comment
У нас была такая же проблема, но после перехода на гостевой exe проблема устранилась. Оно буквально исчезло. Мы обнаружили, что использование службы без сохранения состояния SDK приводило к избыточному использованию памяти. - person Dr Schizo; 24.03.2021