Поделиться через


Руководство по устранению типичных неполадок для службы Azure SignalR

В этой статье приводятся рекомендации по устранению неполадок, связанных с некоторыми распространенными проблемами, с которыми могут столкнуться клиенты.

Слишком длинный маркер доступа

Возможные ошибки

  • ERR_CONNECTION_ на стороне клиента
  • 414 — слишком длинный универсальный код ресурса (URI)
  • 413 Размер данных слишком велик
  • Длина токена доступа не должна превышать 4КБ. 413 — размер запрашиваемой сущности слишком большой

Основная причина

Для HTTP/2 максимальная длина одного заголовка составляет 4 K, поэтому при использовании браузера для доступа к службе Azure возникает ошибка ERR_CONNECTION_ для этого ограничения.

Для клиентов HTTP/1.1 или C# максимальная длина URI составляет 12 K , а максимальная длина заголовка составляет 16 K.

При использовании пакета SDK версии 1.0.6 или более поздней /negotiate, возникает 413 Payload Too Large, если размер созданного токена доступа превышает 4 K.

Решение

По умолчанию утверждения из context.User.Claims включаются при создании маркера JWT доступа к ASRS(службе Azure SignalRService), чтобы они сохранялись и могли передаваться из ASRS в Hub при подключении клиента к Hub.

В некоторых случаях context.User.Claims используются для хранения большого количества сведений для сервера приложений, большинство из которых не используются Hubдругими компонентами.

Созданный маркер доступа передается по сети, и для подключений WebSocket/SSE маркеры доступа передаются через строки запросов. Поэтому рекомендуется передавать лишь необходимые утверждения от клиента через службу ASRS в сервер приложений, когда это необходимо для Центра.

Возможность ClaimsProvider настроить утверждения, передаваемые внутри токена доступа в ASRS, существует.

Для ASP.NET Core:

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

Для ASP.NET:

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

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Требуется TLS 1.2

Возможные ошибки

  • Ошибка ASP.NET "No server available" (Нет доступных серверов) #279
  • ASP.NET "Подключение не активно, данные не могут быть отправлены в службу". Ошибка #324
  • "An error occurred while making the HTTP request to https://<API endpoint> ("Произошла ошибка при выполнении HTTP-запроса к"). Эта ошибка может возникать, если сертификат сервера не настроен должным образом с HTTP.SYS в случае HTTPS. Возможная причина этой ошибки заключается в несоответствии привязки безопасности между клиентом и сервером".

Основная причина

Служба Azure из соображений безопасности поддерживает только TLS версии 1.2. В .NET Framework возможно, что TLS1.2 не является протоколом по умолчанию. В результате невозможно установить подключения сервера к ASRS.

Руководство по устранению неполадок

  1. Если эту ошибку можно воспроизвести локально, снимите флажок Только мой код, включите выдачу всех исключений CLR и отлаживайте сервер приложений локально, чтобы определить, какое исключение возникает.

    • Снимите флажок Только мой код

      Снимите флажок

    • Выдача исключений CLR

      Выдача исключений CLR

    • Просмотрите порождаемые исключения во время отладки кода серверной части приложения:

      Генерация исключений

  2. Для приложений ASP.NET также можно добавить следующий код в Startup.cs, чтобы включить подробную трассировку и просмотреть ошибки в журнале.

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

Решение

Добавьте в запуск следующий код:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Возвращен код ошибки 400 (Недопустимый запрос) для клиентских запросов.

Основная причина

Проверьте, нет ли в запросе клиента нескольких строк hub. Параметр hub запроса сохраняется, и если служба обнаруживает несколько hub в запросе, она возвращает ошибку 400.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

401 Unauthorized returned for client requests (Возврат ошибки с кодом "401 — не санкционировано" для клиентских запросов)

Основная причина

В настоящее время значение по умолчанию времени существования JWT составляет один (1) час.

Для ASP.NET Core SignalR при использовании типа транспорта WebSocket это нормально.

Для другого типа транспорта в ASP.NET Core SignalR, таких как SSE и длинный опрос, по умолчанию соединение может сохраняться не более одного часа.

Для ASP.NET SignalR клиент время от времени отправляет в службу запрос на поддержание соединения; когда /ping дает сбой, клиент прерывает соединение и больше не подключается. Для ASP.NET SignalR время существования токена по умолчанию позволяет соединению длиться не более одного часа для всех типов транспорта.

Решение

Для проблем безопасности расширение срока жизни не рекомендуется. Мы рекомендуем добавить в клиент логику повторного подключения, чтобы при получении такой ошибки 401 он возобновлял подключение. Когда клиент перезагружает подключение, он ведет переговоры с сервером приложений, чтобы снова получить JWT и обновленный токен.

Ознакомьтесь с этим разделом, чтобы узнать, как устанавливать заново клиентские подключения.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Возвращен код 404 для клиентских запросов

При постоянных подключениях к SignalR сначала выполняется /negotiate для службы Azure SignalR, а затем устанавливается реальное подключение к службе Azure SignalR.

Руководство по устранению неполадок

  • Выполните указания из раздела Как просмотреть исходящие запросы, чтобы получить запрос, отправляемый клиентом в службу.
  • Проверьте URL-адрес запроса, при котором возникает ошибка 404. Если URL-адрес направлен на ваше веб-приложение и похож на {your_web_app}/hubs/{hubName}, проверьте, установлен ли у клиента флаг SkipNegotiation как true. Клиент получает URL-адрес перенаправления при первом согласовании с сервером приложений. Клиент должен не пропускать переговоры при использовании Azure SignalR.
  • Еще один случай 404 может произойти, когда запрос на подключение обрабатывается более чем через пять (5) секунд после вызова /negotiate. Проверьте метку времени в запросе клиента и, если служба реагирует слишком медленно, сообщите о проблеме в нашу службу поддержки.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

В ASP.NET при запросе повторного подключения к SignalR возвращается ошибка 404

В SignalR для ASP.NET при разрыве клиентского подключения оно трижды восстанавливается с использованием того же connectionId, прежде чем попытки восстановления подключения прекращаются. /reconnect может помочь, если подключение нарушается из-за временных проблем в сети, при которых /reconnect все же может повторно установить стабильно работающее подключение. В других случаях, например, когда подключение клиента сбрасывается из-за сбоя соединения с маршрутизированным сервером, или когда в Службе SignalR возникают внутренние ошибки, такие как перезапуск экземпляра, отработка отказа или развертывание. Подключение больше не существует, поэтому /reconnect возвращается 404. Это ожидаемое поведение для /reconnect, и после трех попыток повторного подключения соединение прекращается. Рекомендуем реализовать логику перезапуска подключения для случаев прекращения подключений.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Возврат ошибки с кодом 429 (Слишком много запросов) для клиентских запросов

Есть два случая.

Количество одновременных подключений превысило максимальное

Для бесплатных экземпляров ограничение на количество одновременных подключений равно 20. Для стандартных экземпляров предел количества одновременных подключений составляет 1000 на единицу (unit), то есть Unit100 допускает 100 000 одновременных подключений.

Подключения включают как клиентские, так и серверные подключения. Ознакомьтесь со сведениями о том, как учитываются подключения.

Дросселирование переговоров

Когда слишком много клиентов одновременно обрабатывают запросы, их обработка может быть ограничена. Это ограничение относится к количеству единиц, для которых большее количество имеет более высокий предел. Кроме того, мы рекомендуем иметь случайную задержку перед повторной подключением, проверьте здесь примеры повторных попыток.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Ошибка 500 при согласовании: служба Azure SignalR еще не подключена, повторите попытку позже

Основная причина

Эта ошибка возникает, когда нет подключения сервера к службе Azure SignalR.

Руководство по устранению неполадок

Включите трассировку на стороне сервера, чтобы получить подробные сведения об ошибке, возникающей при попытке сервера подключиться к службе Azure SignalR.

Включение ведения журналов на стороне сервера для ASP.NET Core SignalR

Ведение журналов на стороне сервера для ASP.NET Core SignalR интегрируется с ILogger на основе , реализованным в платформе ASP.NET Core. Включить ведение журналов на стороне сервера можно с помощью ConfigureLogging, как показано в примере ниже:

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

Категории журналов для Azure SignalR всегда начинаются с Microsoft.Azure.SignalR. Чтобы включить подробные журналы из Azure SignalR, настройте указанные префиксы на уровень Debug в файле appsettings.json, как показано в следующем примере.

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

Включение трассировки на стороне сервера для ASP.NET SignalR

При использовании версии SDK >= 1.0.0 можно включить трассировки, добавив следующее в web.config: (Сведения)

<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>

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Клиентское подключение прерывается

Когда клиент подключен к службе Azure SignalR, постоянное подключение между клиентом и службой Azure SignalR в некоторых случаях может разрываться по ряду причин. В этом разделе описывается несколько возможных ситуаций, ведущих к такому разрыву подключений, а также приводятся указания по выявлению их первопричины.

Возможные ошибки, отображаемые на стороне клиента

  • 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."}

Основная причина

Клиентские подключения могут разрываться в различных ситуациях:

  • Когда Hub вызывает исключения с входящим запросом
  • Когда подключение к серверу, к которому направляется клиент, удаляется, см. в следующем разделе, где подробно описано удаление подключения к серверу.
  • При возникновении проблемы с сетевым подключением между клиентом и службой SignalR
  • Когда в Службе SignalR возникают внутренние ошибки, такие как перезапуск экземпляра, отказоустойчивость, развертывание и т. д.

Руководство по устранению неполадок

  1. Откройте журнал на стороне сервера приложений, чтобы проверить, не происходит ли что-то непредвиденное.
  2. Просмотрите журнал событий на стороне сервера приложений и проверьте, не перезапускался ли сервер приложений.
  3. Создайте задачу, укажите временные рамки и отправьте нам имя ресурса по электронной почте.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Количество клиентских подключений постоянно растет

Неправильное использование клиентского подключения может вызвать его. Если кто-то забывает остановить или закрыть клиент SignalR, соединение остается открытым.

Ошибки, которые можно увидеть в метриках SignalR в разделе "Мониторинг" меню ресурсов портала Azure.

Число клиентских подключений в метриках службы Azure SignalR постоянно возрастает в течение длительного времени.

Количество клиентских подключений постоянно растет

Основная причина

Подключение DisposeAsync клиента SignalR никогда не вызывается, и подключение остается открытым.

Руководство по устранению неполадок

Проверьте, что клиент SignalR никогда не закрывается.

Решение

Проверьте, производится ли закрытие подключений. Вызывайте HubConnection.DisposeAsync() вручную, чтобы прекратить подключение после его использования.

Например:

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

Распространенное неправильное использование клиентских подключений

Пример функции Azure

Эта проблема часто возникает, когда кто-то устанавливает клиентское подключение SignalR в методе функции Azure, а не делает его статическим членом в классе функций. Возможно, вы ожидаете, что будет установлено только одно клиентское подключение, но вместо этого количество подключений клиента постоянно увеличивается в метриках. Все эти подключения будут удаляться только после перезапуска функции Azure или службы Azure SignalR. Это происходит из-за того, что функция Azure устанавливает одно клиентское подключение для каждого запроса и если вы не останавливаете подключение клиента в методе функции, клиент сохраняет подключения к службе Azure SignalR.

Решение

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Подключение к серверу разрывается

Когда запускается сервер приложений, пакет SDK Azure начинает в фоновом режиме инициировать серверные подключения к удаленной службе Azure SignalR. Как описано в статье Internals of Azure SignalR Service (Внутренние компоненты службы Azure SignalR), служба Azure SignalR направляет входящий клиентский трафик в эти серверные подключения. При удалении подключения к серверу он закрывает все клиентские подключения, которые он обслуживал.

Так как подключения между сервером приложений и Служба SignalR являются постоянными подключениями, они могут столкнуться с проблемами с сетевым подключением. В серверном SDK у нас есть стратегия Always Reconnect для подключений к серверу. В качестве передовой практики также рекомендуется пользователям добавлять механизм непрерывного повторного подключения в клиентские приложения с использованием случайного времени задержки, чтобы избежать массовых одновременных запросов к серверу.

Регулярно выпускаются новые версии для службы Azure SignalR, а иногда происходят исправления или обновления на уровне Azure, или случаются сбои работы зависимых служб. Эти события могут привести к короткому периоду сбоя в обслуживании, но если на стороне клиента имеется механизм отключения и повторного подключения, эффект минимален, как и любой вызванный клиентской стороной разрыв и повторное подключение.

В этом разделе описывается несколько возможных ситуаций, вызывающих разрыв серверного подключения, а также приводятся указания по выявлению их первопричины.

Возможные ошибки, отображаемые на стороне сервера

  • [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.

Основная причина

Соединение между сервером и службой закрыто службой ASRS(Azure SignalRService).

Высокая загрузка ЦП или нехватка пула потоков на стороне сервера может привести к истечении времени ожидания пинга.

В ASP.NET SignalR существовала известная проблема, которая была исправлена в версии 1.6.0 пакета SDK. Обновите используемый пакет SDK до новейшей доступной версии.

Исчерпание пула потоков

Если сервер находится в состоянии нехватки ресурсов, это значит, что ни один поток не выполняет обработку сообщений. Не все потоки отвечают в данном методе.

Как правило, в асинхронных методах асинхронное выполнение вместо синхронного или использование Task.Result/Task.Wait() приводит к этой ситуации.

См. Рекомендации по повышению производительности ASP.NET Core.

См. дополнительные сведения об исчерпании пула потоков.

Как определить исчерпание пула потоков

Проверьте количество нитей. Если пиковых количеств в текущее время не наблюдается, выполните следующие действия:

  • Если используется Служба приложений Azure, проверьте счетчик потоков в метриках. Проверьте агрегацию Max:

    Снимок экрана панели максимального количества потоков для Службы приложений Azure.

  • Если вы используете платформу .NET Framework, метрики можно найти в системном мониторе вашей виртуальной машины сервера.

  • Если применяется .NET Core в контейнере, см. статью Сбор диагностических сведений в контейнерах.

Также можно выявлять исчерпание пула потоков с помощью кода.

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

Добавьте этот код в вашу службу:

service.AddSingleton<ThreadPoolStarvationDetector>();

Затем проверьте журнал при отключении сервера из-за тайм-аута пинга.

Как определить первопричину исчерпания пула потоков

Чтобы определить первопричину исчерпания пула потоков, выполните следующие действия.

  • Создайте дамп памяти, затем проанализируйте стек вызовов. Дополнительные сведения см. в разделе Сбор и анализ дампов памяти.
  • Используйте библиотеку clrmd для создания дампа памяти при обнаружении исчерпания пула потоков. Затем выведите стек вызовов в журнал.

Руководство по устранению неполадок

  1. Откройте журнал на стороне сервера приложений, чтобы проверить, не происходит ли что-то непредвиденное.
  2. Просмотрите журнал событий на стороне сервера приложений и проверьте, не перезапускался ли сервер приложений.
  3. Создайте проблему. Укажите в обращении время появления неполадки и имя ресурса, и отправьте его нам по электронной почте.

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Советы

Как просмотреть исходящий запрос от клиента?

Например, при использовании ASP.NET Core (для ASP.NET это делается сходным образом):

  • Из браузера. При использовании, например, браузера Chrome можно с помощью клавиши F12 открыть окно консоли и перейти на вкладку Network (Сеть). Возможно, потребуется обновить страницу, нажав клавишу F5, чтобы зафиксировать обмен данными с самого начала.

    Просмотр сети в Chrome

  • Из клиента C#:

    Локальный веб-трафик можно просматривать с помощью Fiddler. Fiddler поддерживает трафик WebSocket, начиная с версии 4.5.

    Сетевой просмотр в Fiddler

Как перезапустить клиентское подключение?

Ниже приведены примеры кода, которые содержат логику перезапуска подключений со стратегией ALWAYS RETRY (всегда повторять):

Наличие проблем или отзывов об устранении неполадок? Сообщите нам об этом.

Следующие шаги

Из этого руководства вы узнали, как справляться с распространенными проблемами. Вы также можете ознакомиться с общими методиками устранения неполадок.