Azure Web App (ASP.NET MVC) становится холодным каждые десять минут и занимает + 10-20 с для загрузки

У меня очень странная проблема с Azure Web App, и я очень расстраиваюсь.

Мы используем наше приложение очень быстро и быстро реагируем на это, однако, если мы не используем его примерно десять минут, он имеет очень холодный старт (~ 10-20 секунд). Это холодное начало происходит только тогда, когда оно связано с базой данных. Когда это немного напоминает, когда мы выпускаем веб-приложение.

Наши попытки

Используя Application Insights внутри Azure, мы настраиваем этот ping каждые 5 минут:

enter image description here

Выбросы всегда вызваны моими развертываниями (без использования слотов для развертывания прямо сейчас). Однако эта страница входа не вызывает нашу базу данных, поэтому мы не видим "холодного" начала в этих данных.

Настройка приложения должна быть прочной. Наше веб-приложение размещено в Северной Европе с Always on:

enter image description here

Мы просто перенесли все настройки в новый план обслуживания ресурсов/приложений, чтобы убедиться, что наша проблема запуталась с другими нашими приложениями. Новый план обслуживания приложений - это Standard 1 small, который не должен быть проблемой. Глядя на наше потребление, я не беспокоюсь и, возможно, даже попробую меньшую услугу, которую я буду делать после решения нашей проблемы:

enter image description here

Наша база данных SQL также размещена в Северной Европе (проверенные местоположения в миллиард раз, потому что я сделал эту ошибку раньше).

Как и в случае с сервисом приложений, мы выбрали "слишком большое" аппаратное обеспечение, чтобы убедиться, что это не вызывает проблемы (стандартные S0: 10 DTU). Использование смехотворно низкое:

enter image description here

Мы используем непрерывное развертывание (Deployment options в меню Azure), но, глядя на развертывания, он не должен постоянно развертывать что-то:

enter image description here

Фрустрация приходит в приложение супер отзывчив, когда он работает. Когда он "нагревается", каждая страница загружается за считанные секунды, так же как мое среднее время отклика отображается в нашем веб-приложении:

enter image description here

Но эти цифры просто неверны, когда мы (или наши пользователи!) Используем наше приложение. Здесь мы очень часто ощущаем нагрузку + 10-20 секунд в первый раз.

Кто-нибудь имеет ЛЮБОЕ представление? Любые намеки? Вы не представляете, насколько я благодарен.

EDIT & UPDATE 1:

Я решил настроить еще несколько тестов. Теперь мне удалось получить реальные данные, показывающие нашу проблему, вызвав другую страницу. По иронии судьбы, эта страница НЕ вызывает базу данных, поэтому, хотя я думал, что это проблема с базой данных, это не похоже на это. См. Вызов здесь (тенденция продолжается +24 часов).

Странно, насколько стабильно это составляет ровно ~ 10 секунд. И тренд, кажется, не каждые 10-20 минут, но ближе к каждым 5 минутам - с точно таким же интервалом между ними:

enter image description here

EDIT & UPDATE 2:

Я копаю еще. Оказывается, есть пара очень интересных историй: "медленные" 11 секундные вызовы из edit 1, это только из восточных стран США и с одной конечной точки (http://prntscr.com/jcv69w) и

Самое интересное, что я нашел, это следующее:

У самого приложения нет кэширования. Я использую Entity Framework, который, как я предполагаю, использует некоторое кэширование, но все.

Я зашел в наше приложение и щелкнул его в Chrome. Я узнал, что страницы, которые я уже посетил, показывали мгновенно (с данными из БД), но если бы я открывал новую страницу, она медленно загружалась. Казалось, что некоторые объекты кэшируются при первом открытии страницы.

Затем я попытался открыть приложение в новом браузере. Если бы я открыл страницу, которую раньше открывал в Chrome, она открывалась бы мгновенно. Если бы я открывал новую страницу, которую я раньше не нажимал, она имела бы нагрузку ~ 10 секунд.

Мое лучшее предположение прямо сейчас заключается в том, что я использую структуру Entity Framework, которая почему-то дает проблемы.

ИЗМЕНИТЬ 3:

Просто добавил щедрость и настраивает много протоколирования. Я добавил MiniProfiler, но не могу заставить его работать на производстве (отображается только по местным запросам).

Я также добавил регистрацию в global.asax для Application_Start и Application_BeginRequest и Application_EndRequest чтобы увидеть некоторые и статус там. Скоро будет обновляться с выводами.

EDIT 4:

Итак, теперь у меня есть первые интересные номера. Приложение не перерабатывается. Application_Start вызывается только один раз.

Я вижу разницу во времени, войдя в EndRequest и BeginRequest. Я вижу, что есть несколько вызовов, которые занимают больше, чем +15 секунд между этими двумя... Но когда сайт теплый, он занимает ~ 0,5-2 секунды в зависимости от страницы. Поэтому между началом и концом запроса происходит что-то очень странное. Отладка дальше!

EDIT 5:

Получил MiniProfiler для работы. Ниже приведен пример медленной нагрузки (~ 15 секунд):

enter image description here

Следующим шагом является добавление отслеживания Entity Framework и даже еще одна строка для линейных вызовов. Я получаю деньги в базе данных!

EDIT 6:

Окидоки, я был неправ. это метод рендеринга, который замедляется - не база данных! Я не знаю, как отладить это... В google!

enter image description here

EDIT 7:

Время для другого обновления. Статус: ничего не было решено.

Поэтому я пробовал много вещей:

1) Я попытался отключить все типы кэширования (предотвращение кеширования в ASP.NET MVC для определенных действий с использованием атрибута), и у меня такое же поведение. Первая загрузка? Медленный. Следующая нагрузка? Быстро. Подождите 5-10 минут, такое же поведение так не решено.

2) У меня были некоторые пользовательские вещи в моем файле startup.auth с 5-минутной задержкой. Удалены. Не проблема.

3) Я использовал пользовательский атрибут для авторизации. Я удалил это.

4) Я обновил свою реализацию Entity Framework, чтобы она работала за каждый запрос.

Я очень расстраиваюсь. Следующий шаг:

A) Попробуйте сделать 5-10 версий одной и той же страницы (без _layout, с макетом, с базой данных, без базы данных, с инъекцией зависимостей, без... все эти вещи), поэтому см., Могу ли я найти шаблон.

B) Попробуйте переместить хостинг на виртуальную машину, чтобы узнать, разрешает ли она проблему

EDIT 8 - НОВАЯ РЕЛИКСА ДОБАВЛЕНА:

Теперь я добавил новую реликвию. Две очень страшные вещи следующие (я нашел и воспроизвел ошибку!):

enter image description here

И интерфейсный мудрый (часть браузера New Relic), есть недостаток ~ 15s между двумя запусками:

http://prntscr.com/jevgeg vs http://prntscr.com/jevgix, в котором нет ничего.

Ответы

Ответ 1

Я отправляю ответ, хотя он не решен, но я на 99% уверен, что нашел основную проблему.

Случается, что когда я выпускаю, каждое представление должно быть построено. Для создания представления требуется ~ 15 секунд, что и показывает новое реликвии в моем последнем обновлении.

Это приводит к двум временным решениям и к одному большему вопросу: почему создание представления так медленно?

Временные решения просты. Скомпилируйте представления при выпуске или просмотрите наиболее важные страницы сразу после выпуска. Это явно раздражает, потому что я выпускаю несколько раз в день.

Я предполагаю, что причина настолько медленная, потому что я использую очень большую тему Bootstrap. То, как я обрабатываю пакеты, не очень эффективно, что может стать проблемой.

Причина, по которой я считала, что боль была сайтом, была медленной через ~ 10 минут, была просто потому, что я часто выпускал новый код и не посещал большую часть наших страниц. После этого быстро.

Большое спасибо за вашу помощь и поддержку - по крайней мере сейчас я могу справиться с этим.

Ответ 2

У меня есть несколько возможных ответов.

Entity framework-first/database initialization: если вы используете первую настройку кода с миграциями и, возможно, данные семени, каждая из этих вещей может вызвать некоторые проблемы с "разминкой".

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

Версия фреймворка сущности : сама инфраструктура Entity также имела много улучшений производительности в 5 и 6.x, некоторые из них также связаны с холодными и теплыми скоростями запуска.

Представления не предварительно скомпилированы: если вы получаете медленные нагрузки на страницы (например, после развертывания), каждый первый клик на новой странице (просмотр), а затем последующие загрузки прекрасны. Это может быть связано с тем, что страницы не скомпилированы, я могу подробно остановиться на этом, если это так.

Recycle. Похоже, что вы испытываете эти проблемы, когда приложение перерабатывается, и это не автоматическая инициализация (именно поэтому вы получаете этот холодный удар) худшие проблемы с производительностью, которые я видел с этими вещами, обычно связаны с инфраструктурой сущностей и связаны с прекомпиляцией. Но оба могут быть легко исправлены. Но обеспечение того, что приложение "всегда работает" и само инициализируется после утилизации, также гарантирует, что ни один пользователь не получит этот холодный удар.

ОБНОВЛЕНИЕ: Поскольку это было связано с просмотром, я могу предложить решение, которое я нашел очень полезным. Установка пакета RazorGenerator.Mvc Nuget. И добавление этого движка в качестве первого движка обеспечит использование скомпилированных представлений.

В App_Start вы можете создать файл RazorGeneratorMvcStart.cs с таким содержимым:

using RazorGenerator.Mvc;

[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(MyNamespace.RazorGeneratorMvcStart), "Start")]

namespace MyNamespace {
    public static class RazorGeneratorMvcStart {
        public static void Start() {
            ViewEngines.Engines.Insert(0, new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly));

            VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
        }
    }
}

Двигатель бритвы может даже принимать параметр UsePhysicalViewsIfNewer для тех, кто любит замену просмотра вживую. В этом случае он использует предварительно скомпилированную версию, если в папке не было установлено представление с более новой датой, чем скомпилированная.dll.

Такой подход должен решать проблемы производительности с помощью представлений.

Ответ 3

Несколько идей:

  1. В своем блейджете веб-приложения перейдите в меню "Диагностика и решение проблем". Затем нажмите на счетчики производительности. Я честно прохожу через каждый из доступных перманентных счетчиков, обращая внимание на временную шкалу против вашей деградирующей производительности. Однажды я узнал, что SignalR забивает мой сервер из-за безуспешных соединений, просматривая количество потоков.

  2. Ошибки сервера регистрируются в Application Insights?

  3. На экране "Диагностика и решение проблем" вы видите что-либо подозрительное в журналах трассировки неудачных запросов?

Ответ 4

  1. Отделяйте все от развертывания и локального. Если приложение работает отлично в локальной среде, то происходит что-то другое, когда оно идет на Azure. Решение чего-то занимает много времени.
  2. Любой статический ресурс (сценарий, стили и т.д.) Действительно автоматически кэшируется браузером по первому запросу, поэтому при последующем запросе проблема не должна возникать.
  3. Поскольку вы знаете, что метод "Render" дает проблему, выглядит как сложное вычисление гнездования и манипуляция DOM браузера. Однако, если это не проблема, когда на локальном компьютере, то проверяйте, обращаются ли вызовы к внешним ресурсам и получают ли они блокирующие вызовы (может потребоваться интенсивное использование асинхронных вызовов ajax или серверной стороны, хотя я предполагаю, что у вас уже есть это на месте.)
  4. Возможно, потребуется рефакторинг (чтобы иметь меньшие стеки и возможное использование многопоточного/неблокирующего ввода-вывода), однако вам нужно, чтобы ваш код предлагал на этом.

Разделите событие загрузки страницы и любые последующие вызовы, сделанные им. Также как визуализируется представление вместе с любой обработкой DOM.

Ответ 5

Есть еще два варианта поиска и исправления.

1. Пользовательская новая реликвия для отслеживания.

Проверьте это сообщение от hanselman на его использование в Azure.

2. Следите за лучшей практикой Asp.Net MVC

Проверьте этот пост для лучших практик.

Также для чтения данных вы можете использовать ADO.NET с хранимыми процедурами вместо Entity Framework, потому что на данный момент EF может иметь некоторые проблемы с производительностью.

Ответ 6

Вы компилируете Less или Sass в настройке комплектации?
Если да, то какой JavaScriptEngineSwitcher вы используете?
Я помню, что у меня была аналогичная проблема. Пакеты скомпилированы при первом доступе, и это заняло огромное количество времени.
Решением было перейти на двигатель V8.

Ответ 7

Я понимаю, что прошло чуть больше года для этой темы, но у меня возникла та же проблема в службах приложений Azure. Какой-то десятиминутный тайм-аут, который заставляет всех, кто обращается к приложению, ждать от десяти до тридцати секунд, пока что-то внутреннее перестраивается или переподключается.

В журналах IIS я обнаружил, что каждые десять минут к моей службе приложений отправляется пинг с чего-то под названием ReadyForRequest/1. 0+. Я не могу найти дополнительную информацию об этом запросе в Интернете, но он точно совпадает с нашей десятиминутной проблемой тайм-аута. Мы создали службу поддержки активности, которая посещает наш сайт каждую минуту, и сообщает о времени отклика. Каждые десять минут время отклика изменяется от 0,3 до 10-15 секунд, и это точно соответствует времени этих вызовов ReadyForRequest.

Обычно мы получаем один вызов ReadyForRequest/1. 0+ (LocalCache) и три вызова ReadyForRequest/1. 0+ (AppInit).

GET / - 80 - 10.0.208.4 ReadyForRequest/1.0+(LocalCache)
GET / - 80 - 10.0.208.4 ReadyForRequest/1.0+(AppInit)

У нас есть запрос к нашему представителю Microsoft, но пока они также не могут определить, что вызывает эти звонки.

Может быть, кто-то еще увидит это и получит дальнейшее понимание будущих искателей решений.