Использование пользовательских счетчиков производительности в домене приложений - PullRequest
5 голосов
/ 05 декабря 2008

У меня есть приложение ASP.NET, которое отслеживает статистику путем создания и записи в пользовательские счетчики производительности. Иногда в журналах ошибок я вижу, что счетчики не открывались, поскольку они уже использовались в текущем процессе. Я предполагаю, что это связано с тем, что мой домен приложения .NET был сброшен в рамках того же процесса w3wp.exe. Как я могу избежать этих ошибок и восстановить соединение со счетчиками производительности, когда домен моего приложения был переработан?

Конструкция счетчика:

PerformanceCounter pc = new PerformanceCounter();
pc.CategoryName = category_name;
pc.CounterName = counter_name;
pc.ReadOnly = false;
pc.InstanceLifetime =
PerformanceCounterInstanceLifetime.Process;
pc.InstanceName = instance_name;

Использование счетчика:

pc.Increment()

[Обновление от 26.03.09] Получено сообщение об ошибке:

Экземпляр '_lm_w3svc_1_root_myapp' уже существует со временем жизни Process. Он не может быть воссоздан или использован повторно, пока не будет удален или пока процесс, использующий его, не завершится. уже существует со временем жизни процесса.

Я попытался воспроизвести исключение в консольном приложении, инициализировав счетчики производительности и записав один из них во временном AppDomain. Затем я выгружаю AppDomain и делаю это снова во втором AppDomain (тот же процесс). Они оба преуспевают. Теперь я точно не знаю, в чем причина, моё предположение об утилизации AppDomain в ASP.NET кажется ложным.

Ответы [ 6 ]

5 голосов
/ 22 октября 2012

Указанная выше ошибка также может возникать в журналах приложений при использовании счетчиков производительности WCF на основе процесса . Признаки этого - блок из трех ошибок в журналах событий приложения:

Счетчик производительности не загружен.
Название категории: ServiceModelService 3.0.0.0
Имя счетчика: звонки
Исключение: System.InvalidOperationException: Экземпляр abc@def|service.svc уже существует с жизненным циклом процесса. Он не может быть воссоздан или использован повторно до тех пор, пока он не будет удален или пока процесс, использующий его, не завершится.

Это всегда происходит сразу после следующего информационного сообщения в журналах системных событий:

Рабочий процесс с идентификатором процесса «nnnn», обслуживающего пул приложений «MyAppPool», запросил перезапуск, поскольку рабочий процесс достиг допустимого времени обработки.

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

Номер версии ServiceModelService 3.0.0.0 будет зависеть от версии .NET, которую вы используете (это было проверено с использованием .NET 3.5).

* * Фон тысяча двадцать-один * * тысяча двадцать-дв

Ошибка вызвана тем, что рабочий процесс достигает своего предела времени обработки, после чего он должен быть переработан. Это задается в параметрах перезапуска пула приложений IIS (IIS 6.0 и выше, поэтому Windows Server 2003 и выше). Переработка рабочего процесса приводит к конфликту имени счетчика производительности на основе нового процесса со старым, что приводит к ошибке. Это связано с тем, что в IIS используется переопределенная переработка , где рабочий процесс, который должен быть завершен, продолжает работать до тех пор, пока не будет запущен новый рабочий процесс.

Воспроизведение

(протестировано на Windows Server 2003 = IIS 6.0)

  • Создание службы WCF.
  • Добавьте следующие к web.config в разделе <system.serviceModel>:
    <diagnostics performanceCounters="All" />
  • В свойствах пула приложений для службы в разделе Свойства → Переработка установите рабочий процесс Перезапуск на 1 минуту. Ручная переработка пула приложений не имеет никакого эффекта, поскольку это не создает запроса от рабочего процесса на повторную обработку (как видно из журналов системы просмотра событий с W3SVC информационными событиями).
  • В soapUI создайте набор тестов / тестовый набор / шаг теста / запрос теста для операции WCF.
  • Добавьте тестовый пример либо к нагрузочному тесту в soapUI, либо используйте loadUI , вызывая вызов со скоростью 1 в секунду.
  • Каждую 1 минуту рабочий процесс будет запрашивать перезапуск (это видно из системных журналов). Каждые 2 минуты это приводит к пакету из трех ошибок в журналах приложений от System.ServiceModel 3.0.0.0.
  • Счетчики производительности для этой службы будут недоступны до тех пор, пока рабочий процесс снова не перезагрузится. (Обратите внимание, что на этом этапе для периода повторного использования устанавливается более высокое значение, чтобы узнать, как долго счетчики производительности недоступны, фактически перезапустят процессы и снова сделают счетчики доступными.)

Возможные решения

Решение 1 - красная сельдь

Исправление KB981574 заменяет исправление KB971601 . Последнее исправление описывает проблему:

ИСПРАВЛЕНИЕ: счетчики производительности, которые отслеживают приложение, перестают отвечать при его выходе и перезапуске, и вы получаете исключение System.InvalidOperationException на компьютере под управлением .NET Framework 2.0

Применение прежнего исправления не устраняет проблему. Применение последнего исправления вызвало ошибки пула приложений.

Решение 2 - рабочий раствор

Можно создать фабрику хостов службы, которая предоставляет настраиваемый хост службы :

using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace MyNamespace
{
    public class WebFarmServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(
                   Type serviceType, Uri[] baseAddresses)
        {
            return new WebFarmServiceHost(serviceType, baseAddresses);
        }
    }

    public class WebFarmServiceHost : ServiceHost
    {
        public WebFarmServiceHost(
            Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses) { }

        protected override void ApplyConfiguration()
        {
            base.ApplyConfiguration();

            Description.Name = "W3wp" + Process.GetCurrentProcess().Id +
                               Description.Name;
        }
    }
}

И обратиться к фабрике в сервисной разметке .svc Файл:

<%@ ServiceHost Language="C#" Debug="true" Factory="MyNamespace.WebFarmServiceHostFactory" Service="WcfService1.Service1" CodeBehind="Service1.svc.cs" %>

Финальные настройки

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

Простая настройка, которая, похоже, полностью решает проблему, заключается в добавлении команды режима сна непосредственно перед base.ApplyConfiguration();:

Thread.Sleep(1);

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

Решение 3 - самое простое исправление

В IIS есть DisallowOverlappingRotation свойство метабазы ​​. Этот может быть установлен следующим образом (пример приведен для MyAppPool пула приложений):

cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs SET w3svc/AppPools/MyAppPool/DisallowOverlappingRotation TRUE

Сравнение решений

Решение № 3 приведет к тому, что ваш сайт будет дольше не работать , когда рабочий процесс перезапустится из-за отсутствия повторного использования IIS.

В ходе тестов нагрузки WUU основного базового веб-сервиса, использующих более 100 транзакций в секунду с 5 потоками, «зависание», когда новые транзакции блокировались, проявлялось в течение нескольких секунд каждый раз, когда рабочий процесс перерабатывался. Это зависание было более продолжительным (8+ секунд) при тестировании более сложного веб-сервиса.

Решение № 2 не создавало такой блокировки, имело плавный поток ответов во время повторного цикла и не приводило к ошибкам конфликта пермонов.

Заключение

Для веб-сервисов, где низкая задержка не является обязательным, можно использовать решение № 3. Вы даже можете установить ежедневную переработку в определенное время, если знаете распределение нагрузки и тихое время суток (это можно сделать на той же вкладке в IIS). Это даже может быть поражено, если используется веб-ферма.

Для веб-сервисов, которые не могут терпеть такие задержки, решение №2 является наилучшим способом продвижения вперед.

2 голосов
/ 17 июня 2009

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

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

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

Это процедура для создания имени экземпляра:

    private static string GetFriendlyInstanceName()
    {
        string friendlyName = AppDomain.CurrentDomain.FriendlyName;
        int dashPosition = friendlyName.IndexOf('-');
        if (dashPosition > 0)
        {
            friendlyName = friendlyName.Substring(0, dashPosition);
        }
        friendlyName = friendlyName.TrimStart('_');
        string processID = Process.GetCurrentProcess().Id.ToString();
        string processName = Process.GetCurrentProcess().ProcessName;
        string instanceName = processName + " " + processID + " " + friendlyName.Replace('/', '_').Trim('_').Trim();
        return instanceName;
    }
0 голосов
/ 08 ноября 2013

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

В случае виртуального хостинга вы можете определить это в файле web.config.

0 голосов
/ 05 ноября 2009

У меня была похожая проблема: Многократные экземпляры счетчиков Process LifeTime не могли быть созданы несколько раз в Visual Studio, но это было связано с тем, что у меня был открыт PerfMon!

Мне потребовалось время, чтобы понять это.

0 голосов
/ 30 марта 2009

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

lock (this.lockObject)
{
 //Create performance counter
}
0 голосов
/ 27 марта 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...