Как узнать, почему пул приложений IIS перерабатывается - PullRequest
17 голосов
/ 26 марта 2011

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

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

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

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

Вопрос:

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

Ответы [ 4 ]

11 голосов
/ 26 марта 2011

Без доступа к журналам событий (потому что вы находитесь в среде общего хостинга) большая часть информации, которую вы собираетесь получить, - это событие 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()

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

Обновление:

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

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

private ApplicationShutdownReason _shutdownReason;

Вы можете проверитьполя в .NET Reflector (если у вас все еще есть копия, которая не подвергается временной бомбардировке) или одна из альтернатив ( Альтернативы с открытым исходным кодом для Reflector? ).

7 голосов
/ 26 марта 2011

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

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

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

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

Research - 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 голосов
/ 26 января 2017

Это действительно поздний ответ, но я надеюсь, что он может дать дополнительное понимание тем, у кого есть похожие проблемы (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', запросил перезапуск, поскольку достиг предела виртуальной памяти.

3 голосов
/ 22 марта 2016

Ниже приведен хороший код для поиска 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;
}
...