Добрый день.
Около 2 недель назад наш инструмент мониторинга (NewRelic) начал обнаруживать большое количество сбоев сайта продолжительностью не более 1 минуты, но с очень высокой частотой.
Кроме того, визуально было заметно, что общая производительность веб-приложения ( Умбрако 6.1.6, .
net 4.0 ) упал.
Красные полоски на картинке — это наши водопады.
Да, я оговорюсь.
Прежде чем мы все это узнали, был установлен новый модуль блога и, соответственно, блог компании был перенесен с Worldpress на Umbraco. В итоге имеем следующие входные данные: приложение стало хранить больше данных (намного больше) + был установлен сторонний модуль = High CPU.
В путь
Перед началом исследования было решено проверить Googe Analytics, чтобы убедиться, что количество пользователей не изменилось (в результате все осталось так же) + было решено провести нагрузочное тестирование для определения пропускной способности.Здесь нас ждало полное разочарование; наше приложение умерло, когда 30 одновременные сеансы.
Сайт вообще не открывался через браузер.
И это было производство.
Шаг 1. Сбор дампов производительности под нагрузкой с использованием Инструменты диагностики отладки
1. Установите его на рабочий сервер.2. Запускаем, создаем новое правило с типом «Производительность».
3. Указываем, что дампы нужно собирать с помощью Performance Counters.
4. В нашем случае выбираем % Processor Time, порог — 80%, продолжительность — 15 секунд.
Это означает, что дампы будут собраны, если загрузка процессора составит более 80% в течение 15 секунд. 5. Изучение результатов
Вещи, на которые следует обратить внимание, выделены красными прямоугольниками.
А именно:
- На момент составления дампов был запущен Garbage Collector (сначала я на него не обратил внимания);
- Очень большой размер кучи;
- Все 4 потока принадлежат сборщику мусора и съедают 100% ресурсов процессора.
Немного теории
В GC наиболее трудоемкой генерацией является сборка мусора Gen 2 (которая вызывает сборки Gen 1 и Gen 0 соответственно).У каждого поколения также есть свой порог, при превышении которого автоматически запускается сбор мусора.
Это означает, что чем чаще будет превышен порог, тем чаще будет запускаться сборка мусора.
Небольшой пример: Предположим, порог поколения Gen 2: 300 МБ.
За одну секунду GC может очистить: 100 МБ (Gen 2) Каждому новому пользователю в секунду выделяется: 10 МБ (в Gen 2) Если у нас 10 пользователей, то 10*10=100 Мб, поэтому проблем нет. Если у нас 40 пользователей, то каждую секунду выделяется 400 МБ, из-за чего происходит сбор хаоса (превышение порога) и так по возрастанию.
То есть, чем больше пользователей, тем больше памяти выделяется (по возрастанию), тем чаще вызывается сборка мусора с большим временным интервалом сбора.
В .
net 4.0 при сборке мусора всем потокам сборщика мусора присваивается наивысший приоритет. Это означает, что все ресурсы сервера будут выделены на сбор мусора и, кроме того, все остальные потоки (обработка входящих запросов) будут временно приостановлены до завершения сборки мусора.
Именно по этой причине сервер не отвечал на запросы, даже если он не был полностью загружен.
Следовательно, мы можем сделать вывод: Причина – неправильное выделение большого объема памяти за короткие промежутки времени.Чтобы решить проблему, нам нужно найти места в нашем коде так называемых утечек памяти.
Шаг 2 – поиск предметов.
которые занимают больше всего памяти (профилирование памяти) Для этого я использовал точкаМемори в качестве профилировщика памяти.
Запускаем dotMemory под нагрузкой и пытаемся сделать снимок памяти, когда ее объем начинает существенно расти.
(Зеленая область на изображении ниже — поколение 2.)
Далее приступаем к анализу изображения.
Наибольший объем памяти занимает HttpContext, DynanicNode, Узел .
Мы исключаем HttpContext, поскольку он хранит ссылки на объекты DynanicNode и Node.
Далее будем группировать по поколениям, так как нам нужны только объекты поколения Gen 2.
В поколении Gen 2 мы снова группируемся по доминаторам.
Это позволяет на 100% найти нужные объекты, занимающие наибольший объем памяти.
Затем вам нужно поработать с конкретными экземплярами объекта, чтобы определить, что это за объект (идентификатор, свойства и т. д.).
В этот момент стало ясно, какие данные были источником проблемы; оставалось только найти место, где оно было создано, и исправить его.
Шаг 3. Устраните проблему
В моем конкретном случае проблема заключалась в элементе управления, который формировал основную навигацию сайта.Следовательно, решение самой проблемы заключалось в замене метода isAncestor нашей собственной реализацией + применении OutputCache к нашему элементу управления.Этого элемента управления не было в кеше, то есть он работал при каждом запросе страницы.
А конкретный «порей памяти» был связан с вызовом нативного метода Umbraco. DynamicNode.isAncestor() .
Как оказалось, чтобы определить родителя, метод поднимал в память всё дерево сайта.
Это подтвердило тот факт, что проблема стала проявляться только с ростом данных, а конкретно с импортом блога.
выводы
— Высокая загрузка ЦП — это не только рекурсия или большая нагрузка, но и сбор мусора; — Создание объектов должно быть продуманным и соответствовать архитектуре приложения; — Вывод кэша — всегда и везде; — Все, что не видно при обычном тестировании, появится при нагрузочном тестировании! И обратите внимание: На момент написания статьи NewRelic помог мне найти не источник High CPU, а счетчик производительности.% времени в GC легко указал на источник проблемы.
Если на графике пики ЦП увеличиваются в соответствии с пиками графика % времени в GC и смысл % времени в GC выше линии 20% => Высокая загрузка ЦП из-за сборки мусора.
Спасибо за внимание.
Надеюсь, это было интересно.
Теги: #.
NET #ASP.NET #umbraco #производительность #утечки памяти #dotMemory #разработка веб-сайтов #.
NET #ASP #ASP
-
Мини-Дв Обзоры
19 Oct, 24 -
Re: Куда Мы Все Идем?
19 Oct, 24 -
Nintendo Wii Хороша Для Просмотра Порно
19 Oct, 24