Abaixo está uma história detalhada sobre como carregamos o cartão da NVidia com as tarefas de transcodificação de vídeo para seu streaming. Vamos mostrar que tentamos o que aconteceu e qual a melhor forma de usar placas de vídeo para transmitir online.Por vários anos, nossa equipe desenvolve produtos para processar e distribuir conteúdo de mídia online.
Este artigo descreveu recentemente por que os proprietários de conteúdo podem precisar dessas soluções em nossa era do YouTube.
Um de nossos produtos é o servidor de mídia
Nimble Streamer , que é um software de servidor que transmite arquivos e transmissões ao vivo para a entrada e os torna acessíveis a um grande número de espectadores, ao mesmo tempo em que monetiza o conteúdo. Este é um aplicativo nativo escrito em C ++ e portado para todos os SOs populares (Linux, Windows, MacOS) e plataformas (x64, ARM). Desde o início, baixo consumo de recursos e alta produtividade foram os principais requisitos, e conseguimos alcançar
bons resultados nisso.
No ano passado, lançamos o
transcodificador Nimble Streamer -
transmissão ao vivo . Este aplicativo permite que você pegue o fluxo de entrada de vídeo e / ou áudio em diferentes formatos e faça várias conversões com eles em tempo real. A funcionalidade inclui decodificação (software e hardware), conversão de vídeo e áudio usando filtros (redimensionamento, sobreposição etc.) e codificação (codificação) - software e hardware.
O transcodificador é controlado pelo serviço da web WMSPanel, e os scripts de transcodificação são criados por meio da interface de arrastar e soltar, que permite visualizar visualmente o processo. Vários cenários podem ser executados juntos - com essa abordagem, é conveniente executar combinações de testes, carregando o servidor em qualquer variação.
Nesses vídeos, você pode ver exemplos de como a interface funciona.
A decodificação de cada fluxo é feita apenas uma vez antes de todas as conversões adicionais ... Isso permite que você economize recursos em uma operação de decodificação dispendiosa; isso será visto claramente ao longo dos testes.
Um dos mecanismos de conversão que pode ser usado em nosso transcodificador é a decodificação de hardware e a codificação de vídeo usando a GPU da NVidia. As placas gráficas das últimas gerações permitem executar algumas das tarefas típicas, o que remove a carga da CPU. Nosso transcodificador é capaz de trabalhar com esse hardware, usado ativamente por nossos clientes.
No decorrer da comunicação com os representantes do escritório russo da NVidia, fomos solicitados a tentar organizar testes de estresse conjuntos de nosso transcodificador e GPU NVidia para entender qual o efeito econômico desse tandem será comparado à transcodificação exclusiva de software, sem aceleração de hardware. Além disso, queria entender como usar a GPU da melhor maneira possível e, se possível, fornecer boas receitas.
Precisávamos obter rapidamente o ferro apropriado e ter acesso a ele, para o ciclo de nossos experimentos. Planejamos nos encontrar algumas semanas. Resta descobrir onde obter o equipamento. A melhor opção seria encontrá-los na nuvem e obter acesso remoto. Depois de procurar as opções, verificou-se que a AWS ainda não possui uma VM com uma GPU da geração Maxwell e, na nuvem do Azure, está planejado começar a fornecê-las em breve.
1. Ferro da NVidia na nuvem Softlayer, configurando o Nimble Streamer
Com a assistência da NVidia, a IBM nos forneceu acesso à sua nuvem, o IBM Bluemix Cloud Platform (anteriormente
Softlayer ). Essa é uma grande rede de data centers modernos (cerca de 50 no momento da publicação) em todo o mundo, conectados por uma rede privada comum e fornecendo uma grande variedade de serviços de infraestrutura em nuvem. Todos os datacenters são unificados e permitem que você alugue de um a centenas de servidores virtuais ou físicos da configuração necessária por várias horas, bem como balanceadores, sistemas de armazenamento, firewalls - em geral, tudo o que é necessário para criar uma infraestrutura de TI confiável para o serviço de TI implantado.
O escritório de representação russo da IBM nos deu acesso total ao
portal de autoatendimento para gerenciar serviços em nuvem e à configuração necessária do servidor, onde pudemos trabalhar com diferentes fluxos de entrada e configurações de nosso transcodificador.
Ferro
Primeiro, recebemos um servidor físico (bare-metal) com 128 GB de RAM e 2xGPU NVidia Tesla M60 e o sistema operacional Ubuntu 14.04 pré-instalado. Todos os parâmetros do servidor, senhas, versões de firmware, sua comutação, IP dedicado, o estado dos componentes de hardware, eram visíveis diretamente em sua conta pessoal, permitindo fazer as manipulações necessárias com o hardware alugado, o que minimizava a necessidade de interação com o suporte IBM. Durante a execução do teste, não foi possível carregar de maneira ideal essa configuração, devido a várias limitações na geração de contextos.
Queríamos reduzir a configuração. Como usamos a plataforma em nuvem, era necessário, por meio do portal de autoatendimento, solicitar alterações na configuração. Após a aprovação, esta operação levou cerca de 2 horas para a janela de serviço aprovada. Durante esse período, a equipe técnica do data center de Amsterdã removeu componentes extras (slots de RAM e 1xGPU) do servidor fornecido anteriormente e o colocou em operação novamente. Note-se que, para desenvolvedores, essa opção é muito conveniente, pois não há necessidade de lidar com as configurações de hardware, repará-las ou até mesmo gastar tempo instalando o sistema operacional. Deixe-me lembrá-lo de que, neste caso, o hypervisor não é usado porque precisamos extrair o máximo de recursos de hardware.
Com base nos resultados de nossa pesquisa, decidimos pela seguinte configuração de servidor:
Intel Dual Xeon E5-2690 v3 (2.60GHz)
24 núcleos
64GB RAM
1 TB SATA
Temos 2 processadores com 12 núcleos cada e, graças ao Hyper threading, obtemos o dobro, ou seja, virtualmente 48 núcleos.
Em cenários com acelerador gráfico, foi utilizada uma placa baseada no chip GM204 - Tesla M60:
NVIDIA Tesla M60
1xGPU: 2 x Maxwell GM204
Memória: 16GB GDDR5
Velocidade do relógio: 2,5 GHz
Núcleos NVIDIA CUDA: 2 x 2048
Largura de banda da memória: 2 x 160GB / seg
Chamo a atenção para o fato de que nenhuma afinidade, ajuste de chip, overclock ou outra mágica foi realizada no hardware reduzido - apenas CPUs e GPUs sem overclock e, para a GPU, apenas o driver oficial retirado do site da NVidia foi usado. Se alguém tiver uma experiência semelhante - compartilhe nos comentários.
Então, nós temos acesso. Um rápido conhecimento da interface da web do painel de controle (tudo é simples e claro lá), depois o acesso ao servidor via SSH - e aqui estamos na linha de comando habitual do Ubuntu, coloque o Nimble Streamer, registre uma nova licença de transcodificador e faça uma pequena configuração.
Transceptor ágil de serpentina
O Nimble Streamer foi configurado para pré-criar o cache de contexto da GPU. Isso se deve ao fato de a GPU ter um limite para o número máximo de contextos de decodificação e codificação criados e, além disso, a criação de contextos em tempo real pode levar muito tempo.
Mais detalhes sobre o problema de criação de contextos podem ser encontrados na seção correspondente abaixo.
Configurações de Nimbl no exemplo da primeira série de testes:
nvenc_context_cache_enable = true
nvenc_context_create_lock = true
nvenc_context_cache_init = 0: 30: 15.1: 30: 15
nvenc_context_reuse_enable = true
Mais detalhes sobre essas configurações estão escritos
em nosso artigo .
Antes de iniciar cada série de testes, o cache foi configurado separadamente, levando em consideração as especificidades de cada tarefa.
Criar scripts de transcodificação
Mais trabalho foi realizado em nosso serviço WMSPanel, onde os scripts do transcodificador estão configurados.
Como já mencionado, o trabalho passa pela interface da Web, tudo é extremamente claro e conveniente. Criamos vários cenários que combinam diferentes opções de transcodificação (CPU / GPU), diferentes opções de resolução e diferentes parâmetros de codificação (CPU / GPU, perfil, taxa de bits etc.)
Conjuntos de cenários podem ser executados simultaneamente, o que possibilita introduzir várias combinações de testes, aumentar a carga em uma ordem diferente e alterá-la, dependendo da situação. Apenas selecione os cenários necessários e pare ou retome-os.
Aqui está um conjunto de cenários:
Aqui está um exemplo de um dos cenários:
O decodificador da GPU é assim:
Aplicamos o filtro de tamanho da imagem:
E aqui está o codificador para a variante GPU:
Em geral, a operação da interface do transcodificador pode ser
vista nesses vídeos .
2. Transcodificação de fluxos FullHD 1080p
Para começar, testamos o cenário com as cargas mais altas para descobrir os limites das capacidades de ferro. No momento, a "mais pesada" das resoluções usadas na prática é FullHD 1080p.
Para gerar as transmissões ao vivo originais, um arquivo foi obtido em
FullHD (1920 * 1080) no
H.264 de alto perfil . O conteúdo em si é um tour de vídeo da cidade, ou seja, Este é um vídeo com uma taxa média de alteração de imagem. Não há quadros estáticos de cor única que possam facilitar o trabalho do transcodificador, mas não há mudanças muito rápidas de tipos e cores. Em uma palavra - uma carga bastante típica.
36 fluxos idênticos foram alimentados na entrada Nimble Streamer, que foram usados no transcodificador em diferentes cenários.
O cenário de transcodificação é usado normalmente - o fluxo de entrada é de perfil principal de
1080p ,
720p, 480p, 360p e depois os fluxos de
perfil de linha de base são criados a partir dele
: 240p, 160p . No total, há 1 fluxo na entrada e 5. Na saída, geralmente é realizada uma passagem (transferência sem alterações) do fluxo original para que o visualizador possa selecionar o próprio 1080p ao visualizar. Nós não o adicionamos no script, porque ele não usa transcodificação - há uma transferência direta de dados da entrada para a saída. Esse cenário é otimizado no Nimble e, em condições reais, aumentará o consumo de memória relativamente levemente.
Áudio nos fluxos gerados - não. A adição de áudio ao script não causará cargas significativas na CPU, mas, para a pureza do experimento, excluímos o som.
Teste de CPU, sem GPU
Para começar, lançamos scripts de transcodificação sem usar uma GPU, especificando decodificador e codificador de software nos scripts.
Como resultado, foi possível processar apenas 16 fluxos de entrada com a emissão de 80 fluxos de todas as permissões de saída.
Carga da CPU - 4600%, ou seja, 46 núcleos envolvidos. Consumo de RAM - cerca de 15 GB.
Teste de CPU + GPU
O cache de contexto na inicialização é configurado como 0: 30: 15.1: 30: 15 - ou seja, 30 contextos para codificação, 15 para decodificação, cada GPU.
Deixe-me lembrá-lo de que na GPU temos dois núcleos, o que nos permite paralelizar tarefas - isso é útil para nós.
A carga máxima foi obtida com a seguinte configuração de fluxo.
O decodificador de entrada GPU0 e GPU1 - 15 fluxos. Assim, temos 30 fluxos decodificados, prontos para uso posterior. Cada fluxo é decodificado apenas uma vez, independentemente de quantos cenários ele é usado no futuro.
Os codificadores GPU0 e GPU1 foram alimentados com 15 fluxos cada para obter 720p, ou seja, 30 fluxos de 720p em uma saída resultaram.
Além disso, os codificadores GPU0 e GPU1 forneceram 15 fluxos para 480p - e 30 fluxos de 480p também foram produzidos.
Como os contextos do codificador foram esgotados, a codificação das permissões restantes foi definida na CPU. O resultado foi o seguinte:
- 30 transmissões em 360p
- 30 transmissões 240p
- 30 fluxos 160p
A carga acabou sendo de 2600% da CPU, 75% de decodificador e 32% de codificador. Em seguida, a CPU foi carregada com 6 fluxos para decodificação, para cada 5 resoluções semelhantes configuradas, para um total de 30 threads por saída.
No total,
36 fluxos foram recebidos
na entrada, 180 foram emitidos na saída . A carga final é corrigida da seguinte forma:
CPU 4400%, decodificador de cartão 75%, codificador de cartão 32%, 30 GB de RAM .
Alguns detalhes
Decidimos verificar a opção em que processamos as tarefas mais difíceis na GPU - decodificação 1080 e codificação 720 e 480, e deixar o restante ser processado por meio da CPU.
Primeiro, verificamos o limite do decodificador. Com 22 threads, a decodificação foi afetada pelo problema com os contextos, eles simplesmente não puderam ser criados. Diminuído para 21 - os contextos foram criados, mas a carga se tornou 100% e os artefatos começaram a ser observados no fluxo. Paramos em 20 fluxos - decodificamos 20 fluxos, codificamos em 160p - tudo funciona bem.
Além disso, descobriu-se empiricamente que este cartão com 16 GB de RAM a bordo pode trabalhar com confiança em 47 contextos - e não há diferença, esses são os contextos de um codificador ou decodificador. Repito - isso é especificamente sobre esta GPU Tesla M60, em outros cartões esse número pode ser diferente. Acreditamos que, se o cartão tivesse 24 GB de RAM, o número de contextos poderia ser diferente, mas isso precisa ser testado.
Como resultado, escolhemos a fórmula de criação de cache "15 contextos do decodificador e 30 contextos do codificador" - que fornece 30 fluxos para a entrada e para cada um permite criar 2 permissões. Portanto, as resoluções superiores - 720 e 480 - foram lançadas na GPU, e as demais - 360, 240 e 160 - foram enviadas para a CPU. E como a CPU ainda estava livre depois disso, "finalizamos" os núcleos livres com novos threads, deixando 4 núcleos para tarefas utilitárias.
3. Transcodificação de fluxos HD 720p
Cenário de carregamento típico A maior parte do conteúdo agora é criada em HD. Até o recente SuperBowl LI - o programa de maior audiência do mercado americano - foi
transmitido em HD , deixando o FullHD para o futuro.
Para gerar os fluxos de origem, um arquivo foi obtido em
HD (1280 * 720) em um
perfil alto . O conteúdo é a série "The Good Wife" favorita do nosso engenheiro, ou seja, Este é um vídeo com uma taxa média de alteração de imagem.
Na entrada do Nimble Streamer, 70 fluxos idênticos foram alimentados, que foram então usados no transcodificador em diferentes cenários.
O cenário de transcodificação a seguir é usado - o fluxo de entrada é
720p de alto perfil,
480p, perfil principal de 360p e, em seguida
, são feitos fluxos de perfil de
linha de base de 240p e 160p . Total, na entrada 1, na saída 4. A passagem do fluxo original, como no cenário anterior, não foi executada. O áudio nos fluxos gerados também não é.
Teste de CPU, sem GPU
Como na seção anterior, tentamos transcodificar fluxos apenas na CPU. Como resultado, foi possível processar apenas 22 fluxos de entrada com a emissão de 88 fluxos de todas as permissões de saída. Carga da CPU - 4700%, ou seja, 47 núcleos estavam envolvidos. Consumo de RAM - cerca de 20 GB.
Teste de CPU + GPU
O cache de contexto na inicialização é configurado como 0: 23: 23.1: 23: 23 - ou seja, 23 contextos para codificação, 23 para decodificação para cada GPU.
Usando a GPU, 46 fluxos de 720p foram decodificados. Lá, na GPU, 46 fluxos de 480p foram codificados. Em seguida, as codificações 360p, 240p e 160p foram realizadas na CPU - 46 fluxos cada.
Carga fixa de 2100% da CPU, 61% do decodificador, 16% do codificador.
Além disso, foi iniciada a codificação e decodificação de 24 threads na CPU, para cada 1 thread - 4 saídas, como para a GPU.
Ao todo,
70 fluxos foram inseridos, 280 fluxos foram gerados .
Carga:
4600%, 61% do decodificador, 16% do codificador, 30 GB de RAM .
Quanto ao teste anterior, talvez uma GPU de RAM maior daria mais contextos e poderíamos lidar com mais threads. Mas isso é apenas na teoria, é necessário verificar.
4. O problema com a criação de contextos na GPU NVidia
Algumas palavras sobre o problema que não nos permitiram processar mais threads na GPU.
No final do ano passado, realizamos testes com a equipe da NVidia, com várias placas. Ao trabalhar com várias GPUs, descobriu-se que a criação de contextos diminui bastante o servidor - a criação de cada novo contexto leva cada vez mais tempo no mapa. Se o primeiro contexto foi criado na ordem de 300ms, cada um subsequente adicionou 200-300ms e já nos terceiros dez contextos, criando um novo, levando de 3 a 4 segundos cada. Quando um usuário cria um script de transcodificação, supõe-se que ele comece a trabalhar imediatamente e sem atrasos, e essa nova circunstância negou todas as vantagens na velocidade do Nimbl e atrasou a criação de contextos que levaram a atrasos no início da codificação.
No início, a suspeita caiu no Nimble, mas depois fizemos testes usando o ffmpeg, que a própria NVidia fornece aos clientes e o resultado foi exatamente o mesmo - a GPU está gastando cada vez mais tempo criando cada novo contexto. Em condições em que o servidor já está transcodificando e você precisa iniciar novos encadeamentos para processamento, isso afeta o desempenho geral e torna o servidor simplesmente inutilizável.
O problema foi descrito em detalhes pela equipe da NVidia, mas até agora nenhuma solução em tempo integral foi fornecida. Portanto, até o momento, implementamos um mecanismo de cache de contexto em nosso servidor, com a criação preliminar de contextos no início do servidor. Isso resolveu o problema do ponto de vista do trabalho do usuário final, mas o início do Nimbl pode levar algum tempo. A configuração do Nimbl para um trabalho eficaz com contextos
é descrita em nosso blog .
Além disso, os contextos não são fáceis de criar. Com um grande número de contextos ao incluir qualquer script de transcodificação, a API NVENC começa a gerar erros: "A chamada da API falhou porque não foi possível alocar memória suficiente para executar a operação solicitada".
Empiricamente, descobriu-se que uma GPU pode iniciar e trabalhar com confiança em 47 contextos - e não há diferença, esses são os contextos de um codificador ou decodificador. Havia uma suposição de que isso se deve à quantidade de memória na GPU. Agora existem 16 GB, se você colocar um cartão com 24 GB, é provável que mais contextos possam ser feitos. Mas isso é apenas uma teoria, é necessário verificar, como mencionado anteriormente. Os dados obtidos são válidos para um modelo de GPU específico; outros cartões devem ser testados separadamente.
É a restrição do número de contextos que coloca o principal obstáculo ao trabalhar com grandes cargas.
5. Conclusões
Portanto, o objetivo do teste era estudar a eficácia da GPU para o intervalo indicado de tarefas e desenvolver receitas para seu uso adequado. Qual é o resultado?
Efeito econômico
Acima, vimos como o número de threads que podem ser processados na CPU e no conjunto CPU + GPU é diferente. Vamos ver o que isso significa em termos de dinheiro. Como base, adotamos todos os mesmos preços da Softlayer e de aluguel de equipamentos.
- A configuração sem uma GPU custará US $ 819 por mês . Aqui você pode pegar um carro.
- A configuração com a GPU custará US $ 1729 por mês para o data center em Amsterdã. Os preços podem ser encontrados aqui . Ao usar uma GPU, o preço do aluguel do servidor aumenta um pouco, pois é usado o fator de forma da caixa 2U maior. O efeito econômico provavelmente será maior na compra de equipamentos (mas isso requer uma análise séria do custo total de propriedade, levando em consideração a atualização constante da linha de GPU NVidia).
Agora vamos ver os resultados do teste:
Para FullHD 1080p
- CPU sem GPU: 16 threads por entrada + 80 threads por saída
- CPU + GPU: 36 threads por entrada + 180 por saída
Benefício da GPU: 2,25x.Benefícios do uso da GPU: US $ 819 * 2,25 - US $ 1729 = US $ 113 por mês ao alugar um servidor com uma GPU.Para HD 720p- CPU sem GPU: 22 threads por entrada + 88 threads por saída
- CPU + GPU: 70 threads por entrada + 280 por saída
Benefício da GPU: 3.18x.Beneficie-se do uso da GPU: US $ 819 * 3,18 - US $ 1729 = US $ 875 por mês ao alugar um servidor com uma GPU.Ou seja, com a opção de aluguel, as economias são bastante visíveis. Isso não leva em consideração os descontos - no escritório russo da IBM eles prometem descontos no aluguel de recursos na nuvem em comparação com os preços apresentados aqui.Não entramos nas opções com a compra, porque aqui, o custo total de propriedade depende fortemente da escolha do fornecedor, do custo do serviço no data center e de outros fatores familiares àqueles que trabalham com bare metal. No entanto, os números preliminares também falam em favor de uma solução baseada em GPU.Além disso, não se esqueça do tráfego e da largura do canal - eles estão incluídos em uma certa quantia nas tarifas apresentadas acima, mas você precisará selecionar opções para suas tarefas com base no número de threads, no número esperado de usuários etc.Dimensionamento
A opção com uma placa gráfica por servidor nos parece mais econômica do que a opção com duas ou mais placas. Como podemos ver, o decodificador da GPU sempre carregava mais do que o codificador, mas mesmo assim permaneceu sobrecarregado devido a problemas com o uso de contextos. Se você adicionar uma segunda placa, o decodificador será usado ainda menos, os codificadores que não poderemos carregar com capacidade total e todo o trabalho na codificação ainda precisará ser transferido para a CPU, que será injustificada pelo dinheiro. Também testamos a opção com duas GPUs graças ao suporte do Softlayer, mas devido ao fraco efeito econômico, não fornecemos detalhes no artigo.Assim, para escalar a carga, é preferível adicionar novos servidores com uma placa gráfica do que adicionar placas às máquinas existentes.Se o número de fluxos de entrada e saída do seu projeto for relativamente pequeno - digamos, uma dúzia de fluxos de HD com um pequeno número de permissões de saída, com uma quantidade relativamente pequena de filtragem, seria mais conveniente usar um servidor sem uma GPU.Também é importante notar que a quantidade de RAM para a tarefa de conversão de threads não é tão importante quanto a capacidade de processamento. Portanto, em alguns casos, você também pode economizar reduzindo a quantidade de memória.Conclusão
A solução de hardware apresentada - uma combinação da CPU e GPU Tesla M60 - foi perfeita para transcodificar fluxos ao vivo sob cargas pesadas. A GPU cuida das operações que consomem mais recursos - decodificando os fluxos e codificando-os nas resoluções mais altas, enquanto as resoluções médias e pequenas são bem processadas na CPU.Se um dos leitores tiver experiência e otimizar o desempenho das placas gráficas para transmissão ao vivo, teremos o maior prazer em conhecer sua experiência - escreva nos comentários.