Общие сведения о масштабировании в SignalR 1.x

Патрик Флетчер

Предупреждение

Эта документация не для последней версии SignalR. Взгляните на ASP.NET Core SignalR.

Как правило, существует два способа масштабирования веб-приложения: вертикальное и горизонтальное масштабирование.

  • Увеличение масштаба означает использование сервера большего размера (или более крупной виртуальной машины) с большим объемом ОЗУ, ЦП и т. д.
  • Горизонтальное масштабирование означает добавление дополнительных серверов для обработки нагрузки.

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

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

Одним из решений является перенаправление сообщений между серверами с помощью компонента, называемого объединителе. При включенной внутренней плоскости каждый экземпляр приложения отправляет сообщения в объединителю, а обратная планка перенаправит их другим экземплярам приложения. (В электронике задняя плоскость представляет собой группу параллельных соединителей. По аналогии с обратной панелью SignalR подключается несколько серверов.)

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

В настоящее время SignalR предоставляет три объединители:

  • Служебная шина Azure. Служебная шина — это инфраструктура обмена сообщениями, которая позволяет компонентам отправлять сообщения слабо связанным способом.
  • Редис. Redis — это хранилище ключей и значений в памяти. Redis поддерживает шаблон публикации и подписки ("публикация/подписка") для отправки сообщений.
  • SQL Server. Серверная панель SQL Server записывает сообщения в таблицы SQL. В объединителе используется компонент Service Broker для эффективного обмена сообщениями. Однако он также работает, если компонент Service Broker не включен.

Если вы развертываете приложение в Azure, рассмотрите возможность использования Служебная шина Azure серверной панели. Если вы выполняете развертывание в собственной ферме серверов, рассмотрите SQL Server или объединитее платы Redis.

В следующих разделах содержатся пошаговые руководства по каждой внутренней панели.

Реализация

В SignalR каждое сообщение отправляется через шину сообщений. Шина сообщений реализует интерфейс IMessageBus , который предоставляет абстракцию публикации и подписки. Задние планки работают путем замены IMessageBus по умолчанию шиной, предназначенной для этой задней панели. Например, шиной сообщений для Redis является RedisMessageBus, и она использует механизм публикации и подписки Redis для отправки и получения сообщений.

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

Для каждого клиентского подключения ход чтения потока сообщений отслеживается с помощью курсора. (Курсор представляет позицию в потоке сообщений.) Если клиент отключается, а затем повторно подключается, он запрашивает у шины все сообщения, полученные после значения курсора клиента. То же самое происходит, когда соединение использует длительный опрос. После завершения длинного запроса на опрос клиент открывает новое подключение и запрашивает сообщения, полученные после курсора.

Механизм курсора работает, даже если при повторном подключении клиент направляется на другой сервер. Объединителе известно обо всех серверах, и не имеет значения, к какому серверу подключается клиент.

Ограничения

При использовании объединитерной платы максимальная пропускная способность сообщений ниже, чем при прямом подключении клиентов к одному узлу сервера. Это связано с тем, что объединительная панель перенаправит каждое сообщение на каждый узел, поэтому обратная планка может стать узким местом. Является ли это ограничение проблемой, зависит от приложения. Например, ниже приведены некоторые типичные сценарии SignalR:

  • Широковещательное вещание сервера (например, stock ticker) — в этом сценарии хорошо работают серверные панели, так как сервер управляет скоростью отправки сообщений.
  • Взаимодействие между клиентами (например, чат). В этом сценарии объединительная панель может быть узким местом, если количество сообщений масштабируется вместе с количеством клиентов; то есть, если скорость сообщений увеличивается пропорционально по мере присоединения большего числа клиентов.
  • Высокочастотный режим реального времени (например, игры в режиме реального времени). В этом сценарии не рекомендуется использовать обратную планку.

Включение трассировки для масштабирования Signalr

Чтобы включить трассировку для внутренних планов, добавьте следующие разделы в файл web.config в корневом элементе конфигурации :

<configuration>
  <system.diagnostics>
    <sources>
      <source name="SignalR.SqlMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
      <source name="SignalR.ServiceBusMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
      <source name="SignalR.ScaleoutMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="SignalRSwitch" value="Verbose" />
      <!-- Off, Critical, Error, Warning, Information, Verbose -->
    </switches>
    <sharedListeners>
      <add name="SignalR-Bus" 
          type="System.Diagnostics.TextWriterTraceListener" 
          initializeData="bus.log.txt" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
  . . .
</configuration>