14 pontos por GN⁺ 2024-11-08 | 3 comentários | Compartilhar no WhatsApp
  • A recall é um serviço que oferece bots de reunião para centenas de empresas e opera uma infraestrutura em larga escala na AWS
  • Para oferecer um serviço com boa eficiência de custos, a empresa tenta aproveitar ao máximo o desempenho do hardware
  • Como a disponibilidade de GPUs em provedores de nuvem foi instável nos últimos anos, o processamento de vídeo foi feito na CPU em vez de GPU
  • Ao perfilar bots que usam Chromium headless, descobriram que a maior parte do tempo de CPU não era gasta com processamento de vídeo (codificação/decodificação), mas sim nas funções de cópia de memória __memmove_avx_unaligned_erms e __memcpy_avx_unaligned_erms
    • memmove e memcpy são funções da biblioteca padrão C (glibc) para copiar blocos de memória
    • memmove lida com alguns casos especiais relacionados à cópia de memória em regiões sobrepostas, mas ambas podem ser classificadas como funções de "cópia de memória"
    • O sufixo avx_unaligned_erms indica que elas são otimizadas para sistemas com suporte a Advanced Vector Extensions (AVX) e também para acessos a memória não alinhados
    • erms significa Enhanced REP MOVSB/STOSB, uma otimização para movimentação rápida de memória em processadores Intel modernos. Dá para entender como "uma implementação mais rápida para determinados processadores"
  • O profiling mostrou que quem mais chamava essas funções era o cliente WebSocket em Python que recebia os dados
    • Em seguida vinha a implementação de WebSocket do Chromium, responsável por transmitir os dados

Problemas do WebSocket

  • Era usado um servidor WebSocket local para enviar dados brutos de vídeo do ambiente JS do Chromium para o encoder
  • Um stream de vídeo bruto em 1080p 30fps exige uma largura de banda alta, de mais de 93 MB por segundo
  • O uso de WebSocket gerava muito custo computacional, principalmente por causa de fragmentação e masking
    • Fragmentação: a implementação de WebSocket do Chromium fragmenta mensagens acima de 131 KB em vários frames. Um frame bruto de vídeo com mais de 3 MB era dividido e enviado em mais de 24 frames separados
    • Masking: por motivos de segurança, o WebSocket aplica masking a todos os frames enviados do cliente para o servidor. Em volumes acima de 100 MB por segundo, isso vira um overhead relevante

Buscando alternativas

  • Como era difícil implementar algo muito mais performático que WebSocket usando apenas APIs de navegador, decidiram fazer um fork do Chromium e implementar funcionalidade personalizada
  • Foram consideradas 3 alternativas: raw TCP/IP, Unix Domain Socket e Shared Memory
    • TCP/IP: evita os problemas de fragmentação/masking do WebSocket, mas o tamanho máximo dos pacotes é pequeno, então ainda há problema de fragmentação. Também existe overhead de cópia para o espaço do kernel
    • Unix Domain Socket: permite pular completamente a pilha de rede, mas ainda exige cópia de dados entre espaço de usuário e espaço do kernel
    • Shared Memory: memória acessível simultaneamente por vários processos. O Chromium pode escrever diretamente na memória compartilhada sem cópias intermediárias, e o encoder pode ler dali imediatamente

Implementação da transmissão baseada em memória compartilhada

  • A leitura e a escrita contínuas de dados na memória compartilhada foram implementadas no formato de ring buffer
  • Requisitos: lock-free, múltiplos produtores/um único consumidor, tamanho de frame variável, leitura sem cópia, compatibilidade com sandbox e sinalização de baixa latência
  • Avaliaram implementações prontas de ring buffer, mas como nenhuma atendia a todos os requisitos, decidiram implementar a própria solução
  • Para permitir leitura sem cópia, os ponteiros foram divididos em três: write, peek e read
  • Para garantir thread safety, foram usadas operações atômicas, e para sinalizar chegada de novos dados/liberação de espaço, foi usado um named semaphore
  • Com a implementação do ring buffer em memória compartilhada e outras otimizações, foi possível reduzir o uso de CPU dos bots em até 50%. No fim, isso gerou uma economia anual de mais de US$ 1 milhão na AWS.

3 comentários

 
GN⁺ 2024-11-08
Comentários do Hacker News
  • É uma história típica de uma startup que escolheu um atalho "bom o suficiente" e otimizou depois.

    • Em uma empresa, havia um cluster de VMs com alto uso de CPU, e usaram um profiler para otimizar isso.
    • Reduziram o uso de CPU removendo dados antigos e adicionando filtros às consultas.
  • Há quem diga que a alta largura de banda dos dados brutos de vídeo é surpreendente.

    • Criticam a decisão de projeto dos WebSockets, dizendo que não previram o problema de uso de CPU.
  • Há a opinião de que o problema não era a AWS, mas o desperdício de ciclos de CPU.

    • WebSockets têm relação com custos de transferência de dados ou de API Gateway.
  • Apontam que o MTU e o MSS de redes TCP/IP são pequenos em comparação com o tamanho dos frames de vídeo.

    • Dizem que falta conhecimento técnico e argumentam que é preciso contratar desenvolvedores.
  • Há quem diga que, usando o Mojo do Chromium, não seria necessário se preocupar com código específico de cada plataforma.

    • Também acham aceitável implementar um ring buffer customizado.
  • Há a opinião de que o problema não era a rede, mas a falta de compreensão sobre codecs de vídeo.

    • Dizem que não conseguem entender por que não usaram um protocolo de streaming de vídeo como o RDP.
  • Elogiam a transparência e dizem que também gostariam de transparência nos preços do produto.

  • Explicam que o masking do protocolo WebSocket foi uma tentativa de resolver problemas de intermediários.

    • Dizem que vale a pena ler a RFC relacionada.
  • Apontam que é estranho transmitir dados de vídeo sem compressão.

    • Dizem que não conseguem entender por que não transmitiram um stream comprimido.
  • Dizem que a abordagem inicial de transmitir vídeo bruto por WebSocket é surpreendente.

    • Afirmam que a ineficiência não atrapalhou o desenvolvimento do produto.
    • Dizem que não conseguem entender uma abordagem que não leva em conta o volume de dados.
 
ahwjdekf 2024-11-09
  • Parece que, no desenvolvimento do produto, não houve nenhuma consideração sobre desempenho.
  • No fim, esse problema se resume a como fazer IPC de grandes volumes de dados.
  • A diferença é que não se trata de um IPC comum, mas de fazer IPC com o navegador Chrome, e
  • o funcionamento interno do navegador Chrome não deve ser tão simples, mas como é aberto, é possível modificar.
  • Então, no fim, é uma questão de escolher o IPC.

Desde o começo, desenvolveram isso do jeito errado...

 
ahwjdekf 2024-11-09

“Dizer que a abordagem inicial de transmitir vídeo bruto por WebSocket é surpreendente.” Concordo com isso.