Бөлісу құралы:


Масштабирование Служба SignalR с несколькими экземплярами

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

Для ASP.NET Core

Добавление нескольких конечных точек из конфигурации

Настройте ключ Azure:SignalR:ConnectionString или Azure:SignalR:ConnectionString: для Служба SignalR строка подключения.

Если ключ начинается с Azure:SignalR:ConnectionString:, он должен находиться в формате Azure:SignalR:ConnectionString:{Name}:{EndpointType}, где Name и EndpointType являются свойствами ServiceEndpoint объекта и доступны из кода.

С помощью следующих команд dotnet можно добавить несколько строк подключения экземпляра.

dotnet user-secrets set Azure:SignalR:ConnectionString:east-region-a <ConnectionString1>
dotnet user-secrets set Azure:SignalR:ConnectionString:east-region-b:primary <ConnectionString2>
dotnet user-secrets set Azure:SignalR:ConnectionString:backup:secondary <ConnectionString3>

Добавление нескольких конечных точек из кода

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

services.AddSignalR()
        .AddAzureSignalR(options => 
        {
            options.Endpoints = new ServiceEndpoint[]
            {
                // Note: this is just a demonstration of how to set options.Endpoints
                // Having ConnectionStrings explicitly set inside the code is not encouraged
                // You can fetch it from a safe place such as Azure KeyVault
                new ServiceEndpoint("<ConnectionString0>"),
                new ServiceEndpoint("<ConnectionString1>", type: EndpointType.Primary, name: "east-region-a"),
                new ServiceEndpoint("<ConnectionString2>", type: EndpointType.Primary, name: "east-region-b"),
                new ServiceEndpoint("<ConnectionString3>", type: EndpointType.Secondary, name: "backup"),
            };
        });

Настройка маршрутизатора конечной точки

По умолчанию пакет SDK использует DefaultEndpointRouter для выбора конечных точек.

Поведение по умолчанию

  1. Маршрутизация запросов клиента:

    Когда клиент /negotiate с сервером приложений. По умолчанию пакет SDK случайным образом выбирает одну конечную точку из набора доступных конечных точек службы.

  2. Маршрутизация сообщений сервера:

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

Настройка алгоритма маршрутизации

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

В следующем примере определяется пользовательский маршрутизатор, который направляет сообщения с группой, начиная с east- конечной точки с именем east:

private class CustomRouter : EndpointRouterDecorator
{
    public override IEnumerable<ServiceEndpoint> GetEndpointsForGroup(string groupName, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the group broadcast behavior, if the group name starts with "east-", only send messages to endpoints inside east
        if (groupName.StartsWith("east-"))
        {
            return endpoints.Where(e => e.Name.StartsWith("east-"));
        }

        return base.GetEndpointsForGroup(groupName, endpoints);
    }
}

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

private class CustomRouter : EndpointRouterDecorator
{    public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the negotiate behavior to get the endpoint from query string
        var endpointName = context.Request.Query["endpoint"];
        if (endpointName.Count == 0)
        {
            context.Response.StatusCode = 400;
            var response = Encoding.UTF8.GetBytes("Invalid request");
            context.Response.Body.Write(response, 0, response.Length);
            return null;
        }

        return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

Обязательно зарегистрируйте маршрутизатор в контейнере DI с помощью следующего.

services.AddSingleton(typeof(IEndpointRouter), typeof(CustomRouter));
services.AddSignalR()
        .AddAzureSignalR(
            options => 
            {
                options.Endpoints = new ServiceEndpoint[]
                {
                    new ServiceEndpoint(name: "east", connectionString: "<connectionString1>"),
                    new ServiceEndpoint(name: "west", connectionString: "<connectionString2>"),
                    new ServiceEndpoint("<connectionString3>")
                };
            });

Для ASP.NET

Добавление нескольких конечных точек из конфигурации

Конфигурация с ключом Azure:SignalR:ConnectionString или Azure:SignalR:ConnectionString: для Служба SignalR строка подключения.

Если ключ начинается с Azure:SignalR:ConnectionString:, он должен иметь формат Azure:SignalR:ConnectionString:{Name}:{EndpointType}, где Name и EndpointType являются свойствами объекта ServiceEndpoint и доступны из кода.

В web.config можно добавить несколько строк подключения к экземпляру.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="Azure:SignalR:ConnectionString" connectionString="<ConnectionString1>"/>
    <add name="Azure:SignalR:ConnectionString:en-us" connectionString="<ConnectionString2>"/>
    <add name="Azure:SignalR:ConnectionString:zh-cn:secondary" connectionString="<ConnectionString3>"/>
    <add name="Azure:SignalR:ConnectionString:Backup:secondary" connectionString="<ConnectionString4>"/>
  </connectionStrings>
  ...
</configuration>

Добавление нескольких конечных точек из кода

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

app.MapAzureSignalR(
    this.GetType().FullName, 
    options => {
            options.Endpoints = new ServiceEndpoint[]
            {
                // Note: this is just a demonstration of how to set options. Endpoints
                // Having ConnectionStrings explicitly set inside the code is not encouraged.
                // You can fetch it from a safe place such as Azure KeyVault
                new ServiceEndpoint("<ConnectionString1>"),
                new ServiceEndpoint("<ConnectionString2>"),
                new ServiceEndpoint("<ConnectionString3>"),
            }
        });

Настройка маршрутизатора

Единственное различие между ASP.NET SignalR и ASP.NET Core SignalR — это тип контекста HTTP для GetNegotiateEndpoint. Для ASP.NET SignalR его тип IOwinContext.

Следующий код — это пользовательский пример согласования для ASP.NET SignalR:

private class CustomRouter : EndpointRouterDecorator
{
    public override ServiceEndpoint GetNegotiateEndpoint(IOwinContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the negotiate behavior to get the endpoint from query string
        var endpointName = context.Request.Query["endpoint"];
        if (string.IsNullOrEmpty(endpointName))
        {
            context.Response.StatusCode = 400;
            context.Response.Write("Invalid request.");
            return null;
        }

        return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

Обязательно зарегистрируйте маршрутизатор в контейнере DI с помощью следующего.

var hub = new HubConfiguration();
var router = new CustomRouter();
hub.Resolver.Register(typeof(IEndpointRouter), () => router);
app.MapAzureSignalR(GetType().FullName, hub, options => {
    options.Endpoints = new ServiceEndpoint[]
                {
                    new ServiceEndpoint(name: "east", connectionString: "<connectionString1>"),
                    new ServiceEndpoint(name: "west", connectionString: "<connectionString2>"),
                    new ServiceEndpoint("<connectionString3>")
                };
});

Метрики конечных точек службы

Чтобы включить расширенный маршрутизатор, пакет SDK сервера SignalR предоставляет несколько метрик, помогая серверу принимать интеллектуальные решения. Свойства находятся в разделе ServiceEndpoint.EndpointMetrics.

Имя метрики Description
ClientConnectionCount Общее количество одновременных клиентских подключений ко всем центрам для конечной точки службы
ServerConnectionCount Общее количество одновременных подключений к серверу во всех центрах для конечной точки службы
ConnectionCapacity Общая квота подключения для конечной точки службы, включая подключения клиента и сервера

Следующий код является примером настройки маршрутизатора в соответствии с ClientConnectionCount.

private class CustomRouter : EndpointRouterDecorator
{
    public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        return endpoints.OrderBy(x => x.EndpointMetrics.ClientConnectionCount).FirstOrDefault(x => x.Online) // Get the available endpoint with minimal clients load
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

Динамические масштабируемые службыEndpoints

В пакете SDK версии 1.5.0 сначала мы включаем динамические масштабируемые службы ServiceEndpoints для ASP.NET core версии. Поэтому вам не нужно перезапустить сервер приложений, если необходимо добавить или удалить ServiceEndpoint. Так как ASP.NET Core поддерживает конфигурацию по умолчанию, как appsettings.json и с reloadOnChange: true, вам не нужно изменять код, и она поддерживается по природе. Если вы хотите добавить настраиваемую конфигурацию и работать с горячей перезагрузкой, см. раздел "Конфигурация" в ASP.NET Core.

Примечание.

Учитывая, что время настройки подключения между сервером или службой и клиентом или службой может отличаться, чтобы не было потери сообщений во время процесса масштабирования, у нас есть промежуточный период ожидания готовности подключений к серверу перед открытием нового ServiceEndpoint для клиентов. Обычно требуется несколько секунд, и вы сможете увидеть сообщение журнала, например Succeed in adding endpoint: '{endpoint}' , которое указывает на завершение процесса.

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

Период времени ожидания по умолчанию для шкалы составляет 5 минут, и его можно настроить, изменив значение в ServiceOptions.ServiceScaleTimeout. Если у вас много серверов приложений, рекомендуется расширить значение немного больше.

Настройка в сценариях с разными регионами

Объект ServiceEndpoint имеет свойство EndpointType со значением primary или secondary.

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

В разных случаях сеть может быть нестабильной. Для сервера приложений, расположенного в восточной части США, Служба SignalR конечная точка, расположенная в том же регионе Восточная часть США, и primary конечные точки в других регионах, помеченные как secondary. В этой конфигурации конечные точки службы в других регионах могут получать сообщения от этого сервера приложений восточной части США , но на этот сервер приложений не направляются клиенты между регионами . На следующей схеме представлена архитектура:

Перекрестная географическая инфраструктура

При попытке /negotiate клиента с сервером приложений с маршрутизатором по умолчанию пакет SDK случайным образом выбирает одну конечную точку из набора доступных primary конечных точек. Если основная конечная точка недоступна, пакет SDK выбирается случайным образом из всех доступных secondary конечных точек. Конечная точка помечается как доступная, если подключение между сервером и конечной точкой службы активно.

В сценарии между регионами, когда клиент пытается /negotiate использовать сервер приложения, размещенный в восточной части США, по умолчанию всегда возвращает primary конечную точку, расположенную в одном регионе. Если все конечные точки восточной части США недоступны, маршрутизатор перенаправляет клиента на конечные точки в других регионах. В следующем разделе отработки отказа подробно описан сценарий.

Нормальное согласование

Отработка отказа

Если конечная точка недоступна primary , клиент /negotiate выбирает из доступных secondary конечных точек. Этот механизм отработки отказа требует, чтобы каждая конечная точка служила в качестве конечной primary точки по крайней мере одному серверу приложений.

Схема, показывающая процесс механизма отработки отказа.

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

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