Windows Azure. Диагностика и профилирование приложений. Часть 2

В предыдущей публикации мы обсудили назначение монитора диагностики Windows Azure Diagnostic Monitor и доступные источники диагностических данных. Здесь мы поговорим об использовании монитора диагностики, способах изменения его настроек и настройке передачи данных.

Использование монитора диагностики

Для того, чтобы сконфигурировать монитор диагностики, необходимо обратиться к интерфейсу, предоставляемому классом DiagnosticMonitor в пространстве имен Microsoft. WindowsAzure. Diagnostics. В методе OnStart класса RoleEntryPoint для той или иной роли следует вызвать методы GetDefaultConfiguration и Start. Для настройки монитора диагностики необходимо указать источники диагностических данных и интервалы передачи данных. Выше мы подробно рассмотрели различные источники диагностических данных и способы их включения в процесс сбора информации средствами монитора диагностики. В приведенном ниже примере показано, как запустить монитор диагностики для сбора информации из журнала Windows Azure и журнала событий Windows.

public override bool OnStart()

{

  var conf = DiagnosticMonitor.GetDefaultInitialConfiguration();

// Журнал Windows Azure

  conf.Logs.ScheduledTransferPeriod = TimeSpan.FromSeconds(10);

  conf.Logs.ScheduledTransferLogLevelFilter = LogLevel.Undefined;

// Журнал событий Windows

  conf.WindowsEventLog.DataSources.

  Add(“Application!*[System[Provider[@Name=’WebRole’]]]”);

  conf.WindowsEventLog.ScheduledTransferPeriod =

  TimeSpan.FromSeconds(10);

  conf.WindowsEventLog.ScheduledTransferLogLevelFilter = LogLevel.Undefined;

  DiagnosticMonitor.Start(“DiagnosticConnectionString”, conf);

  return base.OnStart();

}

При вызове метода Start значение параметра DiagnosticConnectionString указывает на настройки в конфигурационном файле ServiceConfiguration. csdef. Ниже приведен пример таких настроек – используется хранилище, предоставляемое локальным эмулятором.

01-07

Изменение настроек диагностики

После того как приложение развернуто и выполняется под управлением Windows Azure можно изменить настройки диагностики для экземпляра без повторного развертывания приложения или перезапуска роли. Это возможно благодаря тому, что монитор диагностики выполняется как отдельный процесс, отслеживающий изменения в настройках. По умолчанию, монитор диагностики с интервалом в одну минуту просматривает содержимое контейнера бинарных объектов wad- control- container. Для изменения настроек диагностики во время выполнения приложения следует использовать класс DeploymentDiagnosticManager из пространства имен Microsoft. WindowsAzure. Diagnostics. Management. Основное назначение класса DeploymentDiagnosticManager – предоставить доступ к экземплярам класса RoleInstanceDiagnosticManager, который представляет собой точки входа в конфигурацию для каждого экземпляра роли.

Для изменения настроек диагностики одного экземпляра непосредственно из кода экземпляра роли, следует использовать класс DeploymentDiagnosticManager для получения класса RoleInstanceDiagnosticManager для данного экземпляра. Ниже показано пример изменения уровня собираемой в журнале Windows Azure информации на Information.

public ActionResult ChangeLogLevel()

{

  var account = CloudStorageAccount.FromConfigurationSetting(“DiagnosticConnectionString”);

  var deploymentManager = new DeploymentDiagnosticManager(account, RoleEnvironment.DeploymentId);

// Получить доступ к менеджеру диагностики

  var instanceManager = deploymentManager.GetRoleInstanceDiagnosticManager

   (RoleEnvironment.CurrentRoleInstance.Role.Name,

  RoleEnvironment.CurrentRoleInstance.Id);

  var conf = instanceManager.GetCurrentConfiguration();

  conf.Logs.ScheduledTransferLogLevelFilter = LogLevel.Information;

  instanceManager.SetCurrentConfiguration(conf);

  …

}

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

public ActionResult ChangeLogLevel()

{

  var account = CloudStorageAccount.FromConfigurationSetting(“DiagnosticConnectionString”);

  var deploymentManager = new DeploymentDiagnosticManager(account, RoleEnvironment.DeploymentId);

// Получить коллекцию всех менеджеров диагностики

  var instanceManagers = deploymentManager.GetRoleInstanceDiagnosticManagersForRole

   (RoleEnvironment.CurrentRoleInstance.Role.Name);

  foreach (var instanceManager in instanceManagers)

  {

    var conf = instanceManager.GetCurrentConfiguration();

    conf.Logs.ScheduledTransferLogLevelFilter = LogLevel.Information;

    instanceManager.SetCurrentConfiguration(conf);

  }

  …

}

Настройки диагностики могут быть изменены удаленно. Это можно сделать, например, из обычного Windows-приложения. Отличием от приведенного выше кода является то, что вместо класса RoleEnvironment следует использовать данные, хранящиеся, например, в конфигурационном файле или получаемые динамически через соответствующие программные интерфейсы Windows Azure. Также можно изменить настройки диагностики и из скрипта на PowerShell – в этом случае следует использовать Windows Azure Platform PowerShell Cmdlets или Azure Management Cmdlets компании Cerebrata. Подробнее см. в этой публикации.

Настройка передачи данных

Выше мы познакомились с настройкой монитора диагностики и узнали о различных источниках диагностических данных. Следующий шаг в использовании механизмов диагностики Windows Azure – это настройка передачи данных с целью их сохранения в надежном хранилище для агрегации и последующего анализа.

Как мы отметили выше, собранные диагностические данные могут быть сохранены либо по заранее заданному расписанию, либо по запросу. В примерах, приведенных выше, мы использовали свойство ScheduledTransferPeriod для задания интервала сохранения данных. По умолчанию, значение этого свойства равно нулю, т.е. собранные данные не передаются в хранилище Windows Azure. Если изменить значение свойство ScheduledTransferPeriod на TimeSpan. FromSeconds() или TimeSpan. FromMinutes() , то можно задать необходимый интервал автоматического сохранения данных. Для того, чтобы все данные из всех источников не передавались одновременно (что может привести к снижению производительности), рекомендуется задавать различные значения TimeSpan для различных источников, желательно не кратные друг другу. В приведенном ниже примере интервалы передачи данных задаются с помощью простых чисел.

conf.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(3);

conf.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(5);

conf.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(9);

Также обратите внимание на то, что данные для одного источника передаются практически одновременно из всех экземпляров роли. Это тоже может иметь негативные последствия для производительности, поэтому не следует стремиться к тому, чтобы собрать и агрегировать максимальное количество данных. Сбор существенных объемов диагностических данных может быть оправдан в процессе отладки приложения, при его запуске в эксплуатацию следует ограничиться минимально разумным набором данных и, по возможности, сохранять их не по расписанию, а по запросу.

Для передачи данных по запросу используется класс DeploymentDiagnosticMonitor, который предоставляет следующие методы:

  • BeginOnDemandTransfer
  • EndOnDemandTransfer
  • CancelOnDemandTransfer

Ниже показан пример использования этих методов.

var account = CloudStorageAccount.FromConfigurationSetting(“DiagnosticConnectionString”);

var deploymentManager = new DeploymentDiagnosticManager(account, RoleEnvironment.DeploymentId);

var instanceManager = deploymentManager.GetRoleInstanceDiagnosticManager

(RoleEnvironment.CurrentRoleInstance.Role.Name, RoleEnvironment.CurrentRoleInstance.Role.Id);

// Принудительно завершить все передачи данных

instanceManager.CancelOnDemandTransfers(DataBufferName.Logs);

var options = new OnDemandTransferOptions

{

  From = DateTime.UtcNow.AddMinutes(-10),

  To = DateTime.Now,

  LogLevelFilter = LogLevel.Verbose,

  NotificationQueueName = “wad-transfers-queue”

};

Guid transferId = instanceManager.BeginOnDemandTransfer(DataBufefrName.Logs, options);

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

string id = transferId.ToString();

var queue = account

.CreateCloudQueueClient()

.GetQueueReference(“wad-transfers-queue”);

while (true)

{

  var message = queue.GetMessage()l

  if (message != null)

  {

   Queue.DeleteMessage(message);

   var reader = XmlReader.Create(new StringReader(message.AsString));

   if (reader.ReadeToDescendant(“C”))

   {

     var decodedContentBytes = Convert.FromBase64String(reader.ReadString());

     using (var stream = new MemoryStream(decodedContentBytes))

     {

       reader = XmlReader.Create(stream);

     }

    if (reader.ReadToDescendant(“RequestId”))

    {

      string requestId = reader.ReadString();

      if (requestId == id)

     {

      break;

     }

   }

  }

}

Thread.Sleep(1000);

}

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

В следующей части мы рассмотрим способы профилирования приложений, выполняющихся на платформе Windows Azure.