Подтвердить что ты не робот

Как узнать, почему пул приложений IIS перерабатывается

Справочная информация:

Я развернул приложение ASP.NET MVC 3, которое работает на моей машине, в поставщик общедоступного хостинга, и я обнаружил некоторые проблемы, которые, как представляется, связаны с пул приложений перерабатывается. Хост настроил рециркуляцию, чтобы произойти в любом из этих обстоятельств:

  • Использование памяти превышает 200 МБ
  • Использование ЦП превышает 75% (предположительно в течение длительного периода)
  • 20 минут простоя

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

Вопрос:

Есть ли способ узнать, почему мое приложение было переработано (например, в Application_End), чтобы я мог его зарегистрировать, чтобы помочь отладке?

4b9b3361

Ответ 1

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

Для этого добавьте следующий код в событие Application_End:

BindingFlags staticFlags = 
    BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField;
BindingFlags instanceFlags = 
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;

HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime)
                        .InvokeMember("_theRuntime", staticFlags, null, null, null);
if(runtime != null) 
{
    string shutDownMessage = (string)runtime.GetType()
         .InvokeMember("_shutDownMessage", instanceFlags, null, runtime, null);

    string shutDownStack = (string)runtime.GetType()
         .InvokeMember("_shutDownStack", instanceFlags, null, runtime, null);

    // Log shutDownMessage & shutDownStack somewhere
}

Если я завершаю или перезаписываю свой пул приложений приложения, я вижу следующее:

HostingEnvironment initiated shutdown
HostingEnvironment caused shutdown -    
   at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   at System.Environment.get_StackTrace()
   at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()
   at System.Web.Hosting.HostingEnvironment.InitiateShutdownWithoutDemand()
   at System.Web.Hosting.PipelineRuntime.StopProcessing()

Это, вероятно, так же хорошо, как и получается.

Update:

Я не мог вспомнить, где я нашел этот код, но Дрю помог мне вспомнить, что это было в блоге Скотта Гатри.

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

private ApplicationShutdownReason _shutdownReason;

Вы можете просмотреть эти поля в .NET Reflector (если у вас все еще есть копия, которая не бомбардирована) или один из альтернатив (Open Source Alternatives to Reflector?).

Ответ 2

Исследование - 1

Сначала я попытался использовать System.Web.ProcessModelInfo.GetCurrentProcessInfo() и System.Web.ProcessModelInfo.GetHistory(int). Результаты этих методов возвращают информацию, такую ​​как PID, время начала, возраст, статус и пиковое использование памяти. К сожалению, они отсутствовали в моей среде хостинга:

HttpException 0x80004005 - Показатели процесса доступны только при включенной модели процесса ASP.NET. При работе в версиях IIS 6 или новее в режиме изоляции рабочего процесса эта функция не поддерживается.

Этот подход может работать и на других, поэтому, если вы в этой ситуации, сделайте снимок.

Исследование - 2

Свойство System.Web.Hosting.HostingEnvironment.ShutdownReason представляет собой перечисление с большим количеством значений, но, к сожалению, все случаи, которые я излагаю в моем вопросе, объединены в одно значение перечисления:

ApplicationShutdownReason.HostingEnvironment: среда хостинга закрыла домен приложения.

Исследование - 3

У ScottGu есть подход в своем блоге (который является тем же кодом Kev опубликовал), который использует отражение для доступа к внутреннему состоянию HttpApplication. К сожалению, в этом случае он сообщает только те же детали, что и # 2 выше:

_shutDownMessage =
  HostingEnvironment initiated shutdown
  HostingEnvironment caused shutdown

_shutDownStack =
  at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
  at System.Environment.get_StackTrace()
  at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()
  at System.Web.Hosting.HostingEnvironment.InitiateShutdownWithoutDemand()
  at System.Web.Hosting.PipelineRuntime.StopProcessing()

Ответ 3

Ниже приведен хороший код из http://mitchelsellers.com/blogs/2007/03/15/logging-aspnet-application-restarts.aspx

//  obtain the shutdown reason
System.Web.ApplicationShutdownReason shutdownReason = System.Web.Hosting.HostingEnvironment.ShutdownReason;
string shutdownDetail = "";

//Evaluate which option caused the error
switch (shutdownReason)
{
    case ApplicationShutdownReason.BinDirChangeOrDirectoryRename:
        shutdownDetail = "A change was made to the bin directory or the directory was renamed";
        break;
    case ApplicationShutdownReason.BrowsersDirChangeOrDirectoryRename:
        shutdownDetail = "A change was made to the App_browsers folder or the files contained in it";
        break;
    case ApplicationShutdownReason.ChangeInGlobalAsax:
        shutdownDetail = "A change was made in the global.asax file";
        break;
    case ApplicationShutdownReason.ChangeInSecurityPolicyFile:
        shutdownDetail = "A change was made in the code access security policy file";
        break;
    case ApplicationShutdownReason.CodeDirChangeOrDirectoryRename:
        shutdownDetail = "A change was made in the App_Code folder or the files contained in it";
        break;
    case ApplicationShutdownReason.ConfigurationChange:
        shutdownDetail = "A change was made to the application level configuration";
        break;
    case ApplicationShutdownReason.HostingEnvironment:
        shutdownDetail = "The hosting environment shut down the application";
        break;
    case ApplicationShutdownReason.HttpRuntimeClose:
        shutdownDetail = "A call to Close() was requested";
        break;
    case ApplicationShutdownReason.IdleTimeout:
        shutdownDetail = "The idle time limit was reached";
        break;
    case ApplicationShutdownReason.InitializationError:
        shutdownDetail = "An error in the initialization of the AppDomain";
        break;
    case ApplicationShutdownReason.MaxRecompilationsReached:
        shutdownDetail = "The maximum number of dynamic recompiles of a resource limit was reached";
        break;
    case ApplicationShutdownReason.PhysicalApplicationPathChanged:
        shutdownDetail = "A change was made to the physical path to the application";
        break;
    case ApplicationShutdownReason.ResourcesDirChangeOrDirectoryRename:
        shutdownDetail = "A change was made to the App_GlobalResources foldr or the files contained within it";
        break;
    case ApplicationShutdownReason.UnloadAppDomainCalled:
        shutdownDetail = "A call to UnloadAppDomain() was completed";
        break;
    default:
        shutdownDetail = "Unknown shutdown reason";
        break;
}

Ответ 4

Это очень поздний ответ, но я надеюсь, что он может предоставить дополнительную информацию для тех, кто имеет похожие проблемы (IIS 7.x или выше).

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

public class ApplicationPoolService : IApplicationPoolService
{
    public bool IsShuttingDown()
    {
        return System.Web.Hosting.HostingEnvironment.ShutdownReason != ApplicationShutdownReason.None;
    }

    public ApplicationShutdownReason GetShutdownReason()
    {
        return System.Web.Hosting.HostingEnvironment.ShutdownReason;
    }
}

public class HostingEnvironmentRegisteredObject : IRegisteredObject
{
    public void Stop(bool immediate)
    {
        // second call is done when the Stop is imminent 
        if (immediate)
            return;

        var reason = appPoolService.GetShutdownReason().ToString();
        logger.Log(LogLevel.Info, $"HostingEnvironmentRegisteredObject.stop called with shutdown reason {reason}");
    }
}

// this code should be placed in global.asax.cs
protected void Application_Start()
{
    HostingEnvironment.RegisterObject(new HostingEnvironmentRegisteredObject());
}

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

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

  • Точное время инициализации выключения
  • Фильтр журнала событий:
    • Источники событий = WAS
    • Уровень события = информация
    • Записан = пользовательский диапазон, включая точное время выключения +/- 1 минута или около того

Журнал событий должен возвращать более релевантную информацию, подобную приведенной ниже:

Рабочий процесс с идентификатором процесса в пуле приложений для приложения "xxx" "xxx" запросил переработку, потому что он достиг своего запланированное время утилизации.


Рабочий процесс с идентификатором процесса в пуле приложений для приложения "xxx" "xxx" запросил переработку, потому что он достиг своей виртуальной памяти предел.