SignalR 1.x의 규모 확장 소개

작성자 : Patrick Fletcher

경고

이 설명서는 최신 버전의 SignalR용이 아닙니다. ASP.NET Core SignalR을 살펴보세요.

일반적으로 웹 애플리케이션을 확장하는 방법에는 스케일 업스케일 아웃이라는 두 가지 방법이 있습니다.

  • 스케일 업은 더 많은 RAM, CPU 등으로 더 큰 서버(또는 더 큰 VM)를 사용하는 것을 의미합니다.
  • 스케일 아웃은 부하를 처리하기 위해 더 많은 서버를 추가하는 것을 의미합니다.

스케일 업의 문제는 컴퓨터 크기에 대한 제한에 빠르게 도달했다는 것입니다. 그 외에도 규모를 확장해야 합니다. 그러나 스케일 아웃하면 클라이언트가 다른 서버로 라우팅됩니다. 한 서버에 연결된 클라이언트는 다른 서버에서 보낸 메시지를 받지 않습니다.

서버가 확장될 때 클라이언트가 직면하는 문제의 스크린샷은 서버가 한 서버에 연결되어 있기 때문에 다른 서버에서 보낸 메시지를 받지 않는다는 것입니다.

한 가지 해결 방법은 백플레인이라는 구성 요소를 사용하여 서버 간에 메시지를 전달하는 것입니다. 백플레인을 사용하도록 설정하면 각 애플리케이션 instance 백플레인에 메시지를 보내고 백플레인은 메시지를 다른 애플리케이션 인스턴스로 전달합니다. (전자에서 백플레인은 병렬 커넥터 그룹입니다. 이와 유사하게 SignalR 백플레인은 여러 서버를 연결합니다.)

백플레인이라는 구성 요소를 사용하여 서버 간에 메시지를 전달하는 솔루션의 스크린샷

SignalR은 현재 세 개의 백플레인을 제공합니다.

  • Azure Service Bus. Service Bus는 구성 요소가 느슨하게 결합된 방식으로 메시지를 보낼 수 있는 메시징 인프라입니다.
  • Redis. Redis는 메모리 내 키-값 저장소입니다. Redis는 메시지를 보내기 위한 게시/구독("pub/sub") 패턴을 지원합니다.
  • SQL Server. SQL Server 백플레인은 SQL 테이블에 메시지를 씁니다. 백플레인은 효율적인 메시징을 위해 Service Broker를 사용합니다. 그러나 Service Broker를 사용하도록 설정하지 않은 경우에도 작동합니다.

Azure에 애플리케이션을 배포하는 경우 Azure Service Bus 백플레인을 사용하는 것이 좋습니다. 자체 서버 팜에 배포하는 경우 SQL Server 또는 Redis 백플레인을 고려합니다.

다음 topics 각 백플레인에 대한 단계별 자습서를 포함합니다.

구현

SignalR에서 모든 메시지는 메시지 버스를 통해 전송됩니다. 메시지 버스는 게시/구독 추상화 기능을 제공하는 IMessageBus 인터페이스를 구현합니다. 백플레인은 기본 IMessageBus를 해당 백플레인용으로 설계된 버스로 바꾸어 작동합니다. 예를 들어 Redis의 메시지 버스는 RedisMessageBus이며 Redis pub/sub 메커니즘을 사용하여 메시지를 보내고 받습니다.

각 서버 instance 버스를 통해 백플레인에 연결됩니다. 메시지가 전송되면 백플레인으로 이동하고 백플레인은 모든 서버로 보냅니다. 서버가 백플레인에서 메시지를 가져오면 로컬 캐시에 메시지를 넣습니다. 그런 다음 서버는 로컬 캐시에서 클라이언트에 메시지를 배달합니다.

각 클라이언트 연결에 대해 메시지 스트림을 읽는 클라이언트의 진행률은 커서를 사용하여 추적됩니다. (커서는 메시지 스트림의 위치를 나타냅니다.) 클라이언트가 연결을 끊은 다음 다시 연결하면 버스에 클라이언트의 커서 값 이후에 도착한 모든 메시지를 요청합니다. 연결에서 긴 폴링을 사용할 때도 마찬가지입니다. 긴 폴링 요청이 완료되면 클라이언트는 새 연결을 열고 커서 뒤에 도착한 메시지를 요청합니다.

커서 메커니즘은 클라이언트가 다시 연결할 때 다른 서버로 라우팅되는 경우에도 작동합니다. 백플레인은 모든 서버를 알고 있으며 클라이언트가 연결하는 서버는 중요하지 않습니다.

제한 사항

백플레인을 사용하면 클라이언트가 단일 서버 노드와 직접 통신할 때보다 최대 메시지 처리량이 낮습니다. 백플레인은 모든 메시지를 모든 노드에 전달하므로 백플레인은 병목 상태가 될 수 있기 때문입니다. 이 제한 사항이 문제인지 여부는 애플리케이션에 따라 달라집니다. 예를 들어 몇 가지 일반적인 SignalR 시나리오는 다음과 같습니다.

  • 서버 브로드캐스트 (예: 주식 시세): 백플레인은 이 시나리오에서 잘 작동합니다. 서버가 메시지를 보내는 속도를 제어하기 때문입니다.
  • 클라이언트 간 (예: 채팅): 이 시나리오에서는 메시지 수가 클라이언트 수와 함께 스케일링되면 백플레인에 병목 현상이 발생할 수 있습니다. 즉, 더 많은 클라이언트가 조인할 때 메시지 속도가 비례적으로 증가하는 경우 입니다.
  • 고주파 실시간 (예: 실시간 게임): 이 시나리오에는 백플레인을 사용하지 않는 것이 좋습니다.

SignalR Scaleout에 대해 추적 사용

백플레인에 대한 추적을 사용하도록 설정하려면 루트 구성 요소 아래의 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>