2 pontos por darjeeling 1 시간 전 | 1 comentários | Compartilhar no WhatsApp

Compartilha o processo de reprodução e correção de dois bugs de condição de corrida no KV Cache encontrados ao operar um Coding Agent baseado no GLM-5 na escala de centenas de milhões de execuções, além de otimizações para melhorar a vazão.

Contexto

As leis de escalabilidade (Scaling Laws) não impulsionam apenas a inovação em parâmetros de modelo e volume de dados, mas também levam a engenharia de infraestrutura ao limite. A Z.ai chama os efeitos colaterais desse processo de Scaling Pain.

Ao processar diariamente centenas de milhões de workloads complexas de Coding Agent com a série GLM-5, foram relatados por alguns usuários fenômenos anormais como saída corrompida (garbled output), geração repetitiva e geração de caracteres raros. Esses problemas não eram reproduzidos de forma alguma em ambientes padrão de inferência e apareciam apenas em cenários de alta concorrência e contexto longo.


Resumo dos principais resultados

Item Número
Taxa de saídas anormais após aplicar o Bug Fix #1 0.1% → menos de 0.03%
Melhoria de vazão com LayerSplit (40K~120K tokens) +10% ~ +132%
Correção do HiCache contribuída como SGLang PR #22811

Detecção de anomalias: uso de métricas de Speculative Decoding

Detectar automaticamente esses fenômenos anormais já era, por si só, um grande desafio. Heurísticas como expressões regulares geravam muitos falsos positivos e falsos negativos, e classificadores baseados em modelo tinham custo alto demais para experimentos em larga escala.

A saída veio das métricas de Speculative Decoding.

  • Saída corrompida / caracteres raros: spec_accept_length extremamente baixo → sinal de inconsistência no estado do KV Cache entre o modelo draft e o modelo target
  • Geração repetitiva: spec_accept_rate extremamente alto → sinal de que, por causa de um KV Cache corrompido, o padrão de atenção converge para um loop repetitivo

Com base nisso, foi implementada uma estratégia de monitoramento online. Quando a geração ultrapassa 128 tokens, se spec_accept_length < 1.4 ou spec_accept_rate > 0.96, a geração é interrompida imediatamente e o retry é repassado ao load balancer. Na prática, o Speculative Decoding foi expandido de ferramenta de otimização de desempenho para ferramenta de monitoramento em tempo real da qualidade de saída.


Bug Fix #1: condição de corrida no KV Cache da arquitetura PD separada

Causa

Na arquitetura separada de PD (Prefill-Decode), há um mecanismo de interrupção de requisição baseado em timeout para controlar tail latency. Se o Prefill não termina dentro do tempo definido, o lado de Decode aborta a requisição e recupera o KV Cache.

O problema é que o sinal de abort não era transmitido corretamente ao lado de Prefill. Mesmo depois de o Decode recuperar o KV Cache e realocá-lo para uma nova requisição (Req2), o RDMA write e a computação de Prefill da requisição anterior (Req1) continuavam, fazendo com que o KV Cache de Req2 fosse sobrescrito.

Correção

Após emitir o abort, o Decode passou a enviar uma notificação ao lado de Prefill, e o Prefill foi alterado para retornar um sinal de "seguro para recuperar" somente quando uma das duas condições abaixo for satisfeita.

  1. O RDMA write ainda não começou
  2. Todos os writes já emitidos foram concluídos

O Decode reutiliza o KV Cache apenas depois de receber essa confirmação. Como resultado da aplicação, a taxa de saídas anormais caiu de 0.1% para menos de 0.03%.


Bug Fix #2: ausência de garantia da ordem Load-Use no HiCache

Causa

O workload de Coding Agent tem comprimento médio de entrada acima de 70K tokens e alta taxa de reutilização de prefixo. Para isso, é usado o HiCache (KV Cache hierárquico), numa estrutura em que o KV Cache é trazido da memória da CPU de forma assíncrona enquanto Load Stream e Forward Stream são executados de forma sobreposta.

O problema era que o kernel Indexer não explicitava a restrição de sincronização com a conclusão do carregamento do cache do Indexer. Se o Forward Stream começasse a executar antes do Load Stream, surgia um padrão de read-before-ready, em que se lia um KV Cache ainda não carregado, levando às saídas anormais.

Correção

Antes da execução do kernel Indexer, foi inserido um ponto explícito de sincronização com o Load Stream, garantindo que o Forward Stream só prossiga com o cálculo após os dados estarem prontos. Essa correção foi contribuída para a comunidade SGLang como o PR #22811.


Otimização: LayerSplit (armazenamento distribuído de KV Cache por camada)

O gargalo comum entre os dois bugs era a própria carga da etapa de Prefill. Para melhorar isso de forma estrutural, foi projetado e implementado o LayerSplit.

Antes, em um ambiente de Context Parallelism (CP), cada GPU armazenava de forma redundante o KV Cache de todas as camadas. No LayerSplit, cada GPU passa a armazenar de forma distribuída apenas parte das camadas, reduzindo fortemente o uso de memória por GPU.

Durante a execução, o rank de CP que possui o KV Cache da camada correspondente faz o broadcast do cache antes da operação de atenção. O broadcast foi sobreposto à operação do indexer para ocultar o overhead de comunicação, e como os dados adicionais de comunicação se limitam ao indexer cache (cerca de 1/8 do tamanho do KV Cache), o overhead total é desprezível.

Com taxa de cache hit de 90%, a vazão para requisições de 40K~120K tokens melhorou em 10%~132%, e quanto maior o contexto, maior o ganho.


Conclusão

"Vazão, latência e disponibilidade não bastam. O sistema também precisa garantir a correção do estado do modelo por trás de cada requisição de geração. As leis de escalabilidade ampliam a capacidade, mas fazer essa capacidade ser confiável em larga escala depende apenas de uma engenharia de sistemas rigorosa."


Fonte: Z.ai Research Blog (2026-04-30)

1 comentários