Веб-приложение Azure (ASP.NET MVC) становится холодным каждые десять минут и для загрузки требуется + 10-20 секунд - PullRequest
0 голосов
/ 01 мая 2018

У меня очень странная проблема с веб-приложением Azure, и я очень разочарован этим.

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

Наши попытки

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

enter image description here

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

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

enter image description here

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

enter image description here

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

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

enter image description here

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

enter image description here

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

enter image description here

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

У кого-нибудь есть идея? Есть намеки? Ты не представляешь, как я буду благодарен.

РЕДАКТИРОВАТЬ И ОБНОВИТЬ 1:

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

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

enter image description here

РЕДАКТИРОВАТЬ И ОБНОВИТЬ 2:

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

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

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

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

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

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

РЕДАКТИРОВАТЬ 3:

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

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

РЕДАКТИРОВАТЬ 4:

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

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

РЕДАКТИРОВАТЬ 5:

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

enter image description here

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

РЕДАКТИРОВАТЬ 6:

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

enter image description here

РЕДАКТИРОВАТЬ 7:

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

Итак, я много чего перепробовал:

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

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

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

4) Я обновил свою реализацию Entity Framework, чтобы она работала в соответствии с запросом

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

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

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

РЕДАКТИРОВАТЬ 8 - ДОБАВЛЕНО НОВОЙ РЕЛИКОЙ:

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

enter image description here

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

http://prntscr.com/jevgeg против http://prntscr.com/jevgix, между которыми нет ничего.

Ответы [ 6 ]

0 голосов
/ 08 мая 2018

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

0 голосов
/ 08 мая 2018

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

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

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

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

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

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

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

0 голосов
/ 07 мая 2018

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

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

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

2. Следуйте рекомендациям Asp.Net MVC

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

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

0 голосов
/ 04 мая 2018

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

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

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

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

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

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

UPDATE: Поскольку это было связано с просмотром, я могу предложить решение, которое я нашел очень полезным. Установка пакета 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.

Этот подход должен решить проблемы производительности с представлениями.

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

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

0 голосов
/ 02 мая 2018

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

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

  2. Чистота журнала ошибок сервера в Application Insights чистая?

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

...