Вероятно, в последнее время вы много слышите о Windows Azure. Это отличная платформа для создания и развертывания веб-приложений. Кроме того, она предоставляет хорошую инфраструктуру для сбора и передачи диагностических данных о выполняемых приложении и роли. Но, увы, не оправдывает ожиданий в отношении записи этих данных в какое-либо удобное хранилище и никак не помогает в их визуализации и анализе.
Знакомьтесь с SQL Azure Reporting CTP — это тема моей нынешней статьи. Она может показаться заурядной (по стандартам разработчиков), но я намерен раскрыть ее в контексте управления и мониторинга своих систем, развернутых в Windows Azure. Я продемонстрирую SQL Azure Reporting CTP на примере использования данных от счетчиков производительности, получаемых при диагностике веб-роли. На сегодняшний день чаще всего применяют либо передачу информации обратно на локальный компьютер, либо обращаются к хранилищу данных SQL Azure с локального компьютера через средства формирования отчетности, например SQL Server Reporting Services или Microsoft Excel.
К сожалению, следование этим шаблонам в текущих реализациях имеет ряд существенных недостатков. С одной стороны, если все данные переносятся в локальное хранилище для формирования отчетов, это может привести не только к увеличению расходов, но и к тому, что вы будете получать устаревшую информацию. А с другой, если вы обращаетесь к SQL Azure для формирования локального отчета или применения локального инструмента, можно сократить объем передаваемых данных за счет их агрегации и суммирования, но процесс их передачи все равно никуда не денется; в случае нетривиального отчета латентность скорее всего останется немалой. Храня эти данные в облаке и выдавая отчеты из облака, вы можете передавать лишь необходимые представления данных, что сохранит их актуальность и уменьшит латентность до минимума.
Проект и подготовка
Чтобы осуществить этот проект, первым делом я определился с тем, какие данные нужно собирать, куда их помещать и как формировать отчеты на их основе. В данном случае я намерен собирать значения наиболее важных счетчиков, которые я всегда анализирую при проверке производительности: % времени в GC (percent time in GC) и % загруженности процессора (percent CPU time). Мне понадобится перемещать эти данные из места их «складирования» (Azure Table Storage) в SQL Azure, чтобы упростить формирование отчетов. Этот поток данных показан на рис. 1.
_mini_oszone.jpg)
Увеличить
Рис. 1. Поток данных
Используя эту схему, можно определить области, где мне потребуется приложить усилия. Номера на схеме соответствуют следующему.
- Конфигурирование диагностики для ролей.
- Выполняется через конфигурирование.
- Передача в SQL Azure:
- создание рабочей роли, которая через некий интервал перемещает данные;
- определение схемы для таблиц данных.
- Формирование отчетов:
- создание запроса для извлечения нужных данных в подходящем формате;
- создание определения отчета для визуализации данных в нем.
Средства формирования отчетов в SQL Azure
На момент написания этой статьи функциональность отчетов в SQL Azure существовала в виде CTP-версии, на которую можно подписаться по ссылке connect.microsoft.com/sqlazurectps. Как только я активировал SQL Azure Reporting в своей учетной записи, я смог перейти к нему в портале управления и увидел примерно то, что показано на рис. 2.
.png)
Рис. 2. SQL Azure Reporting CTP
Важно отметить, что впоследствии, когда я создам этот пример, мне потребуется как URL веб-сервиса, так и имя пользователя (Username). Если вы создаете пример вместе со мной, вам понадобятся свои реквизиты (ваши URL и имя пользователя). В целом, после того, как вы получаете доступ к SQL Azure, он готов и просто ждет развертывания ваших отчетов.
Для создания отчетов и их развертывания в сервисе вам также понадобится Business Intelligence Development Studio (BIDS).
Настройка диагностики
Для сбора нужных данных я должен создать пару объектов PerformanceCounterConfiguration и добавить их в PerformanceCounters.DataSources в методе OnStart интересующих меня ролей. У меня есть простая веб-роль, не модифицированная из шаблона, но она будет источником данных. Я настраиваю оба счетчика на выборку значений через каждые пять секунд и переношу собранные данные в Table Storage через каждую минуту. Соответствующий код показан на рис. 3. Эти цифры совершенно смехотворны для использования на практике и годятся только для проверки концепции, но я-то как раз этим и занимаюсь и хотел бы собрать достаточный объем данных за короткое время, чтобы сгенерировать более-менее репрезентативный отчет.
Рис. 3. Код для сбора данных в примере
// Создаем счетчик производительности
var performanceConfiguration =
new PerformanceCounterConfiguration();
performanceConfiguration.CounterSpecifier =
@"\Processor(_Total)\% Processor Time";
performanceConfiguration.SampleRate =
System.TimeSpan.FromSeconds(5.0);
// Добавляем счетчик в конфигурацию
config.PerformanceCounters.DataSources.Add(
performanceConfiguration);
performanceConfiguration =
new PerformanceCounterConfiguration();
performanceConfiguration.CounterSpecifier =
@"\.NET CLR Memory(_Global_)\% Time in GC";
performanceConfiguration.SampleRate =
System.TimeSpan.FromSeconds(5.0);
config.PerformanceCounters.DataSources.Add(
performanceConfiguration);
config.PerformanceCounters.ScheduledTransferPeriod =
System.TimeSpan.FromMinutes(1.0);
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.
Diagnostics.ConnectionString", config);
Захват данных и формирование отчетов
Теперь мне нужно захватывать данные и хранить их в каком-то формате для последующего формирования отчета. Очевидной выбор для хранения данных в моем случае — SQL Azure, и не только потому, что это структурированное хранилище для Windows Azure, но и единственный источник данных, который в настоящее время может быть использован SQL Azure Reporting. Выбирая место развертывания для ролей Windows Azure Storage, SQL Azure и SQL Azure Reporting, лучше всего размещать их в одном информационном центре или хотя бы в одном географическом регионе, чтобы избежать любых лишних расходов.
Схема данных и их передача
В этом примере я буду использовать простую схему. У меня есть поле Id, которое служит для идентификации и используется как основной ключ (primary key, PK), хотя более реалистичным PK было бы нечто вроде ComputerName + CounterName + TimeStamp. рис. 4 представляет мою простую схему для хранения данных от счетчиков производительности.
рис. 4. Простая схема для хранения данных от счетчиков производительности
Имя | Тип |
Id | Identity, Int |
TimeStamp | Nvarchar(50) |
CounterName | Nvarchar(50) |
CounterValue | Real |
Изначально я хранил TimeStamp как настоящее поле типа TimeStamp, но потом сменил его тип на строку, чтобы упростить манипуляции с этими значениями. Как правило, на начальных этапах разработки я использую локальный экземпляр SQL Server, а потом (по готовности) я заменяю строку подключения на соединение с SQL Azure и запускаю скрипт, создающий нужные таблицы.
Теперь, когда мои данные помещены в Table Storage и для них есть место в SQL Azure, мне нужна рабочая роль, которая будет перемещать эти данные, поэтому я добавляю в решение рабочую роль. В метод OnStart я вставляю стандартный код публикации конфигурации, так как мне нужно получать кое-какую информацию о настройках рис. 5.
Рис. 5. Стандартный код публикации конфигурации
ServicePointManager.DefaultConnectionLimit = 12;
CloudStorageAccount.SetConfigurationSettingPublisher((
configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(
configName));
RoleEnvironment.Changed += (sender, arg) =>
{
if (arg.Changes.OfType<
RoleEnvironmentConfigurationSettingChange>().
Any((change) => (change.ConfigurationSettingName ==
configName)))
{
if(!configSetter(RoleEnvironment.
GetConfigurationSettingValue(configName)))
{
RoleEnvironment.RequestRecycle();
}
}
};
});
Затем я добавляю в класс метод TransferPerfDataToSql. В этом методе я буду получать доступные данные и усреднять их. Метод Run «спит» у меня примерно минуту, поэтому для каждого счетчика будет несколько записей. Так как на самом деле меня не интересует высокая точность значений счетчиков, я буду усреднять их перед каждой операцией перемещения. Таким образом, независимо от интервала выборки, заданного для счетчиков производительности, я буду объединять их значения в одну запись через каждую минуту и 15 секунд. Для большей ясности кода в примере я делаю это раздельно для каждого счетчика, хотя все это можно было бы выполнить одним выражением. На рис. 6 показано, как это выглядит для одного счетчика.
Рис. 6. Получение единого значения в течение интервала
var account = CloudStorageAccount.FromConfigurationSetting(
"Microsoft.WindowsAzure.Plugins.Diagnostics.
ConnectionString");
var context = new PerformanceDataContext(
account.TableEndpoint.ToString(), account.Credentials);
var data = context.PerfData;
// Получаем усредненное значение
List<PerformanceData> selectedData =
(from d in data
where d.CounterName == @"\Processor(_Total)\% Processor Time"
select d).ToList<PerformanceData>();
double AvgCPU = (from d in selectedData
where d.CounterName == @"\Processor(_Total)\% Processor Time"
select d.CounterValue).Average();
Получив значение, нужно удалить данные из Table Storage. Я мог бы напрямую обращаться к REST API, но в примере я просто перебираю в цикле выбранные объекты и передаю их в DeleteObject контекста:
foreach (PerformanceData perfdata in selectedData)
{
context.DeleteObject(perfdata);
}
context.SaveChanges();
Я повторяю этот код и счетчика GC. Каждое полученное значение нужно добавить в хранилище данных. Я создал файл .edmx для таблицы CounterData, применительно к которой написал код, добавляющий в нее данные рис. 7.
Рис. 7. Добавление данных в таблицу CounterData
PerfDataEntities pde = new PerfDataEntities();
CounterData cd = new CounterData();
cd.CounterName = @"\Processor(_Total)\% Processor Time";
cd.CounterValue = (float)AvgCPU;
cd.TimeStamp = System.DateTime.Now.ToString();
pde.AddToCounterDatas(cd);
cd = new CounterData();
cd.CounterName = @"\.NET CLR Memory(_Global_)\% Time in GC";
cd.CounterValue = (float)AvgTimeGC;
cd.TimeStamp = System.DateTime.Now.ToString();
pde.AddToCounterDatas(cd);
pde.SaveChanges();
context.SaveChanges();
Теперь остается лишь написать отчет — это самая желанная задача. (Да, это сарказм.)
Отчет
Писатель отчетов из меня никудышный, и, если честно, глаза мои их не видели бы. Поэтому я создам относительно простой отчет, просто чтобы проиллюстрировать отображение данных в сетке и построение графика для визуализации данных.
Первый шаг — запрос данных в формате, необходимом для создания отчета. Данные, сохраненные в базе данных SQL Azure, являются средними значениями за примерно минутный интервал, а значит, каждая точка данных представляет минуту. Однако в отчете данные будут представляться одной точкой за каждый час, что дает 24 точки в сутки. Для этого я разделяю содержимое поля TimeStamp, используя DATEPART, и выполняю группирование по дням и часам. Это дает нам такой запрос:
SELECT
DATEPART(DD, [TimeStamp]) as [Day]
,DATEPART(HH, [TimeStamp]) as [Hour]
,[CounterName]
,Avg([CounterValue]) [Value]
FROM [dbo].[CounterData]
Group by DATEPART(DD, [TimeStamp]),
DATEPART(HH, [TimeStamp]), CounterName
Order By CounterName
Далее я открываю BIDS и создаю новый проект отчета. Я добавляю два источника данных: один — для облака, а другой — для локального использования. Отчет лучше всего разрабатывать применительно к локальному хранилищу, так как его предварительный просмотр будет быстрее и не надо платить за трафик, генерируемый при формировании отчета. И вообще, реализуя отчет или любой другой проект для облака, я сначала добиваюсь, чтобы их части работали локально, и только потом быстро проверяю, что они работоспособны и в облаке. Наличие двух источников данных сильно упрощает проверку применительно к SQL Azure. После источников данных я добавляю набор данных в отчет, используя ранее упомянутый SQL-код для определения набора данных.
Теперь я добавляю в проект пустой отчет и присваиваю ему имя CounterDatabyHour.rdl. Поскольку мне нужны сетка данных и линейный график, я добавляю tablix и диаграмму sparkline. В случае tablix я использую значение day для заголовков полей от второго до n-го в первой строке, значение hour для заголовков полей от второго до n-го во второй строке и данные в качестве значений в полях каждой строки, сгенерированной с помощью Group By CounterName. В случае диаграммы я задаю CounterName как группы данных и использую hour и day как группы категории (category groups). В итоге я получаю в дизайнере нечто вроде того, что показано на рис. 8.
.png)
Рис. 8. Проектирование диаграммы
В tablix есть выражения, но это просто CStr-функции, манипулирующие значениями полей. Отчет готов, и мне осталось лишь разместить его в облаке. Но сначала нужно сконфигурировать решение на развертывание в облаке. Для этого я открываю свойства решения и для TargetServerURL присваиваю URL, предоставляемый в Windows Azure Management Portal, с пометкой «reportserver». Таким образом, мой URL выглядит как https://rsprodctp2585.ctp.reporting.database.windows.net/ReportServer.
Для этой операции в SQL Azure Reporting нужно использовать HTTPS, но этот протокол в любом случае предпочтителен, так как компании требуется конфиденциальность информации о состоянии ее серверов и данных по производительности. Теперь я развертываю отчет, и у меня запрашивают мои удостоверения — имя пользователя и пароль (копируются с портала управления), как показано на рис. 9.
.png)
Рис. 9. Развертывание отчета
Если проверка пройдет успешно, отчет должен быть благополучно развернут и я смогу перейти прямо на сайт, войти в него и запустить отчет из браузера (рис. 10).
.png)
Рис. 10. Просмотр отчета в браузере
В некоторых случаях вам понадобится напрямую ссылаться на отчет, но во многих других случаях вы предпочтете использовать его как элемент управления, встроенный в приложение или веб-страницу. Здесь самое главное в том, что пользователь этих отчетов не видит никакой разницы от отчетов SQL Server Reporting Services. Разработчик отчетов выполняет несколько другие операции, но и для него многое остается прежним.
Заключение
Мой пример прост и надуман, но тот, кто лучше умеет пользоваться BIDS и больше подкован в написании универсальных отчетов, найдет, что средства SQL Azure Reporting CTP — для создания параметров, связанных отчетов, выражений и тому подобных вещей — образуют платформу для генерации наглядных отчетов с богатой функциональностью, которые могут быть сложны настолько, насколько пожелает их разработчик.
SQL Azure Reporting дает разработчикам привычную парадигму создания и распространения отчетов с той существенной разницей, что никому не нужно беспокоиться об их инфраструктуре. Одно из крупных преимуществ — возможность применения этого сервиса для формирования отчетов на основе различных типов диагностических данных, а также для мониторинга любых аспектов развернутой системы. С помощью SQL Azure Reporting вы можете собирать данные в централизованную базу данных для генерации отчетов и даже создавать отчеты на основе информации от разных систем, сохраняя данные в раздельных базах данных (лишь бы они были базами данных SQL Azure). В планах заявлена поддержка других источников данных, но даже в нынешней инкарнации SQL Azure Reporting — эффективное и желанное пополнение в инструментарии Windows Azure.