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_lengthextremamente baixo → sinal de inconsistência no estado do KV Cache entre o modelo draft e o modelo target - Geração repetitiva:
spec_accept_rateextremamente 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.
- O RDMA write ainda não começou
- 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
LINK DO PR https://github.com/sgl-project/sglang/pull/22811