Usar los contadores de rendimiento de SignalR en un rol web de Azure

Por Luke Latham

Advertencia

Esta documentación no es para la última versión de SignalR. Eche un vistazo a SignalR de ASP.NET Core.

Los contadores de rendimiento de SignalR se usan para supervisar el rendimiento de la aplicación en un rol web de Azure. Microsoft Azure Diagnostics captura los contadores. Los contadores de rendimiento de SignalR se instalan en Azure con signalr.exe, la misma herramienta que se usa para aplicaciones independientes o locales. Dado que los roles de Azure son transitorios, configurará una aplicación para instalar y registrar contadores de rendimiento de SignalR al iniciarse.

Requisitos previos

Creación de una aplicación de rol web de Azure que expone contadores de rendimiento de SignalR

  1. Abierto Visual Studio.

  2. Abra Visual Studio, seleccione Archivo>Nuevo>Proyecto.

  3. En el cuadro de diálogo Nuevo proyecto, seleccione la categoría Visual C#>Cloud de la izquierda y, a continuación, seleccione la plantilla Servicio en la nube de Azure. Asigne a la aplicación el nombre SignalRPerfCounters y seleccione Aceptar.

    New Cloud Application

    Nota:

    Si no ve la categoría de plantilla Nube o la plantilla de servicio en la nube de Azure, debe instalar la carga de trabajo para Visual Studio 2017 desarrollo de Azure. Elija el vínculo Abrir instalador de Visual Studio en el lado inferior izquierdo del diálogo Nuevo proyecto para abrir el Instalador de Visual Studio. Seleccione la carga de trabajo Desarrollo de Azure y elijaModificar para empezar a instalar la carga de trabajo.

    Azure development workload in Visual Studio Installer

  4. En el diálogo Nuevo servicio en la nube de Microsoft Azure, seleccione rol web de ASP.NET y seleccione el botón > para agregar el rol al proyecto. Seleccione Aceptar.

    Add ASP.NET Web Role

  5. En el diálogo Nuevo rol web 1 de Aplicación - web de ASP.NET, seleccione la plantilla MVC y, a continuación, seleccione Aceptar.

    Add MVC and Web API

  6. En el Explorador de soluciones, abra el archivo diagnostics.wadcfgx en Rol web 1.

    Solution Explorer diagnostics.wadcfgx

  7. Reemplace el contenido del archivo por la siguiente configuración y guárdelo:

    <?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. Abra la Consola del administrador de paquetes desde Herramientas> Administrador de paquetes NuGet. Escriba los siguientes comandos para instalar la versión más reciente de SignalR y el paquete de utilidades de SignalR:

    install-package microsoft.aspnet.signalr
    install-package microsoft.aspnet.signalr.utils
    
  9. Configure la aplicación para instalar los contadores de rendimiento de SignalR en la instancia de rol cuando se inicia o recicla. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto Rol web 1 y seleccione Agregar>Nueva carpeta. Asigne el nombre Inicio a la nueva carpeta.

    Add Startup Folder

  10. Copie el archivo signalr.exe (agregado con el paquete Microsoft.AspNet.SignalR.Utils ) de la <carpeta del proyecto>/SignalRPerfCounters/packages/Microsoft.AspNet.SignalR.Utils.<version>/tools a la carpetaInicio que creó en el paso anterior.

  11. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Inicio y seleccione Agregar>elemento existente. En el diálogo que aparece, seleccione signalr.exe y seleccione Agregar.

    Add signalr.exe to project

  12. Haga clic con el botón derecho en la carpeta de Inicio que creó. Seleccione Agregar>Nuevo elemento. Seleccione el nodo General, seleccione Archivo de texto y asigne un nombre al nuevo elemento SignalRPerfCounterInstall.cmd. Este archivo de comandos instalará los contadores de rendimiento de SignalR en el rol web.

    Create SignalR performance counter installation batch file

  13. Cuando Visual Studio crea el archivo SignalRPerfCounterInstall.cmd, se abrirá automáticamente en la ventana principal. Reemplace el contenido del archivo por el siguiente script y, a continuación, guarde y cierre el archivo. Este script ejecuta signalr.exe, que agrega los contadores de rendimiento de SignalR a la instancia de rol.

    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. Seleccione el archivo signalr.exe en el Explorador de soluciones. En las Propiedades del archivo, configure Copiar al Directorio de salida en Copiar siempre.

    Set Copy to Output Directory to Copy Always

  15. Repita el paso anterior para el archivo SignalRPerfCounterInstall.cmd.

  16. Haga clic con el botón derecho en el archivo SignalRPerfCounterInstall.cmd y seleccione Abrir con. En el diálogo que aparece, seleccione Editor binario y seleccione Aceptar.

    Open with Binary Editor

  17. En el editor binario, seleccione los bytes iniciales del archivo y elimínelos. Guarde y cierre el archivo.

    Delete leading bytes

  18. Abra ServiceDefinition.csdef y agregue una tarea de inicio que ejecute el archivo SignalrPerfCounterInstall.cmd cuando se inicie el servicio:

    <?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. Abra Views/Shared/_Layout.cshtml y quite el script de agrupación de jQuery del final del archivo.

    <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. Agregue un cliente de JavaScript que llame continuamente al método increment en el servidor. Abra Views/Home/Index.cshtml y reemplace el contenido por el código siguiente:

    @{
        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. Cree una nueva carpeta en el proyecto Rol web 1 denominada Centros de conectividad. Haga clic con el botón derecho en la carpeta Centros de conectividad en el Explorador de soluciones y seleccione Agregar>nuevo elemento. En el diálogo Agregar nuevo elemento, seleccione la categoría Web>SignalR y, a continuación, seleccione la plantilla de elemento Centro de conectividad clase (v2) de SignalR. Asigne al nuevo centro el nombre MyHub.cs y seleccione Agregar.

    Adding SignalR Hub Class to the Hubs folder in the Add New Item dialog

  22. MyHub.cs se abrirá automáticamente en la ventana principal. Reemplace el contenido por el código siguiente y, a continuación, guarde y cierre el archivo:

    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 es una herramienta de prueba de densidad de conexión que se proporciona con el código base de SignalR. Dado que Crank requiere una conexión persistente, agregue una a su sitio para usarla al probar. Agregue una nueva carpeta al proyecto Rol web 1 denominada PersistentConnections. Haga clic con el botón derecho en la carpeta y seleccione Agregar>Clase. Asigne un nombre al nuevo archivo de clase MyPersistentConnections.cs y seleccione Agregar.

  24. Visual Studio abrirá el archivo MyPersistentConnections.cs en la ventana principal. Reemplace el contenido por el código siguiente y, a continuación, guarde y cierre el archivo:

    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. Cuando se usa la clase Startup, los objetos SignalR se inician cuando se inicia OWIN. Abra o cree Startup.cs y reemplace el contenido por el código siguiente:

    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");
            }
        }
    }
    

    En el código anterior, el atributo OwinStartup marca esta clase para que inicie OWIN. El métodoConfiguration inicia SignalR.

  26. Pruebe la aplicación en Microsoft Azure Emulator presionando F5.

    Nota:

    Si encuentra una FileLoadException en MapSignalR, cambie las redirecciones de enlace en web.config a lo siguiente:

    <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. Espere un minuto. Abra la ventana de herramientas de Cloud Explorer en Visual Studio (Ver>Cloud Explorer) y expanda la ruta de acceso (Local)/Storage Accounts/(Development)/Tables. Haga doble clic en WADPerformanceCountersTable. Debería ver contadores de SignalR en los datos de la tabla. Si no ve la tabla, es posible que tenga que volver a escribir las credenciales de Azure Storage. Es posible que tenga que seleccionar el botón Actualizar para ver la tabla en Cloud Explorer o seleccionar el botón Actualizar en la ventana abrir tabla para ver los datos. de la tabla.

    Selecting the WAD Performance Counters Table in Visual Studio Cloud Explorer

    Showing the counters collected in the WAD Performance Counters Table

  28. Para probar la aplicación en la nube, actualice el archivo ServiceConfiguration.Cloud.cscfg y establezca el Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString a una cadena de conexión válida de una cuenta de Azure Storage.

    <?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. Implemente la aplicación en la suscripción de Azure. Para más información sobre cómo implementar una aplicación en Azure, consulte Creación e implementación de un servicio en la nube.

  30. Espere unos minutos. En Cloud Explorer, busque la cuenta de almacenamiento que configuró anteriormente y busque la tabla WADPerformanceCountersTable en ella. Debería ver contadores de SignalR en los datos de la tabla. Si no ve la tabla, es posible que tenga que volver a escribir las credenciales de Azure Storage. Es posible que tenga que seleccionar el botón Actualizar para ver la tabla en Cloud Explorer o seleccionar el botón Actualizar en la ventana abrir tabla para ver los datos. de la tabla.

Gracias especial a Martin Richard por el contenido original usado en este tutorial.