Compartir vía


Guía para la solución de problemas comunes de Azure SignalR Service

En este artículo se proporciona una guía de solución de problemas para algunas de las incidencias comunes que pueden encontrar los clientes.

El token de acceso es demasiado largo

Errores posibles

  • ERR_CONNECTION_ en el lado cliente
  • 414 - URI de solicitud demasiado largo
  • 413 La carga es demasiado grande
  • El token de acceso no debe tener más de 4 K. 413 Entidad de solicitud demasiado larga

Causa principal

Para HTTP/2, la longitud máxima de un único encabezado es 4 K, por lo que si se usa el explorador para acceder al servicio de Azure, se produce un error ERR_CONNECTION_ para esta limitación.

Para los clientes HTTP/1.1 o C#, la longitud máxima del URI es 12 K y la longitud máxima del encabezado es 16 K.

Con la versión del SDK 1.0.6 o superior, /negotiate produce 413 Payload Too Large cuando el token de acceso generado es mayor que 4 K.

Solución

De forma predeterminada, las notificaciones de context.User.Claims se incluyen al generar el token de acceso JWT a ASRS(Azure SignalR Service), para que las notificaciones se conserven y se puedan pasar de ASRS a Hub cuando el cliente se conecta a Hub.

En algunos casos, los objetos context.User.Claims se usan para almacenar gran cantidad de información del servidor de aplicaciones, que en su mayoría no se usa en Hubs, sino en otros componentes.

El token de acceso generado se pasa a través de la red, y para las conexiones WebSocket/SSE, los tokens de acceso se pasan a través de las cadenas de consulta. Por lo tanto, como procedimiento recomendado, solo se sugiere pasar a través de ASRS las notificaciones necesarias del cliente al servidor de aplicaciones cuando Hub lo necesite.

Hay un objeto ClaimsProvider para personalizar las notificaciones que se pasan a ASRS dentro del token de acceso.

Para ASP.NET Core:

services.AddSignalR()
        .AddAzureSignalR(options =>
            {
                // pick up necessary claims
                options.ClaimsProvider = context => context.User.Claims.Where(...);
            });

Para ASP.NET:

services.MapAzureSignalR(GetType().FullName, options =>
            {
                // pick up necessary claims
                options.ClaimsProvider = context.Authentication?.User.Claims.Where(...);
            });

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

TLS 1.2 obligatorio

Errores posibles

  • Error 279 de ASP.NET que indica que no hay ningún servidor disponible.
  • ASP.NET "La conexión no está activa, los datos no se pueden enviar al servicio." #324
  • "Error al realizar la solicitud HTTP a https://<API endpoint>. Este error puede producirse si el certificado de servidor no está configurado correctamente con HTTP.SYS en el caso HTTPS. La posible causa de este error es una discrepancia del enlace de seguridad entre el cliente y el servidor."

Causa principal

El servicio de Azure solo admite TLS 1.2 por cuestiones de seguridad. Con .NET Framework, es posible que TLS 1.2 no sea el protocolo predeterminado. Como resultado, las conexiones del servidor a ASRS no se pueden establecer correctamente.

Guía de solución de problemas

  1. Si este error se puede reproducir localmente, desactive Solo mi código, genere todas las excepciones de CLR y depure el servidor de aplicaciones de forma local para ver qué excepción se produce.

    • Desactive Solo mi código.

      Desactivar Solo mi código

    • Generar excepciones de CLR

      Generar excepciones de CLR

    • Vea las excepciones que se generan al depurar el código del servidor de aplicaciones:

      Excepción generada

  2. En el caso de ASP.NET, también puede agregar el código siguiente a Startup.cs para habilitar el seguimiento detallado y ver los errores del registro.

    app.MapAzureSignalR(this.GetType().FullName);
    // Make sure this switch is called after MapAzureSignalR
    GlobalHost.TraceManager.Switch.Level = SourceLevels.Information;
    

Solución

Agregue el siguiente código a su página de inicio:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Error 400 Solicitud incorrecta devuelto para solicitudes de cliente

Causa principal

Compruebe si la solicitud de cliente tiene varias cadenas de consulta hub. El hub se conserva el parámetro de consulta y, si el servicio detecta más de un hub en la consulta, devuelve un error 400.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Se ha devuelto el error 401 No autorizado para las solicitudes de cliente.

Causa principal

Actualmente, el valor predeterminado de la duración del token JWT es de una (1) hora.

En el caso de ASP.NET Core SignalR, cuando se usa el tipo de transporte WebSocket, es correcto.

Para otro tipo de transporte de ASP.NET Core SignalR, SSE y sondeo prolongado, la duración predeterminada significa de forma predeterminada que la conexión puede persistir como máximo durante una hora.

En el caso de ASP.NET SignalR, el cliente envía una solicitud de "mantener conexión" de /ping al servicio de vez en cuando; cuando se produce un error de /ping, el cliente anula la conexión y nunca se vuelve a conectar. En el caso de ASP.NET SignalR, la duración del token predeterminada hace que la conexión dure como máximo una hora para todo el tipo de transporte.

Solución

Por motivos de seguridad, no se recomienda ampliar TTL. Se recomienda agregar lógica de reconexión del cliente para reiniciar la conexión cuando se produce el error 401. Cuando el cliente reinicia la conexión, negocia con el servidor de aplicaciones para obtener de nuevo el token JWT y obtener un token renovado.

Consulte aquí cómo reiniciar las conexiones de cliente.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Error 404 devuelto para solicitudes de cliente

En el caso de una conexión persistente de SignalR, primero realizará un proceso /negotiate en Azure SignalR Service y, a continuación, establecerá la conexión real con Azure SignalR Service.

Guía de solución de problemas

  • Consulte Cómo ver las solicitudes salientes para obtener la solicitud del cliente al servicio.
  • Compruebe la dirección URL de la solicitud cuando se produce el error 404. Si la dirección URL apunta a la aplicación web y es similar a {your_web_app}/hubs/{hubName}, compruebe si el cliente SkipNegotiation es true. El cliente recibe una dirección URL de redireccionamiento la primera vez que negocia con el servidor de aplicaciones. El cliente no debe omitir la negociación al usar Azure SignalR.
  • Se puede producir otro error 404 cuando la solicitud de conexión se controla durante más de cinco (5) segundos después de llamar a /negotiate. Compruebe la marca de tiempo de la solicitud de cliente e infórmenos del problema si la solicitud al servicio tiene una respuesta lenta.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Error 404 devuelto para la solicitud de reconexión de ASP.NET SignalR

En el caso de ASP.NET SignalR, cuando la conexión de cliente se interrumpe, se vuelve a conectar con el mismo parámetro connectionId tres veces antes de detener la conexión. /reconnect puede ayudar si la conexión se interrumpe debido a problemas intermitentes de la red, ya que /reconnect puede restablecer la conexión persistente correctamente. En otras circunstancias, por ejemplo, se quita la conexión de cliente debido a que se quita la conexión de servidor enrutada, o SignalR Service tiene algunos errores internos, como el reinicio de la instancia, la conmutación por error o la implementación. La conexión ya no existe, por lo que /reconnect devuelve 404. Es el comportamiento esperado para /reconnect y, después de tres reintentos, la conexión se detiene. Se recomienda tener una lógica de reinicio de conexión cuando se detiene la conexión.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Error 429 Demasiadas solicitudes devueltas para solicitudes de cliente

Hay dos casos.

El recuento de conexiones simultáneas supera el límite.

En el caso de las instancias Gratis, el límite del número de conexiones simultáneas es 20 para instancias Estándar y el límite del número de conexiones simultáneas por unidad es 1000, lo que significa que 100 unidades permitirán 100 000 conexiones simultáneas.

Las conexiones incluyen conexiones de cliente y de servidor. Consulte aquí cómo se cuentan las conexiones.

NegotiateThrottled

Cuando hay demasiados clientes negocian solicitudes en el mismo tiempo, podría limitarse. El límite se relaciona con los recuentos de unidades que tienen un límite mayor. Además, se recomienda tener un retraso aleatorio antes de volver a conectarse, compruebe aquí para ver ejemplos de reintento.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Error 500 con NEGOTIATE: Azure SignalR Service no está conectado todavía. Vuelva a intentarlo más tarde.

Causa principal

Este error se genera cuando no hay ninguna conexión de servidor a la instancia conectada de Azure SignalR Service.

Guía de solución de problemas

Habilite el seguimiento del lado servidor para averiguar los detalles del error cuando el servidor intenta conectarse a Azure SignalR Service.

Habilitación del registro del lado servidor para ASP.NET Core SignalR

El registro del lado servidor para ASP.NET Core SignalR se integra con los registros basados en ILogger proporcionado en el marco de ASP.NET Core. Puede habilitar el registro del lado servidor mediante ConfigureLogging. A continuación se incluye un ejemplo de uso:

.ConfigureLogging((hostingContext, logging) =>
        {
            logging.AddConsole();
            logging.AddDebug();
        })

Las categorías de registrador de Azure SignalR Service siempre comienzan con Microsoft.Azure.SignalR. Para habilitar registros detallados de Azure SignalR, configure los prefijos anteriores para Debug nivel en el archivo de appsettings.json, vea el ejemplo siguiente:

{
    "Logging": {
        "LogLevel": {
            ...
            "Microsoft.Azure.SignalR": "Debug",
            ...
        }
    }
}

Habilitación del seguimiento del lado servidor para ASP.NET SignalR

Cuando use una versión del SDK >= 1.0.0, podrá habilitar los seguimientos si agrega el código siguiente a web.config: (Detalles)

<system.diagnostics>
    <sources>
      <source name="Microsoft.Azure.SignalR" switchName="SignalRSwitch">
        <listeners>
          <add name="ASRS" />
        </listeners>
      </source>
    </sources>
    <!-- Sets the trace verbosity level -->
    <switches>
      <add name="SignalRSwitch" value="Information" />
    </switches>
    <!-- Specifies the trace writer for output -->
    <sharedListeners>
      <add name="ASRS" type="System.Diagnostics.TextWriterTraceListener" initializeData="asrs.log.txt" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Interrupciones de la conexión de cliente

Cuando el cliente está conectado a Azure SignalR, la conexión persistente entre el cliente y Azure SignalR a veces puede interrumpirse por distintas razones. En esta sección se describen varias causas posibles de esta interrupción de la conexión y se proporcionan instrucciones sobre cómo identificar la causa principal.

Posibles errores detectados en el lado del cliente

  • The remote party closed the WebSocket connection without completing the close handshake
  • Service timeout. 30000.00ms elapsed without receiving a message from service.
  • {"type":7,"error":"Connection closed with an error."}
  • {"type":7,"error":"Internal server error."}

Causa principal

Las conexiones de cliente pueden interrumpirse en varias circunstancias:

  • Cuando Hub produce excepciones con la solicitud entrante
  • Cuando la conexión del servidor, a la que se enruta el cliente, se quita, vea la sección siguiente para obtener más información sobre Interrupción de la conexión del servidor
  • Cuando se produce un problema de conectividad de red entre el cliente y SignalR Service
  • Cuando SignalR Service tiene algunos errores internos, como el reinicio de la instancia, la conmutación por error, la implementación, etc.

Guía de solución de problemas

  1. Abra el registro del lado servidor de la aplicación para ver si se ha producido alguna anomalía.
  2. Compruebe el registro de eventos del servidor de aplicaciones para ver si se ha reiniciado el servidor de aplicaciones.
  3. Cree un problema para nosotros en el que debe indicar el plazo de tiempo y envíenos el nombre del recurso por correo electrónico.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Aumento constante de la conexión de cliente

El uso incorrecto de la conexión de cliente puede provocarlo. Si alguien olvida detener o eliminar el cliente de SignalR, la conexión permanece abierta.

Posibles errores detectados en las métricas de SignalR que se encuentran en la sección Supervisión del menú de recursos de Azure Portal

Las conexiones de cliente aumentan constantemente durante mucho tiempo en las métricas de Azure SignalR.

Aumento constante de la conexión de cliente

Causa principal

La conexión del cliente de SignalR DisposeAsync nunca se llamará y la conexión se mantiene abierta.

Guía de solución de problemas

Compruebe si el cliente de SignalR nunca se cierra.

Solución

Compruebe si se cierra la conexión. Llame a HubConnection.DisposeAsync() manualmente para detener la conexión después de usarla.

Por ejemplo:

var connection = new HubConnectionBuilder()
	.WithUrl(...)
	.Build();
try
{
	await connection.StartAsync();
	// Do your stuff
	await connection.StopAsync();
}
finally
{
	await connection.DisposeAsync();
}

Uso inadecuado común de la conexión de cliente

Ejemplo de función de Azure

Este problema suele producirse cuando alguien establece una conexión de cliente de SignalR en un método de función de Azure en lugar de convertirlo en un miembro estático de la clase de función. Es posible que solo se establezca una conexión de cliente, pero en su lugar verá que el recuento de conexiones de cliente aumenta constantemente en las métricas. Todas estas conexiones se anulan solo después de que se reinicie Función de Azure o el servicio Azure SignalR. Este comportamiento se produce porque la función de Azure establece una conexión de cliente para cada solicitud y, si no detiene la conexión de cliente en el método de función, el cliente mantiene activas las conexiones al servicio Azure SignalR.

Solución

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Interrupción de la conexión del servidor

Cuando se inicia el servidor de aplicaciones, en segundo plano, el SDK de Azure empieza a iniciar conexiones del servidor con la instancia remota de Azure SignalR. Como se describe en el artículo sobre el funcionamiento interno de Azure SignalR Service, Azure SignalR enruta el tráfico de cliente entrante a estas conexiones de servidor. Cuando se quita una conexión de servidor, cierra todas las conexiones de cliente que estaba atendiendo.

A medida que las conexiones entre el servidor de aplicaciones y SignalR Service son conexiones persistentes, pueden experimentar problemas de conectividad de red. En el SDK del servidor, tenemos una estrategia de volver a conectar siempre a las conexiones del servidor. Como procedimiento recomendado, también se recomienda a los usuarios que agreguen lógica de reconexión continua a los clientes con un tiempo de retraso aleatorio para evitar solicitudes masivas simultáneas al servidor.

Se publican nuevas versiones de Azure SignalR Service con regularidad y, a veces, se aplican revisiones o actualizaciones en todo Azure o se produce una interrupción ocasional de los servicios dependientes. Estos eventos pueden provocar un breve período de interrupción del servicio, pero siempre que el lado cliente tenga un mecanismo de desconexión o reconexión, el efecto es mínimo, como cualquier conexión de desconexión causada por el lado cliente.

En esta sección se describen varias causas posibles de esta interrupción de la conexión del servidor y se proporcionan algunas instrucciones sobre cómo identificar la causa principal.

Posibles errores detectados en el lado del servidor

  • [Error]Connection "..." to the service was dropped
  • The remote party closed the WebSocket connection without completing the close handshake
  • Service timeout. 30000.00ms elapsed without receiving a message from service.

Causa principal

ASRS(Azure SignalR Service) cierra la conexión de servicio del servidor.

El uso elevado de la CPU o el colapso del grupo de subprocesos en el servidor puede provocar un tiempo de espera de ping.

Para ASP.NET SignalR, se corrigió un problema conocido en el SDK 1.6.0. Actualice el SDK a la versión más reciente.

Colapso del grupo de subprocesos

Si el servidor está colapsado, significa que no hay ningún subproceso trabajando en el procesamiento de mensajes. Todos los subprocesos no responden en un método determinado.

Normalmente, en métodos asincrónicos, asincrónicos a través de la sincronización o por Task.Result/Task.Wait() provoca este escenario.

Consulte Procedimientos recomendados para el rendimiento de ASP.NET Core.

Consulte más información sobre el colapso del grupo de subprocesos.

Detección del colapso del grupo de subprocesos

Compruebe el número de subprocesos. Si no hay picos en ese momento, siga estos pasos:

  • Si utiliza Azure App Service, compruebe el número de subprocesos en las métricas. Compruebe la agregación Max:

    Captura de pantalla del panel con el número subprocesos Max en Azure App Service.

  • Si utiliza .NET Framework, puede encontrar las métricas en el monitor de rendimiento en la máquina virtual del servidor.

  • Si usa .NET Core en un contenedor, consulte Recopilación de diagnósticos en contenedores.

También puede usar código para detectar la colapso del grupo de subprocesos:

public class ThreadPoolStarvationDetector : EventListener
{
    private const int EventIdForThreadPoolWorkerThreadAdjustmentAdjustment = 55;
    private const uint ReasonForStarvation = 6;

    private readonly ILogger<ThreadPoolStarvationDetector> _logger;

    public ThreadPoolStarvationDetector(ILogger<ThreadPoolStarvationDetector> logger)
    {
        _logger = logger;
    }

    protected override void OnEventSourceCreated(EventSource eventSource)
    {
        if (eventSource.Name == "Microsoft-Windows-DotNETRuntime")
        {
            EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All);
        }
    }

    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        // See: https://learn.microsoft.com/dotnet/framework/performance/thread-pool-etw-events#threadpoolworkerthreadadjustmentadjustment
        if (eventData.EventId == EventIdForThreadPoolWorkerThreadAdjustmentAdjustment &&
            eventData.Payload[2] as uint? == ReasonForStarvation)
        {
            _logger.LogWarning("Thread pool starvation detected!");
        }
    }
}

Agréguelo a su servicio:

service.AddSingleton<ThreadPoolStarvationDetector>();

A continuación, compruebe el registro cuando el servidor se desconectó debido al tiempo de espera de ping.

Búsqueda de la causa principal del colapso del grupo de subprocesos

Para encontrar la causa principal del colapso del grupo de subprocesos:

  • Vuelque la memoria y analice la pila de llamadas. Para más información, consulte Recopilación y análisis del volcado de memoria.
  • Use clrmd para volcar la memoria cuando se detecta un colapso del grupo de subprocesos. A continuación, registre la pila de llamadas.

Guía de solución de problemas

  1. Abra el registro del lado del servidor de la aplicación para ver si se ha producido alguna anomalía.
  2. Compruebe el registro de eventos del lado del servidor de aplicaciones para ver si el servidor de aplicaciones se ha reiniciado.
  3. Cree una incidencia, indique el período de tiempo y envíenos el nombre del recurso por correo electrónico.

¿Tiene problemas o comentarios sobre la solución de problemas? Cuéntenoslo.

Sugerencias

¿Cómo se puede ver la solicitud saliente del cliente?

Considere ASP.NET Core como ejemplo (ASP.NET es similar):

  • Desde el explorador: tomando Chrome como ejemplo, puede usar F12 para abrir la ventana de la consola y cambiar a la pestaña Red. Es posible que tenga que actualizar la página usando F5 para capturar la red desde el mismo principio.

    Red en la vista de Chrome

  • Desde el cliente de C#:

    Puede ver el tráfico web local con Fiddler. El tráfico de WebSocket es compatible a partir de Fiddler 4.5.

    Red en la vista de Fiddler

¿Cómo se reinicia la conexión de cliente?

Estos son los códigos de ejemplo que contienen la lógica de reinicio de la conexión con la estrategia ALWAYS RETRY:

¿Tiene problemas o comentarios sobre la solución de problemas? Háganoslo saber.

Pasos siguientes

En esta guía ha aprendido sobre cómo controlar los problemas comunes. También puede aprender otros métodos de solución de problemas genéricos.