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

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

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

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

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

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

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

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

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

Решение

По умолчанию утверждения context.User.Claims включаются при создании маркера доступа JWT к ASRS(Azure S ignalRService), чтобы утверждения сохранялись и могут передаваться из ASRSHubв то время, когда клиент подключается к нему.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 и отлаживайте сервер приложений локально, чтобы определить, какое исключение возникает.

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

      Uncheck Just My Code

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

      Throw CLR exceptions

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

      Exception throws

  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 Bad Request returned for client requests (Возврат ошибки с кодом 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 происходит сбой, клиент прерывает /ping подключение и никогда не будет повторно подключаться. Для ASP.NET SignalR время существования маркера по умолчанию длится не более одного часа для всех типов транспорта.

Решение

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

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

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

404 returned for client requests (Возврат ошибки с кодом 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, доступных в разделе мониторинга в меню ресурсов портала Microsoft Azure

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

Client connection increasing constantly

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

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

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

Проверьте, возможно, клиент 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 SignalR или функции 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 до новейшей доступной версии.

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

Если на сервере возникла нехватка потоков, то потоки не смогут производить обработку сообщений. Все потоки не отвечают в определенном методе.

Обычно эта ситуация возникает при применении асинхронных обращений к синхронным вызовам ("async over sync") или при использовании Task.Result/Task.Wait() в асинхронных методах.

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

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

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

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

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

    Screenshot of the Max thread count pane in Azure App Service.

  • Если используется платформа .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 View Network

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

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

    Fiddler View Network

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

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

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

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

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