Introdução à expansão no SignalR

por Patrick Fletcher

Aviso

Esta documentação não é para a versão mais recente do SignalR. Dê uma olhada em ASP.NET Core SignalR.

Versões de software usadas neste tópico

Versões anteriores deste tópico

Para obter informações sobre versões anteriores do SignalR, consulte Versões mais antigas do SignalR.

Perguntas e comentários

Deixe comentários sobre como você gostou deste tutorial e o que poderíamos melhorar nos comentários na parte inferior da página. Se você tiver perguntas que não estão diretamente relacionadas ao tutorial, poderá postá-las no fórum do ASP.NET SignalR ou StackOverflow.com.

Em geral, há duas maneiras de dimensionar um aplicativo Web: escalar verticalmente e escalar horizontalmente.

  • Escalar verticalmente significa usar um servidor maior (ou uma VM maior) com mais RAM, CPUs etc.
  • Escalar horizontalmente significa adicionar mais servidores para lidar com a carga.

O problema com o dimensionamento é que você atinge rapidamente um limite no tamanho do computador. Além disso, você precisa escalar horizontalmente. No entanto, quando você escala horizontalmente, os clientes podem ser roteados para servidores diferentes. Um cliente conectado a um servidor não receberá mensagens enviadas de outro servidor.

Diagrama que mostra setas indo de Clientes para Load Balancer para servidores.

Uma solução é encaminhar mensagens entre servidores, usando um componente chamado backplane. Com um backplane habilitado, cada instância do aplicativo envia mensagens para o backplane e o backplane as encaminha para as outras instâncias do aplicativo. (Em eletrônicos, um backplane é um grupo de conectores paralelos. Por analogia, um backplane do SignalR conecta vários servidores.)

Diagrama que mostra setas indo do servidor do Aplicativo Signal R para o Backplane para o servidor do Aplicativo Signal R para computadores.

Atualmente, o SignalR fornece três backplanes:

  • Barramento de Serviço do Azure. O Barramento de Serviço é uma infraestrutura de mensagens que permite que os componentes enviem mensagens de maneira flexível.
  • Redis. O Redis é um repositório de chave-valor na memória. O Redis dá suporte a um padrão de publicação/assinatura ("pub/sub") para enviar mensagens.
  • SQL Server. O backplane SQL Server grava mensagens em tabelas SQL. O plano de fundo usa o Service Broker para mensagens eficientes. No entanto, ele também funcionará se o Service Broker não estiver habilitado.

Se você implantar seu aplicativo no Azure, considere usar o backplane redis usando o Cache Redis do Azure. Se você estiver implantando em seu próprio farm de servidores, considere os planos de fundo SQL Server ou Redis.

Os tópicos a seguir contêm tutoriais passo a passo para cada backplane:

Implementação

No SignalR, cada mensagem é enviada por meio de um barramento de mensagens. Um barramento de mensagens implementa a interface IMessageBus , que fornece uma abstração de publicação/assinatura. Os planos de fundo funcionam substituindo o IMessageBus padrão por um barramento projetado para esse backplane. Por exemplo, o barramento de mensagens para Redis é RedisMessageBus e usa o mecanismo de pub/sub do Redis para enviar e receber mensagens.

Cada instância do servidor se conecta ao backplane por meio do barramento. Quando uma mensagem é enviada, ela vai para o backplane e o backplane a envia para todos os servidores. Quando um servidor recebe uma mensagem do backplane, ele coloca a mensagem em seu cache local. Em seguida, o servidor entrega mensagens aos clientes de seu cache local.

Para cada conexão de cliente, o progresso do cliente na leitura do fluxo de mensagens é acompanhado usando um cursor. (Um cursor representa uma posição no fluxo de mensagens.) Se um cliente se desconectar e se reconectar, ele solicitará ao barramento todas as mensagens que chegaram após o valor do cursor do cliente. A mesma coisa acontece quando uma conexão usa sondagem longa. Após a conclusão de uma longa solicitação de sondagem, o cliente abre uma nova conexão e solicita mensagens que chegaram após o cursor.

O mecanismo de cursor funciona mesmo que um cliente seja roteado para um servidor diferente na reconexão. O backplane está ciente de todos os servidores e não importa a qual servidor um cliente se conecta.

Limitações

Usando um plano de fundo, a taxa de transferência máxima da mensagem é menor do que é quando os clientes conversam diretamente com um único nó de servidor. Isso ocorre porque o plano de fundo encaminha cada mensagem para cada nó, de modo que o plano de fundo pode se tornar um gargalo. Se essa limitação é um problema depende do aplicativo. Por exemplo, aqui estão alguns cenários típicos do SignalR:

  • Transmissão de servidor (por exemplo, ticker de ações): os planos de fundo funcionam bem para esse cenário, pois o servidor controla a taxa na qual as mensagens são enviadas.
  • Cliente para cliente (por exemplo, chat): nesse cenário, o backplane pode ser um gargalo se o número de mensagens for dimensionado com o número de clientes; ou seja, se a taxa de mensagens aumentar proporcionalmente à medida que mais clientes ingressarem.
  • Tempo real de alta frequência (por exemplo, jogos em tempo real): um backplane não é recomendado para esse cenário.

Habilitando o rastreamento para o dimensionamento do SignalR

Para habilitar o rastreamento para os planos de fundo, adicione as seguintes seções ao arquivo web.config, no elemento de configuração raiz:

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