Что происходит в BeginProcessRequest()?
мы используем NewRelic для обеспечения трассировки приложений на стороне сервера.
мы заметили, что некоторые из наших приложений постоянно тратят около 100 мс в методе System.Web.Mvc.MvcHandler.BeginProcessRequest()
.
это происходит до вызова любого пользовательского кода контроллера (который регистрируется отдельно, а не кумулятивно) - не очевидно, почему он будет тратить так много времени в этом методе.
какие вещи MVC будет делать в этом методе? Может это просто быть запрос в очереди?
[EDIT:]как и предполагалось-ответ скаляра ниже был точен. Мы удалили и оптимизировали все наши зависимости от сеанса и увидели массовое увеличение масштабируемости и стабильности приложений
4 ответа:
то, что вы могли бы видеть, обычно называют ловкостью потока в .NET.
то, что вы, вероятно, видите, насколько результаты под актуальной меткой (т. е. код приложения в
System.Web.HttpApplication.BeginRequest()
) - это проблема гибкости потока; в большинстве случаев время, которое вы видите здесь, не обязательно выполняется код, но веб-контекст ожидает, что потоки будут выпущены обратно в него из блокировки чтения-записи.The
Application_BeginRequest()
"пауза" - это тот, который довольно распространен в a ASP.NET веб-стек. В общем, когда вы видите длительное время загрузки в BeginRequest, вы имеете дело с ASP.NET гибкость потоков и / или блокировки потоков - особенно при работе с операциями ввода-вывода и сеансами. Не то, чтобы это плохо, это просто, как .net гарантирует, что ваши потоки остаются параллельными.промежуток времени обычно происходит между BeginRequest и PreRequestHandlerExecute. Если приложение пишет несколько вещей для сеанса, то ASP.NET выдаст читателю-писателю замок на
HttpContext.Current.Session
.хороший способ узнать, является ли это проблемой, с которой вы можете столкнуться, - это проверить идентификаторы потоков, чтобы узнать, является ли проблема гибкостью-идентификаторы будут отличаться для данного запроса.
например. Во время отладки, возможно, вы могли бы добавить следующий код
Global.asax.cs
:protected void Application_BeginRequest(Object sender, EventArgs e) { Debug.WriteLine("BeginRequest_" + Thread.CurrentThread.ManagedThreadId.ToString()); }
откройте окно вывода отладки (из Visual Studio: View >> Output, затем выберите "Debug" из раскрывающегося списка "show output from").
во время отладки, нажмите страница, где вы видели долгое время. Затем просмотрите журнал вывода - Если вы видите несколько идентификаторов, то вы можете страдать от этого.
вот почему вы можете видеть задержку иногда, но не в других случаях, код приложения может использовать сеанс немного по-другому или сеанс или операции ввода-вывода могут быть выше или ниже от страницы к странице.
если это так, некоторые вещи, которые вы можете сделать, чтобы помочь ускорить работу в зависимости от того, как сеанс используется на сайте или каждый данный страница.
для страниц, которые не изменяют сессии:
<% @Page EnableSessionState="ReadOnly" %>
для страниц, которые не используют состояние сеанса:
<% @Page EnableSessionState="False" %>
если приложение не использует сеанс (web.конфигурации):
<configuration> <system.web> <sessionState mode="Off" /> </system.web> </configuration>
Итак, давайте возьмем следующий пример:
пользователь загружает страницу, а затем решает перейти на другую страницу, прежде чем первый запрос будет выполнен загрузка ASP.NET вызовет блокировку сеанса, в результате чего загрузка нового запроса страницы будет ждать завершения первого запроса страницы. С помощью ASP.NET MVC каждое действие блокирует сеанс пользователя для синхронизации; вызывая ту же проблему.
все время, которое потребовалось для разблокировки блокировки, будет сообщено через new relic, не говоря уже о тех, где пользователь отказался от сеанса, и поток, возвращающийся, ищет пользователя, который больше не существует.
кстати элемент управления UpdatePanel вызывает такое же поведение -
http://msdn.microsoft.com/en-us/magazine/cc163413.aspx
что можно сделать:
эта проблема блокировки является одной из причин Microsoft имеет класс SessionStateUtility -
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
так что вы можете переопределить поведение по умолчанию, если вы столкнулись с этой проблемой, как показано здесь в этом Redis реализация:https://github.com/angieslist/AL-Redis
существует много вариантов поставщика состояния по умолчанию, используемого веб-сайтами на основе .net. Но знайте, что обычно это время транзакции указывает на то, что потоки блокируются и ждут запросов к серверу, которые будут завершены.
Если вы хотите включить определенный контроллер для параллельной обработки запросов от одного пользователя, вы можете использовать атрибут с именем SessionState, который был введен в MVC начиная с версии 3. Нет необходимости использовать контроллер без сеанса для достижения параллелизма, опция Ready-only SessionStateBehavior позволит вам пройти проверки безопасности, которые вы, возможно, реализовали на основе данных сеанса.
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)] [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")] public class ParallelController : Controller { ... }
у меня также были задержки в
System.Web.Mvc.MvcHandler.BeginProcessRequest()
, когда пытаются сделать несколько длинных запуск действия, и я видел его вNewRelic
. Эти атрибуты решили проблему и дали возможность обрабатывать действия параллельно для этого контроллера.
я столкнулся с этой же проблемой в приложении, которое имело очень минимальное использование сессий. После учета принятого ответа и даже временного удаления SessionState полностью для диагностических целей у меня все еще были значительные проблемы с производительностью в этом "методе"
на основе комментария todd_saylor в этой теме, Я сделал много исследований на свой сайт и обнаружил, что
BeginProcessRequest
смогите быть подачей как улов новой реликвии-все для разностороннего представления потери, которые появляются в разных областях кода. Я смог значительно сократить время в этой области, профилируя код на моей локальной машине с помощью профилировщика производительности Муравьев Red Gate.мое местное профилирование показало несколько вещей:
- Я использовал Ninject в качестве контейнера DI, что вызвало потерю производительности в его разрешении объекта. Я заменил его SimpleInjector и увеличил производительность на порядок.
- Я нашел это где-то между расширениями AutoMapper IQueryable
Project().To<>()
и аттракцион LINQ в SQL-сервер провайдера, что динамическая компиляция и преобразование в формат JIT проекций отвечает за 50% времени запроса. Заменив его на CompiledQuerys сделал еще одну значительную вмятину.надеюсь, это поможет кому-то еще!
для тех, кто читает это, испытывая высокую загрузку ЦП IIS, которая необъяснима, взгляните на эту тему с форума поддержки NewRelic, который я открыл.
Я занимаюсь этой проблемой уже более недели, пока не понял, что именно их агент был основной причиной проблемы.
.Чистая агентов, вызывая высокую загрузку процессора на сервере IIS
поэтому первое, что я предлагаю вам попробовать, это удалить агент .NET и посмотреть, есть ли какие-либо изменения, прежде чем погружаться в более сложные эксперименты.
Я публикую этот ответ на этот конкретный вопрос, так как я попал сюда первым, работая над проблемой, и гибкость потока установила меня на длинный курс, который был неправильным...(хотя очень интересно само по себе).