SFUs em cascata: aprimorando a escalabilidade e a qualidade da mídia em aplicativos WebRTC

Há duas dificuldades na implantação de servidores de mídia para o WebRTC: dimensionamento, ou seja, indo além do uso de um servidor e otimizando atrasos para todos os usuários da conferência. Embora o sharding simples, no espírito de "enviar todos os usuários da conferência X para o servidor Y", seja facilmente escalável horizontalmente, está longe de ser o ideal em termos de atrasos. Distribuir a conferência entre servidores não apenas próximos dos usuários, mas também interconectados - parece uma solução para ambos os problemas. Hoje, preparamos uma tradução detalhada de Boris Grozev da Jitsi: problemas de SFUs em cascata, com uma descrição da abordagem e algumas dificuldades, além de detalhes de implementação. Vale dizer que as conferências Voximplant também usam SFU ; Atualmente, estamos trabalhando na cascata do SFU, que deve aparecer em nossa plataforma no próximo ano.


Neurônios do mouse. Imagem NIHD ( CC-BY-2.0 )

As comunicações em tempo real são muito sensíveis à rede: largura de banda, latência e perda de pacotes. Uma diminuição na taxa de bits leva a uma diminuição na qualidade do vídeo, um longo atraso na rede leva a um longo atraso para os usuários finais. A perda de pacotes pode tornar o som intermitente e levar a congelamentos no vídeo (devido a pulos de quadros).

Portanto, é muito importante para a conferência escolher a rota ideal entre os dispositivos / usuários finais. Quando há apenas dois usuários, é fácil: o WebRTC usa o protocolo ICE para estabelecer uma conexão entre os participantes. Se possível, os participantes se conectam diretamente, caso contrário, um servidor TURN é usado. O WebRTC pode resolver um nome de domínio para obter o endereço de um servidor TURN, para que você possa selecionar facilmente um TURN local com base no DNS, por exemplo, usando as propriedades do AWS Route53 .

No entanto, quando o roteamento de vários participantes ocorre por meio de um servidor de mídia central, a situação se torna complicada. Muitos serviços WebRTC usam SFUs (Selective Forwarding Units) para transferir áudio e vídeo entre 3 ou mais participantes com mais eficiência.

Problema com uma estrela


Na topologia em estrela, todos os participantes se conectam a um único servidor através do qual trocam fluxos de mídia. Obviamente, a escolha do local do servidor é de grande importância: se todos os participantes estiverem nos EUA, usar um servidor em Sydney não é uma boa ideia.


Muitos serviços usam uma abordagem simples que funciona bem na maioria dos casos: eles escolhem um servidor mais próximo do primeiro participante da conferência. No entanto, há momentos em que essa solução não é ótima. Imagine que temos três participantes da figura acima. Se um australiano (chamador C) for o primeiro a ingressar na conferência, o algoritmo escolherá um servidor na Austrália; no entanto, o servidor 1 nos EUA será a melhor escolha, porque ele está mais perto da maioria dos participantes.

O cenário descrito não é muito frequente, mas ocorre. Se assumirmos que o usuário está conectado em uma ordem aleatória, a situação descrita ocorre com ⅓ de todas as conferências com 3 participantes, um dos quais é muito excluído.

Outro cenário e mais frequente: temos dois grupos de participantes em locais diferentes. Nesse caso, a ordem de conexão não é importante; sempre teremos um grupo de participantes próximos que são forçados a trocar mídia com um servidor remoto. Por exemplo, 2 participantes da Austrália (C&D) e 2 dos EUA (A&B).


Mudar para o Servidor 1 não será ideal para membros de C&D. O servidor 2 não é ideal para A&B. Ou seja, não importa qual servidor seja usado, sempre haverá participantes conectados ao servidor remoto (= não otimizado).

Mas se não tivéssemos um único limite de servidor? Poderíamos conectar cada participante ao servidor mais próximo, restaria apenas conectar esses servidores.

Solução: Em cascata


Adiamos a questão de como conectar os servidores; vamos primeiro ver qual será o efeito.


A conexão SFU entre C e D não mudou - o Servidor 2. ainda é usado, o Servidor 1 é usado para os participantes A e B, e isso é obviamente melhor. O mais interessante é a conexão entre, por exemplo, A e C: em vez de A <=> Servidor 2 <=> C, a rota A <=> Servidor 1 <=> Servidor 2 <=> C é usada.

Efeito implícito na taxa de câmbio


O mix SFU tem seus prós e contras. Por um lado, na situação descrita, o tempo de troca entre os participantes se torna mais longo quando novos saltos na rede são adicionados. Por outro lado, há uma diminuição nesse momento quando falamos sobre a conexão “cliente” - “primeiro servidor”, porque podemos restaurar o fluxo de mídia com um atraso menor pelo princípio do salto por salto.

Como isso funciona? O WebRTC usa RTP (geralmente sobre UDP) para transmitir mídia. Isso significa que o transporte não é confiável. Quando um pacote UDP é perdido, você pode ignorar a perda ou solicitar um reenvio (retransmissão) usando o pacote RTCP NACK - a opção já está na consciência do aplicativo. Por exemplo, um aplicativo pode ignorar a perda de pacotes de áudio e solicitar a retransmissão de alguns (mas não todos) pacotes de vídeo, dependendo se eles são necessários para decodificar os quadros subseqüentes ou não.


Retransmissão de pacotes RTP, servidor único

Quando há cascata, a retransmissão pode ser limitada ao servidor local, ou seja, realizado em cada site individual. Por exemplo, na rota A-S1-S2-C, se um pacote for perdido entre A e S1, então S1 notará isso e solicitará uma retransmissão; semelhante à perda entre S2 e C. E mesmo se o pacote for perdido entre servidores, o lado receptor também poderá solicitar uma retransmissão.


Retransmissão de pacotes RTP, dois servidores. Observe que o servidor 2 não solicita o pacote 2, porque o NACK chegou logo após o envio do pacote.

O cliente usa um buffer de tremulação para atrasar a reprodução do vídeo e conseguir receber pacotes atrasados ​​/ retransmitidos. O tamanho do buffer muda dinamicamente, dependendo do tempo de troca entre as partes. Quando ocorrem retransmissões de salto por salto, o atraso diminui e, como resultado, o buffer pode ser menor - como resultado, o atraso geral também diminui.

Resumidamente: mesmo que o tempo de troca entre os participantes seja maior, isso pode levar a uma diminuição no atraso na transferência de mídia entre os participantes. Ainda temos que estudar esse efeito na prática.

Apresentando SFUs em cascata: Jitsi Meet Case


Alarme vs. Mídia


Vamos dar uma olhada no alarme. Desde o início, o Jitsi Meet compartilhou o conceito de servidor de sinalização ( Jicofo ) e servidor de mídia / SFU. Isso permitiu a introdução de suporte em cascata é relativamente simples. Primeiro, poderíamos lidar com toda a lógica de sinalização em um só lugar; segundo, já tínhamos um protocolo de sinalização entre Jicofo e o servidor de mídia. Precisávamos apenas expandir um pouco a funcionalidade: já suportávamos várias SFUs conectadas a um servidor de sinalização, tivemos que adicionar a capacidade de uma SFU para conectar-se a muitos servidores de sinalização.

Como resultado, dois pools de servidores independentes apareceram: um para instâncias jicofo e outro para instâncias de servidor de mídia, consulte o diagrama:


Um exemplo de organização de servidores na AWS com a possibilidade de uma cascata entre diferentes data centers.

A segunda parte do sistema é a comunicação ponte a ponte. Queríamos tornar essa parte o mais simples possível, para que não haja sinalização complicada entre as pontes. Todo alarme varia entre jicofo e jitsi-videobridge; A conexão de ponte é usada apenas para mensagens de áudio / vídeo e link de dados.

Protocolo Octo


Para gerenciar essa interação, adotamos o protocolo Octo, que agrupa pacotes RTP em cabeçalhos simples de tamanho fixo e também permite enviar mensagens de texto. Na implementação atual, as pontes são conectadas por uma topologia de malha completa (malha completa), mas outras topologias também são possíveis. Por exemplo, use um servidor central (estrela para pontes) ou uma estrutura em árvore para cada ponte.

Explicação: Em vez de agrupá-lo em um cabeçalho Octo, você pode usar a extensão de cabeçalho RTP, que fará fluxos entre pontes no RTP puro (S). Versões futuras do Octo podem usar essa abordagem.

Segunda Explicação: Octo não significa nada. Inicialmente, queríamos usar um servidor central e isso nos lembrou um polvo. Então, o nome do projeto apareceu.

Octo Header Format

Na terminologia do Jitsi, quando uma ponte faz parte de uma conferência com várias pontes, ela possui um canal Octo adicional (de fato, um canal para áudio e outro para vídeo). Este canal é responsável por enviar / receber mídia de / para outras pontes. Cada ponte possui uma porta livre para Octo (4096 por padrão), portanto, precisamos do campo ID da conferência para lidar com várias conferências.

No momento, o protocolo não possui mecanismos de segurança internos e delegamos essa responsabilidade nos níveis mais baixos. Essa é a coisa mais próxima que faremos no futuro próximo, mas por enquanto as pontes devem estar em uma rede segura (por exemplo, uma instância separada do AWS VPC).

Simulcast


O Simulcast permite que cada participante envie vários fluxos de mídia com taxas de bits diferentes, enquanto a ponte ajuda a determinar quais são necessárias. Para que isso funcione corretamente, transferimos todos os fluxos de simulcast entre as pontes. Graças a isso, você pode alternar rapidamente entre fluxos, porque a ponte local não precisa solicitar um novo fluxo. Entretanto, isso não é ideal do ponto de vista do tráfego ponte a ponte, pois alguns threads raramente são usados ​​e carregam apenas a largura de banda sem nenhum objetivo.

Seleção de membro ativo


Também queríamos a oportunidade de assinar um participante / orador ativo da conferência. Acabou sendo simples - ensinamos cada ponte a determinar independentemente o participante principal e, em seguida, notificamos nossos clientes locais. Isso significa que a determinação ocorre várias vezes, mas não é onerosa e permite simplificar alguns pontos (por exemplo, você não precisa decidir qual ponte deve ser responsável pelo DSI e se preocupar com o roteamento de mensagens).

Seleção de ponte


Na implementação atual, esse algoritmo é simples. Quando um novo participante ingressa na conferência, Jicofo deve determinar qual ponte atribuir a ele. Isso é feito com base na região do participante e no congestionamento das pontes. Se na mesma região houver uma ponte livre, ela será designada. Caso contrário, alguma outra ponte será usada.

Para mais informações sobre o Octo, consulte a documentação .

Expandir o SFU em cascata


Para implantação, usamos máquinas no Amazon AWS. Tínhamos servidores (alarmes e mídia) em 6 regiões:

  • us-east-1 (Virgínia do Norte);
  • us-west-2 (Oregon);
  • eu-oeste-1 (Irlanda);
  • eu-central-1 (Frankfurt);
  • ap-se-1 (Singapura);
  • ap-se-2 (Sydney).

Usamos instâncias HAProxy georreferenciadas para determinar a região membro. O domínio meet.jit.si é gerenciado pelo Route53 e resolve a instância HAProxy, que adiciona a região aos cabeçalhos HTTP da solicitação enviada. Posteriormente, o cabeçalho é usado como o valor da variável config.deploymentInfo.userRegion , disponível no cliente, graças ao arquivo /config.js .

A interface jitsi mostra quantas pontes são usadas e a quais usuários específicos estão conectados - para fins de diagnóstico e demonstração. Passar o mouse sobre o canto superior esquerdo do vídeo local mostrará o número total de servidores e o servidor ao qual você está conectado. Da mesma forma, você pode ver os parâmetros do segundo participante. Você também verá o tempo de troca entre o navegador e o navegador do interlocutor (parâmetro E2E RTT).


Ao ver quem está conectado a qual servidor, você pode ver se a cascata é usada.

Conclusão


Octo apareceu originalmente como um teste A / B. Os primeiros resultados foram bons, agora o Octo está disponível para todos. Ainda há muito tráfego para passar por ele e uma análise mais detalhada do desempenho; também está planejado usar esses desenvolvimentos para apoiar conferências ainda maiores (quando um SFU não é mais suficiente).

Source: https://habr.com/ru/post/pt432708/


All Articles