У нас есть Workflow сервис, выполняющий некоторый процесс и сейчас нет средства Real-Time мониторинга этого сервиса.
Расширение AppFabric к IIS показывает кумулятивную информацию о количестве инстансов за период, но чтобы видеть последнюю информацию, нужно постоянно жать руками на обновление. Так же нельзя сравнить количество инстансов в периоде.
Можно снять данные с Monitoring Database — это решение опять же завязано на AppFabric, также получение последних изменений в real-time сложно (нужно делать регулярные запросы и т.д. и т.п.)
Нужно придумать способ узнавать информацию о некотором наборе метрик в виде диаграмм на chart с постоянным обновлением текущего состояния.
Кому это нужно
Все кто предварительно читать статью, задавали один и тот же вопрос- для кого все это сделано.
Ответ- в случаи просадки производительности, которая началась и еще не закончилась- этот инструмент как раз и показывает состояние части системы. Зная нормальные значения, можно увидеть что они не в порядке, или происходят какие-либо всплески. Фактически- это инструмент мониторинга работающего сервера ведь.
Выбор библиотек
Выбор библиотеки для реализации Real Time Server
Выбор был по большом счету предопределен: когда есть решение рекомендованное вендором платформы (SignalR от Microsoft), то все остальные почти всегда идут лесом. Для очистки совести (и самообразования) было проведено изучение еще одной библиотеки, которую смогли нагуглить — Xsocket.
На сайте Xsocket есть сравнение. Там достаточно много параметров. Каждый вендор свое болото хвалит, как известно. Я выбрал несколько ключевых параметров по которым отвалился xsocket.
- Только websockets, webrtc. Т.к. ни каких ServerSiteEvents, ForeverFrame, longpooling. В IE не поддерживает webrtc. В итоге IE9 не поддерживается, а в компании много народу сидит на win7 без sp1 даже… А следовательно, вообще с IE8. Уже этого достаточно, чтобы не смотреть на эту библиотеку;
- Платная поддержка;
- Количество скачивания с nuget на порядок меньше чем у signalr.
Я не готов брать проект не вендора и при этом не видно, чем он принципиально лучше. SignalR более популярна и решает поставленную задачу.
Выбор клиентской библиотеки отображения графиков
Библиотека для отображения графиков была выбрана canvasjs . Причина выбора проста: Google выдал ее по запросу «rea ltime chart js library». В течение часа разбора по этому вопросу было принято решение: не тратить время на изучение альтернатив, если уже это нам подходит. Библиотека работает и с Chrome и с IE9+. Значит, подходит.
Выбор библиотеки хранения данных:
StreamInsight — рекомендованная Microsoft платформа для реализации системы мониторинга.
Цитата:
Microsoft Stream Insight provides a powerful platform for developing and deploying complex event processing (CEP) applications. CEP is a technology for high-throughput, low-latency processing of event streams. Typical event stream sources include data from manufacturing applications, financial trading applications, Web analytics, or operational analytics.
Изучение:
- Стартовая страница на Microsoft.com
- Блог команды
- Stream Insight examples
- Глоссарий — обязательно надо прочесть, иначе все не понятно совершенно.
- Видеокурс
Приступаем к разработке…
Устройство сервера с SignalR Hub
UI у нас в целом готов, можно приступать к разработке на сервере.
Тестовый пример Workflow
Перейдем от того, что видет клиент, к тому что в backend работает- workflow service. Создадим простейший пример workflow(ну не production же копировать).
Теперь у нас есть Workflow Service, и генератор запросов к нему.
Сбор данных
Внутри себя обработчик запросов к AppFabric — это Windows Workflow.
Работающий Workflow Instance генерирует и выстреливает события. По умолчанию есть 1 слушатель ETW (Event Tracing for Windows)). Он их обрабатывает и складывает в базу данных мониторинга appfabric.
Мы тоже хотим получать часть событий, отстреливаемых workflow.
Их можно получать 2 путями:
- ходить руками в базу данных мониторинга
- использовать Tracking Participant.
Вариант хождения в базу данных мониторинга хорош, но у него есть изъян: запросы создают нагрузку на базу, а чтобы получать информацию за некоторый короткий промежуток времени, нужно постоянно в эту базу посылать запросы. В итоге, мы будем генерировать паразитную нагрузку, которая может оказаться достаточно существенной.
Вариант Tracking Participant лучше в том смысле, что ему не нужна никакая база данных, чтобы эти события получать. Мы дальше можем их любым интересующим нас способом перенаправить туда, куда нужно.
Реализация Tracking Participant
Для этого нужно написать Tracking Participant, который будет приемником выстреливаемых событий.
Для реализации в коде tracking participant нужно реализовать 3 части:
-
BehaviorExtensionElement
-
IServiceBehavior
-
TrackingParticipan
После написания этого кода, необходимо
TrackingProfile
По умолчанию tracerecord генерируется достаточно много. Фильтровать данные в коде — это плохая идея, т.к. надо писать код проверок, да и это очистка от ненужных записей, всегда что-то можно пропустить. Лучше выбрать только интересующие нас записи. Это делается через TrackingProfile
В нем мы определяем query, в которых выбираем какие именно события мы хотим получать в tracking participant. Можно собирать события изменения состояния инстансов workflow, можно собирать на более низком уровне состояние активностей входящих в инстансе, можно фильтровать по именам активностей.
Таких запросов можно написать много. Данные мы собираем, теперь их нужно отстреливать в некоторое хранилище для обработки.
Как выбрать собираемые данные мы знаем. Пора уже связать интерфейс с источником данных через streamInsight
StreamInsight Server
Сам по себе StreamInsight сервер внутри несложен, тонкости начинаются при подключении входных потоков и создания из них выходных.
В целом, в коде ничего страшного: мы объявили wcf сервис для получения данных, signalr обертку для отправки данных в приложения для отображения.
Одна из основных фишек StreamInsight — это брать поток данных и нарезать этот поток на window. В нашем примере мы из потока данных сделали PointEvent. Т.к. каждое пришедшее из внешнего мира событие превращается в точку (есть время прихода, и входящий объект.). Приходящие сообщения формируют поток, и streaminsight нарезает этот поток на window, в нашем случаи используя Tumbling Window по 1 секунде. Все события пришедшие за секунду попадают в это окно.
Когда мы описали источник данных и потребителя, мы просто связываем это все в synk.
Есть еще 2 типа Event, и еще 3 типа окон. Нам для нашей задачи они оказались не нужны. Желающим понять глубже рекомендую прочесть >глоссарий из него все станет понятно.
Из нетривиального, стоит отметить CepOperator. Для того, чтобы создать окно событий из сложного объекта (не clr type), нам пришлось написать этот CepOperator.
Как и написано в комментариях, у StreamInsight один костыль. Он не поддерживает вложенные в объект массивы.Из-за этого пришлось написать костыль и конвертировать массив в json строку, и затем из него десериализовать.
Теперь у нас ест все 3 части. Источник данных, сервер, UI.Осталось их связать между собой.
Общение между StremInsight Server и источником данных Workflow
В принципе, просто реализуется интерфейс IObservable.
В итоге, на основе его далее строится wcf сервис.
Подключаем со стороны StreamInsight Server wcf proxy как источник сообщений.
//определяем источник данных.
var observableWcfSource = app.DefineObservable(() => new WcfObservable(wcfSourceUrl, «WcfObservableService»));
Клиент работы с SignalRHub
В целом ничего сложного.
//определяем средство доставки данных клиентам.
var observableSink = app.DefineObserver(() => new SignalRObserver(signalRHubUrl));
Результат
У нас есть Генератор запросов к Windows Workflow. WWF, который генерирует события, мы их ловим и передаем через WCF на StreamInsight Server. На Сервере мы агрегируем прилетающие события и пробрасываем их на SignalRHub на IIS и оттуда в browser. В браузере рисуем диаграмму.
Нагрузочное тестирование
Первая попытка протестировать все была на машине разработчика: win7sp1. НЕ НАДО ТЕСТИРОВАТЬ НАГРУЗКУ НА МАШИНЕ РАЗРАБОТЧИКА. Серверная винда и клиентская сильно отличаются своими настройками. Клиентскую можно использовать как positive test, т.е. если даже на ней летает, то и на сервере должно быть хорошо. Обратное не значит вообще ничего.
Тестирование отдачи от signalr hub в browser
1000 запросов за 60 секунд с одного генератора запросов, в signalr hub, и просмотр в 1 вкладке браузера прошла успешно. Для нашего кейса 17 запросов в секунду в hub — это нормальная нагрузка.
Затем мы повторили эксперимент: 1000 запросов за 60 секунд, но при этом 10 открытых вкладок. И вот тут мы больно ударились: оказалось, что отправка сообщений начинает подтормаживать, при достижении 7 клиентских подключений просто останавливается. Мы подумали, почитали и решили перейти с win7 на winserver.
( “1.IIS/Cassini on Windows 7 has a default limit of 10 concurrent connections. Try running tests on Windows Server and see if it behaves the same. ”). После теста на winserver 2012 стало очевидно, что пора уже забить на win7 надо и тестироваться на схожей с production среде (это и раньше было очевидно, но тестишь по началу всегда на своей машине) на iis есть ограничение числа соединений, их конечно можно поднять, но лучше win server.
Результаты на windows server 2012 с 1 открытой вкладкой браузера:
150000 запросов за 576 секунд= 260 запросов в секунду, т.е. уже на порядок выше, чем на клиентской, а это тем более удовлетворяет нашим потребностям.
Затем провели эксперимент с 10 открытыми вкладками, и все работало. Единственное, что при таком потоке сообщений отображение на canvas в браузере подтормаживало, но это уже мелочи.
Вывод: используйте серверную ОС, для серверных задач. SignalRHub работает достаточно быстро, чтобы перемалывать огромную массу сообщений.
Тестирование отображения в браузере
При 260 сообщений в секунду, конечно, браузер не успевает все отрисовать нормально, но на 50 сообщений в секунду уже все хорошо. Сам браузер память отжирает медленно, так что на 150000 chrome процесс не сожрал более 110мб, с учетом, что все точки он хранил в памяти. В общем, будем считать, что даже удалять старые записи из массива не будем, ибо смысла в этом нет.
Тестирование через SoapUI
Мы написали тест планы для тестирования используя SoapUI.
На нем я смог положить WCF сервис, через который влетают данные, причем сделать это так, чтобы он сам уже не поднялся
После разбирательства, было решено сделать метод PushEvent — OneWay. Потери событий небольшим допустимы, зато это привело к тому, что в сервис каждую секунду влетало 400событий в течении часа, и он работал на тех тестовых планах от SoapUI, которые раньше его убивали.
Дальнейшие изыскания
Я намеренно не стал описывать JS код мой, тк он требует доработки (нужно чтобы график умел работать в 2 режимах- осциллограф- когда данные ограничены промежутком времени, и сейсмограф- сколько собрал, все показать.). Если будет интерес, напишу отдельно.
Автор: SychevIgor