Использование счетчиков производительности SignalR в веб-роли Azure

Автор Люк Латэм (Luke Latham)

Предупреждение

Эта документация не подходит для последней версии SignalR. Взгляните на ASP.NET Core SignalR.

Счетчики производительности SignalR используются для мониторинга производительности приложения в веб-роли Azure. Счетчики собираются с помощью Microsoft Azure Diagnostics. Вы устанавливаете счетчики производительности SignalR в Azure с signalr.exe, то же средство, используемое для автономных или локальных приложений. Так как роли Azure являются временными, вы настраиваете приложение для установки и регистрации счетчиков производительности SignalR при запуске.

Предварительные требования

  • Visual Studio 2015 или 2017
  • Microsoft Azure SDK для Visual Studio.Примечание: Перезапустите машину после установки SDK.
  • Подписка Microsoft Azure: Чтобы зарегистрироваться для бесплатной пробной версии Azure, см. Azure Free Trial.

Создание приложения Azure Web Role, которое раскрывает счетчики производительности SignalR

  1. Откройте Visual Studio.

  2. В Visual Studio выберите Файл>Создать>Проект.

  3. В диалоговом окне "Новый проект" выберите категорию Visual C#>Cloud слева и выберите шаблон облачной службы Azure. Назовите приложение SignalRPerfCounters и нажмите кнопку "ОК".

    Новое облачное приложение

    Примечание.

    Если вы не видите категорию шаблона облака или шаблон облачной службы Azure, необходимо установить рабочую нагрузку разработки Azure для Visual Studio 2017. Щелкните ссылку Open Visual Studio Installer в левой нижней части диалогового окна "Создать проект", чтобы открыть Visual Studio Installer. Выберите рабочую нагрузку разработки Azure и нажмите кнопку "Изменить", чтобы начать установку рабочей нагрузки.

    Рабочая нагрузка разработки Azure в Visual Studio Installer

  4. В диалоговом окне "Новая облачная служба Microsoft Azure" выберите веб-роль ASP.NET и нажмите кнопку >, чтобы добавить роль в проект. Нажмите ОК.

    Добавление веб-роли ASP.NET

  5. В диалоговом окне "Новое ASP.NET веб-приложение — WebRole1" выберите шаблон MVC и нажмите кнопку "ОК".

    Добавление MVC и веб-API

  6. В Обозревателе решений откройте файл диагностики.wadcfgx под разделом WebRole1.

    Проводник решений diagnostics.wadcfgx

  7. Замените содержимое файла следующей конфигурацией и сохраните файл:

    <?xml version="1.0" encoding="utf-8"?>
    <DiagnosticsConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
      <PublicConfig>
        <WadCfg>
          <DiagnosticMonitorConfiguration overallQuotaInMB="4096">
            <DiagnosticInfrastructureLogs scheduledTransferLogLevelFilter="Error" />
            <Logs scheduledTransferPeriod="PT1M" scheduledTransferLogLevelFilter="Error" />
            <Directories scheduledTransferPeriod="PT1M">
              <IISLogs containerName ="wad-iis-logfiles" />
              <FailedRequestLogs containerName ="wad-failedrequestlogs" />
            </Directories>
            <WindowsEventLog scheduledTransferPeriod="PT1M">
              <DataSource name="Application!*[System[(Level=1 or Level=2 or Level=3)]]" />
              <DataSource name="Windows Azure!*[System[(Level=1 or Level=2 or Level=3 or Level=4)]]" />
            </WindowsEventLog>
            <CrashDumps containerName="wad-crashdumps" dumpType="Mini">
              <CrashDumpConfiguration processName="WaIISHost.exe" />
              <CrashDumpConfiguration processName="WaWorkerHost.exe" />
              <CrashDumpConfiguration processName="w3wp.exe" />
            </CrashDumps>
            <PerformanceCounters scheduledTransferPeriod="PT1M">
              <PerformanceCounterConfiguration counterSpecifier="\Memory\Available MBytes" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\ISAPI Extension Requests/sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\Bytes Total/Sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Requests/Sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Errors Total/Sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Queued" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Rejected" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\% Time in GC" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Exceptions(w3wp)\# of Exceps Thrown / sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\# of current logical Threads" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\# of current physical Threads" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\Current Queue Length" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\Contention Rate / sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# Bytes in all Heaps" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# GC Handles" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# of Pinned Objects" sampleRate="PT10S" />
    
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Connected" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Reconnected" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Disconnected" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Current" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Received Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Sent Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Received/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Sent/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Received Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Received/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Message Bus Messages Received/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Published Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Published/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers Current" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Allocated Workers" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Busy Workers" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Topics Current" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: All Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: All/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Resolution Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Resolution/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Invocation Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Invocation/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Tranport Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Transport/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Open" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Buffering" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Errors Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Errors/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Send Queue Length" sampleRate="PT10S" />
            </PerformanceCounters>
          </DiagnosticMonitorConfiguration>
        </WadCfg>
        <StorageAccount></StorageAccount>
      </PublicConfig>
      <PrivateConfig>
        <StorageAccount name="" key="" endpoint="" />
      </PrivateConfig>
      <IsEnabled>true</IsEnabled>
    </DiagnosticsConfiguration>
    
  8. Откройте консоль диспетчера пакетов из Инструменты>Диспетчер пакетов NuGet. Введите следующие команды, чтобы установить последнюю версию SignalR и пакет служебных программ SignalR:

    install-package microsoft.aspnet.signalr
    install-package microsoft.aspnet.signalr.utils
    
  9. Настройте приложение для установки счетчиков производительности SignalR в экземпляр роли при его запуске или перезапуске. В Обозревателе решений щелкните правой кнопкой мыши на проекте WebRole1 и выберите Добавить>Новая папка. Назовите новую папку Startup.

    Добавление папки запуска

  10. Скопируйте файл signalr.exe (добавленный пакетом Microsoft.AspNet.SignalR.Utils) из папки <project folder>/SignalRPerfCounters/packages/Microsoft.AspNet.SignalR.Utils.<version>/tools в папку Startup, созданную на предыдущем шаге.

  11. В Обозревателе решений щелкните правой кнопкой мыши папку «Запуск» и выберите Добавить>Существующий элемент. В появившемся диалоговом окне выберите signalr.exe и нажмите кнопку "Добавить".

    Добавление signalr.exe в проект

  12. Правой кнопкой мыши щелкните по созданной папке Автозагрузка. Щелкните Добавить>Новый элемент. Выберите узел "Общие", выберите текстовый файл и назовите новый элемент SignalRPerfCounterInstall.cmd. Этот файл команды установит счетчики производительности SignalR в веб-роль.

    Создание пакетного файла счетчика производительности SignalR

  13. Когда Visual Studio создает файл SignalRPerfCounterInstall.cmd , он автоматически откроется в главном окне. Замените содержимое файла следующим скриптом, а затем сохраните и закройте файл. Этот скрипт выполняет signalr.exe, который добавляет счетчики производительности SignalR для экземпляра роли.

    SET SignalR_LogDir=%~dp0Log\
    MKDIR "%SignalR_LogDir%"
    cd %~dp0
    signalr.exe ipc >> "%SignalR_LogDir%SignalR_Log.txt" 2>&1
    net localgroup "Performance Monitor Users" "Network Service" /ADD >> "%SignalR_LogDir%NetworkAdd.txt" 2>&1
    
  14. Выберите файл signalr.exe в Обозреватель решений. В свойствах файла установите Копировать в каталог вывода на Всегда копировать.

    Установите параметр

  15. Повторите предыдущий шаг для файла SignalRPerfCounterInstall.cmd .

  16. Щелкните правой кнопкой мыши на файле SignalRPerfCounterInstall.cmd и выберите Открыть с помощью. В появившемся диалоговом окне выберите "Двоичный редактор " и нажмите кнопку "ОК".

    Открытие с помощью двоичного редактора

  17. В двоичном редакторе выберите все ведущие байты в файле и удалите их. Сохранить и закрыть файл.

    Удаление ведущих байтов

  18. Откройте ServiceDefinition.csdef и добавьте задачу запуска, которая выполняет файл SignalrPerfCounterInstall.cmd при запуске службы:

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="SignalRPerfCounters" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
      <WebRole name="WebRole1" vmsize="Small">
        <Startup>
          <Task commandLine="Startup\SignalRPerfCounterInstall.cmd" executionContext="elevated" taskType="background" />
        </Startup>
        <Sites>
          <Site name="Web">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
        </Endpoints>
      </WebRole>
    </ServiceDefinition>
    
  19. Откройте Views/Shared/_Layout.cshtml и удалите скрипт пакета jQuery из конца файла.

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>
    
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
    </body>
    </html>
    
  20. Добавьте клиент JavaScript, который постоянно вызывает increment метод на сервере. Откройте Views/Home/Index.cshtml и замените содержимое следующим кодом:

    @{
        ViewBag.Title = "Home Page";
    }
    
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
    <script src="~/signalr/hubs" type="text/javascript"></script>
    
    <div id="body">
        <section class="featured">
            <div class="content-wrapper">
                <p>
                    Hello World!
                </p>
                <div style="font-size:large;">
                    My Counter: <span id="counter"></span>
                </div>
            </div>
        </section>
        <section class="content-wrapper main-content clear-fix"></section>
    </div>
    
    <script type="text/javascript">
      $(document).ready(function () {
        var hub = $.connection.myHub;
    
        hub.client.sendResult = function (x) {
          console.log('sendResult(' + x + ')');
          $("#counter").text(x);
          window.setTimeout(function () {
            hub.server.increment(x);
          }, 1000);
        };
    
        $.connection.hub.connected = function () {};
        $.connection.hub.disconnected = function () {};
    
        $.connection.hub.stateChanged(function (change) {
          console.log('new State' + change.newState);
          if (change.newState === $.signalR.connectionState.disconnected) {
            $.connection.hub.start();
          }
          if (change.newState === $.signalR.connectionState.reconnecting) {
            console.log('Re-connecting');
          } else if (change.newState === $.signalR.connectionState.connected) {
            console.log('The server is online');
          }
        });
    
        $.connection.hub.error(function (error) {
          console.log('error ' + error);
        });
        
        $.connection.hub.logging = true;
        
        $.connection.hub.reconnected(function () {
          console.log('Reconnected');
          hub.server.increment(0);
        });
    
        $.connection.hub.start().done(function () {
          console.log('hub started');
          hub.server.increment(0);
        });
      });
    </script>
    
  21. Создайте новую папку в проекте WebRole1 с именем Hubs. Щелкните правой кнопкой мыши папку "Центры" в Обозреватель решений и выберите "Добавить>новый элемент". В диалоговом окне "Добавление нового элемента" выберите категорию WebSignalR и затем выберите шаблон класса концентратора SignalR (v2). Назовите новый концентратор MyHub.cs и нажмите кнопку "Добавить".

    Добавление класса SignalR Hub в папку

  22. MyHub.cs автоматически откроется в главном окне. Замените содержимое следующим кодом, а затем сохраните и закройте файл:

    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR;
    
    namespace WebRole1.Hubs
    {
        public class MyHub : Hub
        {
            public async Task Increment(int x)
            {
                await this.Clients.Caller.sendResult(x + 1);
            }
        }
    }
    
  23. Crank.exe — это средство тестирования плотности подключения, предоставленное базой кода SignalR. Так как Crank требует постоянного подключения, вы добавляете его на сайт для использования при тестировании. Добавьте новую папку в проект WebRole1 с именем PersistentConnections. Щелкните эту папку правой кнопкой мыши и выберите "Добавить>класс". Назовите новый файл класса MyPersistentConnections.cs и нажмите кнопку "Добавить".

  24. Visual Studio откроет файл MyPersistentConnections.cs в главном окне. Замените содержимое следующим кодом, а затем сохраните и закройте файл:

    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Infrastructure;
    
    namespace WebRole1.PersistentConnections
    {
        public class MyPersistentConnection : PersistentConnection
        {
            protected override Task OnReceived(IRequest request, string connectionId, string data)
            {
                //Return data to calling user
                return Connection.Send(connectionId, data);        
            }
        }
    }
    
  25. С помощью класса Startup объекты SignalR запускаются при старте OWIN. Откройте или создайте Startup.cs и замените содержимое следующим кодом:

    using Microsoft.Owin;
    using Owin;
    using WebRole1.PersistentConnections;
    
    // Marks this class for automatic OWIN startup
    [assembly: OwinStartup(typeof(WebRole1.Startup))]
    namespace WebRole1
    {
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                ConfigureAuth(app);
                // Only needed if "No Authentication" was not selected for the project
                app.MapSignalR();
                app.MapSignalR<MyPersistentConnection>("/echo");
            }
        }
    }
    

    В приведенном выше коде атрибут OwinStartup обозначает этот класс для запуска OWIN. Метод Configuration запускает SignalR.

  26. Протестируйте приложение в эмулятор Microsoft Azure, нажав клавишу F5.

    Примечание.

    Если вы столкнулись с FileLoadException в MapSignalR, измените перенаправления привязки в web.config следующим образом:

    <dependentAssembly>
      <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.0.0" />
    </dependentAssembly>
    
  27. Подождите около одной минуты. Откройте окно инструментов Cloud Explorer в Visual Studio (просмотр>Cloud Explorer) и разверните путь.(Local)/Storage Accounts/(Development)/Tables Дважды щелкните WADPerformanceCountersTable. Счетчики SignalR должны отображаться в данных таблицы. Если таблица не отображается, может потребоваться повторно ввести учетные данные Azure Storage. Может потребоваться выбрать кнопку "Обновить", чтобы просмотреть таблицу в Cloud Explorer или кнопку "Обновить" в окне открытой таблицы, чтобы просмотреть данные в таблице.

    Выбор таблицы счетчиков производительности WAD в Visual Studio Cloud Explorer

    Отображение счетчиков, собранных в таблице счетчиков производительности WAD

  28. Чтобы протестировать приложение в облаке, обновите файл ServiceConfiguration.Cloud.cscfg и установите Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString на действительную строку подключения учетной записи в хранилище Azure.

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceConfiguration serviceName="SignalRPerfCounters" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2015-04.2.6">
      <Role name="WebRole1">
        <Instances count="1" />
        <ConfigurationSettings>
          <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=&lt;account-name&gt;;AccountKey=&lt;account-key&gt;" />
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>
    
  29. Разверните приложение в вашей подписке Azure. Дополнительные сведения о развертывании приложения в Azure см. в статье "Создание и развертывание облачной службы".

  30. Подождите несколько минут. В Cloud Explorer найдите учетную запись хранения, настроенную выше, и найдите в ней таблицу WADPerformanceCountersTable . Счетчики SignalR должны отображаться в данных таблицы. Если таблица не отображается, может потребоваться повторно ввести учетные данные Azure Storage. Может потребоваться выбрать кнопку "Обновить", чтобы просмотреть таблицу в Cloud Explorer или кнопку "Обновить" в окне открытой таблицы, чтобы просмотреть данные в таблице.

Особое спасибо Мартину Ричарду за исходное содержимое, используемое в этом руководстве.