ByteDance Spark suporta prática de inferência de modelo Wanka

Resumo: Este artigo foi compilado a partir do discurso de abertura "ByteDance Spark suporta a prática de inferência de modelo Wanka" no CommunityOverCode Asia 2023 pelo engenheiro de infraestrutura da ByteDance, Liu Chang, e pelo engenheiro de sistema de aprendizado de máquina da ByteDance, Zhang Yongqiang.
No processo de desenvolvimento de nativo da nuvem, o Kubernetes permitiu que mais e mais tipos de aplicativos de carga, incluindo big data e IA, migrassem para o Kubernetes devido às suas fortes capacidades de construção ecológica e influência. O Byte explora internamente a migração do Spark do Hadoop para o Kubernetes. executa trabalhos nativos da nuvem. A arquitetura de gerenciamento de recursos de big data da ByteDance e a evolução da implantação do Spark podem ser divididas em três estágios:
  • O primeiro estágio é o gerenciamento de recursos offline baseado inteiramente no YARN. Ao usar o YARN em grande escala para gerenciar clusters de big data, a utilização de recursos do Spark pode ser efetivamente melhorada e, ao mesmo tempo, reduzir os custos de operação e manutenção de recursos.
  • O segundo estágio é o estágio de implantação mista de recursos offline. Ao construir um cluster de implantação híbrido de YARN e Kubernetes, a utilização geral de recursos offline é melhorada. Através da tecnologia de implantação híbrida, a utilização de recursos de clusters e de máquinas individuais foi significativamente melhorada. Uma maior melhoria na utilização de recursos significa a necessidade de meios de isolamento mais completos. Portanto, começamos a promover gradativamente a implantação conteinerizada do Spark.
  • O terceiro estágio é uma implantação completa nativa da nuvem. As cargas off-line não usam mais arquiteturas diferentes para gerenciamento, e a pilha de tecnologia e o pool de recursos são verdadeiramente unificados. A natividade da nuvem do Spark também é gradualmente construída e aprimorada.
É claro que o nativo da nuvem é quase uma tendência de desenvolvimento unânime na indústria, então por que usar o nativo da nuvem? Por que usar o Kubernetes como base unificada de gerenciamento de recursos? Existem três vantagens principais. A primeira é a operação e manutenção eficientes , que fornecem criação e gerenciamento de carga ágil. Seja carga on-line ou carga de big data, ele pode facilmente alcançar desenvolvimento, integração e implantação contínuas. O segundo é o pool de recursos . A base nativa da nuvem unificada reduz a sobrecarga da infraestrutura e melhora ainda mais a eficiência da transferência de recursos. Em termos de utilização de recursos, a taxa de utilização de todo o data center pode ser melhorada de forma mais abrangente e completa, alcançando a redução de Isso aumenta a eficiência. . O terceiro é a prosperidade ecológica . Sabemos que o Kubernetes tem quase o ecossistema mais ativo. Ele promove o desenvolvimento ecológico em todos os níveis, fornecendo definições de interface padronizadas, sejam instalações básicas de operação e manutenção, gerenciamento de aplicativos de camada superior ou rede e armazenamento subjacentes. . etc., existem muitas opções de gerenciamento que facilitam o uso do Spark nativo da nuvem.

Escala ByteDance Spark

ByteDance tem escala de negócios Spark líder do setor, executando milhões de trabalhos off-line todos os dias, ocupando recursos de milhões de núcleos, dezenas de milhares de placas GPU e o tamanho total do cluster atinge dezenas de milhares de nós. Uma carga do Spark em grande escala significa que não é fácil implementar o Spark de forma totalmente nativa. Aqui estão as questões que pensamos na prática. A implantação do trabalho Spark é uma implantação estática por Standalone ou uma implantação dinâmica por K8s Native. O Operador deve ser usado? Como implementar o gerenciamento e o controle de recursos em nível de locatário de trabalhos do Spark em K8s? O gerenciamento deve ser realizado quando o trabalho é enviado ou quando o Pod é criado? Como dar suporte às necessidades de agendamento do Spark? Ao enviar jobs no Spark, o grande número de criações de Pod causa gargalos no agendamento? Para uma migração de arquitetura operacional em grande escala, como construímos recursos periféricos e suavizamos a experiência antes e depois da migração operacional?
No processo de exploração da nativação da nuvem pelo Spark, os parceiros também enfrentaram muitos problemas. As tarefas de pesquisa incluem um grande número de tarefas de processamento em lote off-line com requisitos de GPU extremamente altos. Os negócios de cluster on-line podem liberar uma grande quantidade de recursos durante picos baixos. os serviços online não podem ser totalmente utilizados pela GPU, a utilização geral é baixa. O aprendizado de máquina é um parceiro importante do Spark. Resolvemos os problemas acima e trabalhamos juntos para fortalecer o ecossistema circundante. O Spark fez melhorias de mecanismo direcionadas para os negócios, e os negócios também se beneficiaram dos recursos, agendamento e gerenciamento nativos da nuvem. .

Soluções nativas da nuvem Spark e melhorias de mecanismo

Os métodos atuais de uso convencional das soluções de tecnologia nativa da nuvem Spark incluem Spark Native e Spark Operator de código aberto do Google. Os dois métodos atingem o mesmo objetivo e, em última análise, chamam a ferramenta de linha de comando Spark-submit. A diferença é que o Spark Operator do Google suporta semântica mais rica e injeta recursos mais ricos mais próximos dos K8s por meio do Operator e do Mutatingwebhook.
Existem duas soluções de tecnologia nativa da nuvem Byte Spark. A primeira é a migração suave, que não precisa modificar o método de envio do YARN. Ela é enviada ao Kubelet ou Gödel para agendamento por meio do Yodel. submetido ao sistema de agendamento através do Arcee. Os conceitos que precisam ser explicados aqui são: Gödel é um sistema de agendamento de recursos distribuído desenvolvido pela Byte. Ele hospeda os recursos de agendamento de recursos do YARN e do Kubernetes e unifica o pool de recursos, cota, agendamento e isolamento do Kubernetes e do YARN. pelo próprio Byte Operator que suporta tipos de trabalho YARN e transforma os componentes RM e NM do YARN. Arcee é um operador unificado de big data nativo da nuvem desenvolvido de forma independente pela Byte, que pode gerenciar de forma mais conveniente cargas de big data, como Spark e Flink. A diferença entre Yodel e Arcee é que Yodel é uma solução de big data em Gödel que é "compatível com o protocolo YARN", enquanto Arcee é uma solução de big data em Gödel que é "compatível com o protocolo K8s". reutilizará as mesmas tecnologias Gödel Scheduler e Kubelet.
Esta prática é uma implantação completa nativa da nuvem, que é enviada por meio dos principais recursos do Arcee Operator, que incluem principalmente gerenciamento do ciclo de vida do trabalho, gerenciamento de recursos do trabalho e algumas funções de personalização do mecanismo.

Introdução ao Arcee

A ideia central do design do Arcee é o gerenciamento de tarefas de dois níveis , que se baseia no modelo de gerenciamento de dois níveis do YARN - o serviço de gerenciamento central AM, que é o principal responsável pela criação e manutenção de trabalhos de big data, e então AM cria e mantém a computação trabalhadores. Correspondente ao trabalho Spark, Arcee cria o Driver e o Driver cria o Executor necessário. Este modelo de gerenciamento pode gerenciar e expressar com eficácia o status do trabalho de big data e personalizar estratégias de gerenciamento de trabalho. Por outro lado, também pode garantir que o mecanismo de computação tenha controle total sobre a operação dos trabalhos de computação e tenha a capacidade de ajustar o uso de recursos conforme necessário.
A arquitetura geral é mostrada na figura. Arcee Operator contém seis módulos . O módulo Arcee CRD define dois tipos de recursos: ArceeApplication e ArceeCommand: ArceeApplication é usado para descrever trabalhos específicos e ArceeCommand descreve as operações usadas para trabalhos; injeção de configuração usada e verificação para Application/Pod Application Manager é responsável pelo gerenciamento do ciclo de vida dos trabalhos; PodSetManager é o gerenciamento de recursos do trabalho; EngineManager é usado para implementar alguns recursos de personalização do mecanismo; para concluir a interface de trabalhos de big data, como Spark, com agendadores em lote.
O processo completo de envio de trabalho é que o Arnold (plataforma de aprendizado de máquina) inicia o envio do trabalho Spark, chama o Spark Client e preenche os parâmetros necessários para enviar o trabalho ao K8s. No modo Arcee, o Spark Client usa o Arcee Client integrado para criar o Spark ArceeApplication, que é pré-processado pelo Webhook e enviado ao APIServer. Em seguida, o Controlador Arcee recebe o evento de criação da Aplicação. O Arcee ApplicationManager gera o status do trabalho correspondente e cria o Driver de acordo com a descrição na Aplicação. O Driver cria os Executores necessários sob demanda. também executará a injeção de configuração relacionada. Todos os Pods do Driver e Executor no Aplicativo serão mantidos no PodsetManager da Arcee para estatísticas de uso de recursos e fornecerão informações relevantes para outros módulos.

Faísca em Arcee

O Spark no Arcee pode ser considerado uma melhoria do modelo de implantação Spark Native até certo ponto. A principal diferença é que o Cliente K8s integrado no Spark Client é substituído pelo Arcee Client, o componente responsável por gerenciar a carga do Driver; torna-se Operador Arcee; Motorista e Executor tornam-se independentes um do outro. Possui um Aplicativo Arcee unificado para manutenção. Arcee também fornece gerenciamento do ciclo de vida do trabalho, proteção de agendamento e outras funções relacionadas.

Otimização do motor Spark

Com base na prática de negócios apresentada na seção anterior, o lado do mecanismo Spark fez os seguintes aprimoramentos. A seguir estão a ocorrência e as soluções de cada problema.
  • O executor sai normalmente para evitar anormalidades no status do MPS
      Atualmente, alguns trabalhos de limpeza de banco de dados Spark que requerem o uso de GPU são executados em K8s e misturados com serviços online. Esses trabalhos compartilham o dispositivo GPU no host por meio de MPS (MPS é a tecnologia Multi-Process Service fornecida pela Nvidia, que permite diferentes. processos ao mesmo tempo. O processo executa multiplexação por divisão de espaço na GPU em vez da multiplexação por divisão de tempo padrão. Se um dos vários processos compartilhados for eliminado durante a execução do Kernel, é fácil causar uma exceção fatal no nível do hardware, o que fará com que outros processos na GPU saiam, por isso é necessário lidar com a saída normal de cada processo.
      A execução em K8s pode fazer com que o contêiner seja despejado ou eliminado devido ao esgotamento de recursos devido a determinados motivos de agendamento. Analisamos cuidadosamente as situações de saída de vários Executores e Trabalhadores dos relacionamentos Driver, Executor, Daemon e Worker. Ao implementar a saída graciosa do Executor no ambiente do contêiner, capturando o sinal de saída e executando automaticamente cudaDeviceSync, evita que o MPS fique em um estado indefinido devido à saída offline.
  • Resolva um grande número de problemas pendentes de pods por meio de cota
      O Spark oferece suporte a DynamicAllocation. No uso real, os usuários geralmente definem Max com um valor relativamente grande. Atualmente, para evitar a geração de um grande número de pods pendentes, o Arnold executa a verificação de cota com base em Max. Os executores podem realmente ser submetidos ao K8s, caso contrário, aguardarão na fila do serviço Arnold. No entanto, a desvantagem atual de usar Max to Check Quota é que é fácil desperdiçar recursos. Se houver uma cota na fila menor que Max, de acordo com as características da tarefa atual, a tarefa pode ser iniciada primeiro para utilizar os recursos atuais. Porém, a lógica atual de Verificação de Cota faz com que esta parte do recurso seja. inutilizável e a tarefa está sempre na fila na camada superior. Este problema pode ser resolvido pelos seguintes meios:
    • Use o parâmetro Spark.kubernetes.allocation.batch.size para controlar o número de pods extraídos em cada lote;
    • Limite o número máximo de Pening Pods para um único trabalho por meio do parâmetro Spark.kubernetes.allocation.maxPendingPods;
    • No entanto, o ajuste de parâmetros ainda não pode resolver o problema de um grande número de envios na mesma fila no mesmo período. Portanto, você pode usar o Webhook para verificar a cota com base na fila. Se não houver cota, a criação do pod falhará. . Spark lida com a exceção, adiciona uma estratégia de criação de pod, aumenta exponencialmente o intervalo de tempo de criação, etc. para resolver este problema.
  • Otimização robusta de operações em cenários de recursos instáveis ​​em locais mistos
Para dar alguns exemplos, muitas vezes é descoberto que o Spark Executor Pod é rejeitado anormalmente (UnexpectedAdmissionError) durante vários testes de estresse durante o agendamento da otimização da estabilidade de recursos. Através da investigação centralizada, vários problemas de condição de corrida em uma série de lógica Kubelet foram corrigidos e o recurso misto diário médio atingiu um aumento estável na taxa de preenchimento limite. Também realizamos uma série de ajustes e transformações, adicionando alguns pontos de coleta de indicadores de GPU para facilitar a observação do uso de recursos e melhorando a tolerância a falhas da tarefa à instabilidade de recursos por meio de parâmetros como Lista Negra e Especulação.

Integração ecológica envolvente

No ambiente Spark on K8s, logs e indicadores de monitoramento também são muito importantes. Eles podem nos ajudar a observar o status de execução de todo o cluster, contêiner e tarefa, localizar rapidamente problemas com base em logs e monitoramento e tratá-los em tempo hábil. . Portanto, um sistema Trace foi construído gradativamente durante o processo de nativação da nuvem Spark. O Arcee Operator e o agendador Gödel fornecem alguns indicadores de trabalho, o Spark fornece indicadores de negócios e o componente autônomo Metrics Collector fornece indicadores de máquinas físicas e indicadores de contêiner. Em termos de logs, o Log Agent em execução em cada nó coleta logs de caminhos especificados e os carrega automaticamente na plataforma de log para análise e consulta. Todos os indicadores e registros podem ser consultados em tempo real com base na plataforma de treinamento de aprendizado de máquina Arnold. Tabelas de dados específicas também são fornecidas. Os usuários podem realizar consultas de nível superior com base em suas necessidades, como produção de relatórios, otimização de trabalhos, descoberta de anomalias de trabalhos. etc. Ao mesmo tempo, Arnold também pode acompanhar as atualizações em tempo hábil por meio do gerenciamento de imagens.

Prática de raciocínio do modelo Wanka

Nossos clusters atuais são divididos principalmente em clusters offline e clusters online. O cluster offline concentra-se principalmente em tarefas de treinamento e concentra-se principalmente no rendimento de tarefas. Existem cartões como V100, A100 e A800. e se concentra na latência e na taxa de transferência, principalmente em placas menores, como T4, A10 e A30, com dezenas de milhares de placas GPU no total.

principal contradição

A principal contradição atual é que a cota do cluster offline foi totalmente alocada. Logicamente, os recursos foram alocados, mas ainda há muito espaço para melhorias na utilização geral do cluster offline. Além disso, existem muitas necessidades internas de computação que não foram atendidas. Por exemplo, nosso cluster é como um grande recipiente. Essas tarefas de alta qualidade são, na verdade, como pedras. As pedras podem estar cheias, mas ainda existem muitas lacunas entre as pedras. areia, portanto a nossa definição de problema é encontrar essas lacunas e preenchê-las com areia, ou seja, encontrar recursos reutilizáveis ​​adequados e propor tarefas adequadas.

recurso

Cluster offline: tarefas de baixa qualidade

A primeira são as tarefas de baixa prioridade no cluster offline. Esta parte está no cluster offline como um todo e não é sensível a atrasos. Usamos esses recursos ociosos com baixa prioridade e agendamos tarefas de baixa prioridade quando há tempo livre. Então, quando houver tarefas de alta prioridade, elas serão antecipadas. Ao mesmo tempo, estes são os recursos de todo o cartão e o seu fornecimento não tem regras óbvias, porque o envio offline em si não tem regras óbvias e o nível de isolamento geral é relativamente baixo.

Online -> Offline: Maré

A outra parte são os recursos de maré de online para offline. Esta parte requer o empréstimo dos recursos ociosos do cluster online para o cluster offline. Nós os implementamos com base no Virtual-Kubelet. aleatório Há um padrão óbvio com os altos e baixos do negócio. Quando o negócio online está no auge, os recursos são desocupados por meio de escalonamento automático e, em seguida, emprestados ao cluster offline. ser expandido novamente e o cluster expulsará o pod offline. Este é um nível de isolamento médio, o pod offline deve ser executado na mesma máquina, mas o cartão ainda pode ser isolado.

Online->Offline: Colocação normal

A outra parte são os recursos normais de co-localização de online para offline. Esta parte na verdade significa que emprestamos parte do poder de computação da GPU relativamente pouco utilizada no cluster online para o cluster offline. não use o cartão inteiro e esteja vazio. O poder de computação pode ser reutilizado e a implementação geral é baseada em Virtual-Kubelet + ByteCUDA + MPS.
ByteCUDA é um CUDA Hook autodesenvolvido. Ele realiza alguns trabalhos no isolamento de memória e na multiplexação por divisão de tempo na camada superior. O MPS da camada inferior melhora o nível geral de isolamento por meio da multiplexação por divisão de espaço. O que é emprestado é na verdade um recurso de cartão não integrado, ou seja, um cartão pode ser usado para diversas finalidades. Este cartão pode ter tarefas online e tarefas offline. A vantagem é que o volume de fornecimento é relativamente estável. Esta parte do serviço não se expande ou diminui automaticamente. Todos funcionam no mesmo cartão e têm o nível de isolamento mais alto.
Uma grande questão que temos sobre a co-localização normal é como evitar que o offline afete o online? Em primeiro lugar, o isolamento da memória e o isolamento do poder de computação devem ser feitos. Além disso, usamos um algoritmo de empréstimo dinâmico adaptável à carga, ou estratégia de empréstimo, para observar algum consumo de energia da GPU dentro de um período de janela e, em seguida, fazer julgamentos com base em. Esses indicadores deveriam nossos cálculos off-line evitar ativamente as solicitações de cálculo on-line para que o mundo on-line seja menos afetado?
Além disso, o MPS é famoso por seu problema de propagação de falhas. O problema mencionado acima é resolvido pela saída elegante. A partir das renderizações acima, podemos ver que a taxa de transferência on-line antes e depois da colocação permanece quase inalterada e o atraso aumenta em cerca de 0,75 ms. Na verdade, é aceitável. Sua taxa de utilização aumentou dos 10% originais para 70%. Isso tem um pequeno impacto na receita geral, mas a taxa de utilização melhorou bastante.

Tarefa

Depois dos recursos vêm as tarefas, que é o que chamamos de areia. A primeira é que sua demanda deve ser grande o suficiente, caso contrário não há necessidade de “mexer”. Além disso, porque estes são recursos fragmentados, o tamanho das tarefas necessárias deve ser relativamente moderado e não pode ser tarefas particularmente grandes. É necessário também que essas tarefas não possam consumir fortemente esses recursos não isolados, como discos, redes, etc., além disso, as tarefas também devem ser capazes de se adaptar à expansão e contração automática de recursos, pois esses recursos são elásticos; recursos e devem ser usados ​​automaticamente ao expandir tarefas. Os recursos, ao diminuir, não serão prejudicados por essa redução.

Tarefas de raciocínio offline baseadas em Spark

Com base nos requisitos de implementação acima, a tarefa de raciocínio offline baseada no Spark foi finalmente bloqueada. Primeiro, porque há um grande número de requisitos de raciocínio offline internos, a demanda é grande o suficiente, além disso, o processo da tarefa de raciocínio é relativamente simples; , e não há nada entre Executores Para necessidades de comunicação, não há necessidade de cartões online, RDMA, etc., além disso, uma grande quantidade de dados é armazenada em HDFS e Hive, que é naturalmente compatível com Spark; ao mesmo tempo, também precisamos usar os recursos de processamento e distribuição de dados do Spark e a capacidade de expandir e reduzir dinamicamente a capacidade com base na Alocação Dinâmica;

Compilação do SDK

Depois de bloquear a tarefa, o que precisamos fazer é encapsular as melhores práticas tanto quanto possível. Acima está um diagrama esquemático do SDK, que é um Tide Box que suporta inferências de modelos comuns, como Pytorch e Tensorflow, e também suporta. Pontos de verificação em nível de partição. Desta forma, não há necessidade de repetir cálculos quando os recursos são retirados, o que pode evitar o desperdício de poder computacional e melhorar a utilização geral dos recursos através do suporte ao Batching.

Construção de plataforma

Após a construção do SDK, a construção da plataforma também é um aspecto muito importante. Não queremos que os usuários executem comandos diretamente através do Spark Submit, o que é inconveniente de controlar. Portanto, a plataforma de aprendizado de máquina Arnold é usada como base para gerenciar esses recursos de maneira unificada. Com base no desenvolvimento e depuração do Notebook, as variáveis ​​necessárias podem ser definidas antecipadamente. Os usuários também podem depurar em uma única etapa, sem procurar manualmente por Enviar. . É relativamente conveniente alternar recursos em diferentes cenários ao mesmo tempo.
Além disso, o método de inicialização de tarefas pode suportar vários métodos, como acionamento de eventos upstream, acionamento de tempo, acionamento de API, etc., o que facilita o uso do usuário. Por exemplo, se quiser organizar alguns requisitos de pipeline ou automação do usuário, você pode implementá-los de maneira flexível por meio desses métodos. Além disso, a operação e manutenção de tarefas também é muito importante. Ele pode realizar a capacidade de visualizar tarefas históricas e retroceder problemas com um clique.

Correspondência tarefa-recurso

Existem muitos tipos de tarefas de inferência do Spark. Uma delas é a demanda de emergência repentina. Essa parte da demanda de recursos é relativamente grande, o tempo também é urgente e geralmente é uma demanda não convencional. Para esta parte, precisamos usar baixa otimização off-line. e o Tide é um recurso com placas mais integradas e maior poder computacional. Além disso, é necessário retroceder em lote tarefas que exigem reexecuções regulares, têm requisitos de recursos relativamente grandes e têm urgência média de tarefa, e usar esses recursos em implantações mistas normais e de maré. As tarefas de rotina podem ser de nível diurno e ter requisitos médios de recursos. Utilizaremos um fornecimento relativamente mais estável e mais estável de recursos normais de co-localização para apoiá-las.
O estado de pico do empréstimo online para o offline é de cerca de 10.000 GPUs Tide; a implantação mista normal é de cerca de 2.000+. Esta parte também se deve à implantação mista offline, a utilização geral dobrou, há cerca de 100 tarefas de inferência offline cada; dia, e uma única tarefa tem um limite máximo de 5K+ GPUs. Limitamos ativamente essa parte, caso contrário, os usuários podem aumentá-la ainda mais, resultando na ocupação de todos os recursos. Uma tarefa típica de limpeza de banco de dados requer recursos estáveis ​​para ser executada por 9,5 dias. Através deste recurso elástico, o cronograma foi reduzido para 7,5 horas para ser concluído.

perspectiva futura

No futuro, os nossos recursos flexíveis de co-localização terão de fazer mais, não só para melhorar a utilização global dos recursos, mas também para optimizar os recursos globais. Em primeiro lugar, tente evitar o impacto nas operações online, para que possa ser mais utilizado off-line e atingir uma taxa de utilização mais elevada. Além disso, ainda precisamos conectar mais empresas para expandir a escala geral e a receita. e, ao mesmo tempo, reduzir ou evitar, tanto quanto possível, problemas relacionados causados ​​pela reversão desnecessária de recursos.
Companheiro de frango, deepin-IDE de "código aberto" e finalmente conseguiu a inicialização! Bom cara, a Tencent realmente transformou o Switch em uma "máquina de aprendizagem pensante" Revisão de falhas e explicação da situação da Tencent Cloud em 8 de abril Reconstrução de inicialização de desktop remoto RustDesk Cliente Web Banco de dados de terminal de código aberto do WeChat baseado em SQLite WCDB inaugurou uma grande atualização Lista de abril TIOBE: PHP caiu para o nível mais baixo, Fabrice Bellard, o pai do FFmpeg, lançou a ferramenta de compressão de áudio TSAC , o Google lançou um grande modelo de código, CodeGemma , isso vai te matar? É tão bom que é de código aberto - ferramenta de edição de imagens e pôsteres de código aberto
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/5941630/blog/10581528
Recomendado
Clasificación