Roteamento de inference de LLM em produção: dos sinais do engine à política — Qianru Lao e Lu Zhang, OpenAI
Autoria: AI Engineer · Assistir no YouTube
Vídeo de autoria do canal indicado, não da IANIA; todos os direitos pertencem ao criador. Transcrição, resumo e tradução gerados automaticamente; o conteúdo no idioma original é preservado na versão em idioma original.
Idioma original: inglês
Vídeo original: Routing LLM Inference in Production: From Engine Signals to Policy — Qianru Lao & Lu Zhang, OpenAI · Canal: AI Engineer · 17:22 · Assistir no YouTube
Tópicos: Engenharia de software com IA, Inferência e otimização de modelos, Infraestrutura e hardware de IA
Qianru Lao e Lu Zhang apresentam a evolução do sistema de roteamento de inference da OpenAI, desde um mecanismo adaptativo baseado em feedback dos engines até uma arquitetura com control plane e data plane separados. O sistema combina sinais em tempo real, capacidade, latência de rede e localidade do KV cache para distribuir solicitações entre engines. Um otimizador calcula pesos de roteamento para minimizar a latência total, respeitando restrições de capacidade. A apresentação também explica mecanismos de proteção, como redução de peso para engines problemáticos, limites de retries e load shedding.
Pontos-chave
Seção intitulada “Pontos-chave”- O inference load balancer seleciona um engine para cada solicitação e encaminha a solicitação até ele.
- O roteamento precisa levar em conta sinais como TTFT, TBOT, utilização, saúde dos engines e localidade do KV cache.
- O método inicial ajustava pesos de roteamento com um ciclo de feedback baseado no desempenho observado em relação à média da frota.
- Embora adaptável, o ciclo de feedback dificultava explicar decisões, ajustar aspectos isolados e evitar oscilações que prejudicam o uso do cache.
- Na nova arquitetura, o control plane calcula uma visão global do roteamento e o data plane toma decisões rápidas usando o estado local mais recente.
- Os sinais dos engines e as atualizações de pesos são processados de forma assíncrona, sem esperar pelo control plane a cada solicitação.
- O otimizador busca minimizar a latência total, incluindo tanto a latência de rede quanto a latência no engine.
- O roteamento precisa atender à demanda, manter os engines dentro da capacidade efetiva e usar pesos não negativos.
- Mecanismos de proteção incluem penalidades para engines fora do padrão, limites dinâmicos de retries e load shedding para degradar o serviço de forma controlada.
Capítulos
Seção intitulada “Capítulos”| Início | Capítulo | Resumo |
|---|---|---|
| 00:12 | O inference load balancer e o roteamento inicial | A apresentação introduz a função do balanceador e descreve como o sistema inicial selecionava engines usando pesos ajustados por feedback de desempenho. |
| 07:22 | Arquitetura com control plane e data plane | A nova arquitetura separa a otimização global das decisões rápidas por solicitação e processa as atualizações de forma assíncrona. |
| 12:15 | Otimização da latência total | O exemplo de tráfego entre regiões mostra por que escolher sempre o engine mais próximo pode ser pior do que considerar capacidade e espera. |
| 15:38 | Proteções para estabilidade em produção | Os palestrantes explicam como penalidades, limites de retries e load shedding ajudam a manter o sistema estável sob falhas e sobrecarga. |
Citações
Seção intitulada “Citações”A combinação de desempenho, confiabilidade, localidade e consciência do cache é o que torna esse problema tão interessante. — 02:58
É muito difícil entender uma decisão específica de roteamento ou por que um engine recebeu um peso maior do que esperávamos. — 06:17
Um engine mais distante pode ser mais rápido no total. — 12:46
A latência total inclui tanto a distância da rede quanto a latência do lado do engine. — 14:27
Degradamos o sistema de forma controlada, em vez de deixar tudo falhar. — 16:49
Conceitos e entidades
Seção intitulada “Conceitos e entidades”- OpenAI (empresa): Empresa cujas equipes de inference desenvolveram o sistema de roteamento discutido na apresentação.
- Qianru Lao (pessoa): Palestrante da OpenAI que apresenta a arquitetura de control plane e data plane e o otimizador de roteamento.
- Lu Zhang (pessoa): Palestrante da OpenAI que apresenta a evolução do roteamento e os mecanismos de proteção do sistema.
- inference load balancer (conceito): Componente que seleciona um engine para cada solicitação e a encaminha até ele.
- control plane (conceito): Parte da arquitetura que reúne sinais e calcula pesos de roteamento com uma visão global do sistema.
- data plane (conceito): Parte da arquitetura que seleciona engines rapidamente usando o estado de roteamento instalado localmente.
- KV cache (conceito): Cache que pode guardar contexto útil da conversa em um engine e evitar recomputação em solicitações seguintes.
- TTFT (conceito): Métrica de latência que indica o tempo até a geração do primeiro token.
- TBOT (conceito): Métrica de latência entre tokens de saída, usada para caracterizar o desempenho do engine.
- weighted consistent hashing (conceito): Método inicial de seleção que combinava hashing consistente com pesos atribuídos aos engines.
- load shedding (conceito): Mecanismo que descarta proativamente parte do tráfego quando a demanda ultrapassa a capacidade disponível.
Tradução completa (pt-BR)
Seção intitulada “Tradução completa (pt-BR)”00:12 Oi, pessoal, obrigado por participarem da nossa palestra. Eu sou Lou e este é meu colega Chenu. Hoje, nós dois trabalhamos na equipe de inference da OpenAI e vamos falar sobre o roteamento de inference de LLM em produção, especificamente sobre como nosso sistema evoluiu do roteamento baseado em ciclos de feedback impulsionados por sinais do engine para uma política mais explícita e previsível, que ainda é informada por sinais do engine. No entanto, a forma como usamos esses sinais é diferente. Quanto à agenda de hoje, vamos começar…
00:45 …apresentando o balanceador de carga de inference: o que é, o que faz e como evoluiu. Depois, Chenu vai nos apresentar a arquitetura mais recente, orientada por control plane e data plane: quais são as responsabilidades de cada um. Em seguida, veremos um estudo de caso concreto de como reduzimos a sobrecarga da rede global. Por fim, volto para discutir os mecanismos de proteção que ajudam a manter o sistema estável sob carga de produção. Para começar, o que é o balanceador de carga de inference e onde ele fica? Então, este…
01:20 …é um diagrama de alto nível do sistema de que estamos falando. À esquerda estão os clusters de frontend. Eles são os clusters de CPU — desculpem, são os clusters de CPU que funcionam como gateways para o nosso sistema. Eles recebem as solicitações dos usuários e, em seguida, as preparam como solicitações de inference que podem ser processadas pelos engines de inference. À direita estão os clusters de engine, que geralmente são clusters de GPU e cada um hospeda vários…
01:53 …engines de inference. Por isso, eles receberam o nome de clusters de engine. E, como talvez vocês já tenham ouvido, hoje em dia as GPUs são muito populares e caras. No meio fica o IRB, ou balanceador de carga de inference. Na verdade, ele é executado nos clusters de frontend, mas também serve de ponte para a nossa pilha de inference. Ele tem duas responsabilidades principais: selecionar um engine e encaminhar a solicitação. Nesta palestra, vamos nos concentrar na seleção do engine. De certa forma,…
02:25 …o IRB se parece com um balanceador de carga tradicional, porque uma solicitação normalmente tem como alvo um modelo, e esse modelo é atendido por vários engines. Eles podem estar em clusters diferentes, em regiões diferentes ou até em continentes diferentes, o que nos dá boa resiliência diante de degradações localizadas ou falhas de cluster. No entanto, a pilha de inference, ou as particularidades da inference, introduz muitas nuances. Por exemplo, é preciso considerar vários sinais…
02:58 …informados em tempo real, como o conhecido time to first token (TTFT), o tempo entre tokens de saída, também conhecido como throughput de tokens ou time between tokens, além de sinais de harness e utilização. Além disso, há um conceito importante, o KV cache, que também é bastante conhecido. Por exemplo, quando a conversa já tem muito contexto útil armazenado em cache em um engine, enviar as próximas interações da mesma conversa de volta para esse engine evita recalcular esse conteúdo, melhora a eficiência e reduz a latência. Então, a…
03:33 …combinação de desempenho, confiabilidade, localidade e consciência do cache é o que torna esse problema tão interessante. Então, como abordamos esse problema? Vamos dar uma olhada nos primeiros dias. E, para ser sincero, dizer “os primeiros dias” neste setor soa muito mais histórico do que realmente é. Naquela época, o processo de roteamento começava com a preocupação de que nem toda solicitação pudesse ser atendida por todos os engines, por causa de restrições como capacidades ou limitações…
04:06 …relacionadas a computação ou à residência de dados. Entre os engines restantes, o IRB usava hashing consistente ponderado para selecionar o melhor engine de destino para uma solicitação ou para determinado usuário. A pergunta importante, então, é: de onde vêm os pesos? Eles eram gerados por um ciclo de feedback periódico. Como mencionei antes, os engines de inference informam todo tipo de sinal que nos interessa, e o controlador suaviza esses sinais periodicamente e calcula uma…
04:40 …pontuação de desempenho. Essa pontuação era então comparada com a média da frota. Depois, o peso era ajustado para cada engine, basicamente: o peso aumentava se o desempenho fosse melhor e diminuía se fosse pior do que a média da frota. Esse peso gerado influenciava o roteamento. Conceitualmente, isso é semelhante a um controlador P. E não, esse controlador P não ajuda você a gerenciar um processo Linux; é uma técnica clássica da teoria de controle que…
05:12 …direciona continuamente o sistema para o estado desejado. Nós simplesmente pegamos esse conceito importante, a parte proporcional, e o aplicamos ao nosso balanceador de carga. Isso tem várias propriedades interessantes. Por exemplo, ele pode combinar os sinais úteis que nos interessam em uma única decisão de roteamento e, como se adapta ao desempenho observado, conforme mencionei antes, há muitas restrições. Essas restrições podem fazer com que alguns engines fiquem mais ocupados, porque conseguem atender mais solicitações ou mais tipos de solicitação do que os demais. Mas esses sinais de ocupação são incorporados ao ciclo seguinte, fazendo com que solicitações com menos restrições possam ir para mais engines desse tipo. Assim, o sistema se equilibra sozinho e, até certo ponto, isso significa que não precisamos fazer muita intervenção manual: simplesmente funciona. No entanto, essa adaptabilidade vem com grandes concessões…
05:44 …pelas mesmas razões que permitem combinar tantos sinais. Também é muito difícil entender uma decisão de roteamento específica ou, por exemplo, por que determinado engine recebeu um peso maior do que esperávamos. E, sempre que queremos fazer fine-tuning em algum aspecto, é quase impossível não afetar outra coisa. Além disso, a carga nem sempre fica muito bem distribuída de maneira uniforme, porque, às vezes, um modelo é atendido por engines em diferentes tipos de GPU, que têm características diferentes. Aí…
06:17 …o problema fica muito mais complicado, e o ciclo de feedback às vezes cria oscilações ruins. Quando você desvia parte do tráfego de um engine, ele fica um pouco mais ocioso, e esse sinal é enviado ao controlador. O controlador então pensa: “Esse engine pode receber muito mais tráfego”. Aí parte do tráfego volta a ser direcionada para ele, ficando alternada entre alguns engines e prejudicando a utilização do KV cache. Todas essas limitações…
06:51 …nos levaram a repensar a arquitetura e a ver se havia novas maneiras de resolver o problema. Vou passar a palavra a Chenu para que ele explique em detalhes a nova arquitetura que testamos. >> Sim, obrigado, L. Vou falar sobre a arquitetura do balanceador de carga e sobre como reduzimos a sobrecarga geral com nosso algoritmo de roteamento. O balanceador de carga responde a uma pergunta…
07:22 …para cada solicitação vinda de um cluster de CPU: qual engine deve atendê-la? Uma abordagem básica e ingênua seria o round robin, que distribui as solicitações igualmente entre os engines. Mas, se você pensar um pouco, isso não faz sentido, porque os engines não são homogêneos: podem ter hardware e capacidade diferentes, estados de saúde diferentes e também distâncias diferentes em relação ao cluster de CPU. Além disso, o round robin pode prejudicar a localidade do cache: solicitações relacionadas que poderiam reutilizar o cache do…
07:53 …mesmo engine talvez sejam enviadas para engines diferentes. Uma solução provavelmente melhor seria cada cluster de CPU escolher o melhor engine com base na própria visão local. Mas isso também não basta. Pense em um caso extremo: vários clusters de CPU direcionam tráfego para os mesmos engines de forma independente, o que pode sobrecarregar esses engines e deixar os demais subutilizados. Então, o que precisamos é de uma solução…
08:26 …otimizada globalmente: um control plane que tenha uma visão global de todos os clusters de CPU e engines de GPU e possa calcular respostas de roteamento otimizadas globalmente; e o data plane pode tomar decisões de roteamento rapidamente com base na resposta fornecida pelo control plane. Agora, vamos examinar o control plane e o data plane. No data plane, há um seletor de engine que escolhe um engine para cada solicitação. Ele lê o…
08:56 …estado de roteamento local, que inclui os engines candidatos e os pesos de roteamento de cada um deles. Ambos são atualizados de forma assíncrona em segundo plano. Assim, não precisamos consultar o control plane antes de tomar uma decisão de roteamento para cada solicitação. O data plane também coleta sinais dos engines em tempo real, como o número de réplicas prontas e o estado de saúde dos engines, para apresentar ao control plane sinais rápidos de proteção local. O carregador de dados…
09:30 …
10:03 combina esses sinais do mecanismo em tempo real, sem sobrecarga. Com regressões offline de capacidade, TTFT e TBOT, o otimizador pode transformar esses dados em pesos de roteamento, e o plano de controle publica o peso de roteamento para cada plano de dados buscar. Assim, nenhuma solicitação precisa esperar no plano de dados. O plano de controle calcula continuamente o próximo snapshot de roteamento otimizado globalmente, enquanto o plano de dados toma uma decisão de roteamento com base no mais recente
10:37 snapshot já instalado localmente. Em resumo, há três caminhos importantes no sistema. O primeiro é o caminho da solicitação de inference. A solicitação chega ao cluster de CPU, e o plano de dados dentro desse cluster seleciona um mecanismo para atendê-la com base no estado de roteamento local e encaminha a solicitação aos mecanismos selecionados. O segundo é o caminho dos sinais dos mecanismos. O sistema coleta continuamente sinais em tempo real dos mecanismos, como TTFT,
11:12 TBOT, número de réplicas de rádio e ocupação do mecanismo, entre outros. Os dois planos precisam desses sinais dos mecanismos em tempo real. O plano de controle precisa deles para calcular um roteamento otimizado globalmente, enquanto o plano de dados precisa deles para atender às solicitações com rapidez localmente. E o terceiro é o caminho dos pesos de roteamento. O plano de controle calcula e publica os pesos de roteamento, e o plano de dados busca as atualizações em seu cache local. Portanto, apenas o primeiro caminho é síncrono,
11:44 mas é rápido e ocorre apenas localmente, dentro do plano de dados do cluster de CPU. Os outros dois ciclos são assíncronos e servem para melhorar as decisões de roteamento futuras. Essa é basicamente a parte da arquitetura. Mas ainda resta uma pergunta: como calculamos esses pesos de roteamento? Antes de responder a essa pergunta, vamos primeiro responder a outra: por que não
12:15 simplesmente enviar uma solicitação ao mecanismo mais próximo? Porque a demanda de tráfego e a capacidade das GPUs não são equilibradas geograficamente. Por exemplo, na região um, o cluster de CPU A envia 90 RPS, e o mecanismo A próximo pode atender 100 RPS. Nesse caso, escolher apenas o mais próximo funciona bem. Já na região dois, o cluster de CPU B envia 120 RPS, e o mecanismo B próximo só pode atender 100 RPS. Portanto, se insistirmos em manter tudo local,
12:46 os 20 RPS excedentes terão de esperar em um mecanismo B sobrecarregado. Já na região três, estamos usando apenas 40 RPS de um mecanismo C que suporta 80 RPS. Isso deixa 40 RPS de capacidade disponível. Se enviarmos os 20 RPS excedentes do cluster B ao mecanismo C, isso aumentará a distância de rede.
13:17 Mas também pode evitar um tempo de espera muito maior no mecanismo. Nesse caso, um mecanismo mais distante pode ser mais rápido de ponta a ponta. É por isso que precisamos de algo melhor do que o roteamento que escolhe apenas o mecanismo mais próximo. Agora vamos abrir a caixa-preta do otimizador. O otimizador recebe quatro tipos de entrada: as solicitações de cada cluster de CPU, a latência de rede até cada mecanismo, a capacidade disponível dos mecanismos
13:52 e a integridade, além dos perfis de latência de TTFT e TBOT, que nos dizem como a latência do lado do mecanismo muda à medida que a carga aumenta. Com essas entradas, o otimizador gera os pesos de roteamento. Os pesos de roteamento indicam, para cada cluster de CPU, que fração do tráfego deve ser direcionada a cada mecanismo de GPU. E o objetivo da otimização é simples: minimizar a latência esperada de ponta a ponta em todo o tráfego
14:27 roteado. O importante é que a latência de ponta a ponta inclui tanto a distância de rede quanto a latência do lado do mecanismo. Isso significa que um mecanismo próximo pode ser atraente quando ainda tem capacidade para atender ao tráfego, enquanto um mecanismo mais distante pode ser melhor se todos os mecanismos próximos estiverem quase lotados. O otimizador também precisa respeitar várias restrições rígidas. Primeiro, precisa rotear toda a demanda de tráfego. Segundo, precisa garantir que todos os mecanismos permaneçam
15:02 dentro da capacidade efetiva. Terceiro, precisa manter os pesos de roteamento não negativos. Com isso, o plano de controle recebe do otimizador os pesos de roteamento e os publica; o plano de dados os busca e os usa para tomar decisões de roteamento otimizadas globalmente. Essa é basicamente a minha parte, e Lu vai continuar falando sobre os mecanismos de proteção do sistema. Obrigada, Chenu. Como engenheiros de IA, todos nós
15:38 sabemos, de certa forma, que em muitos casos os ambientes de produção não se comportam da maneira ideal. Os clusters podem falhar, as GPUs ou nós individuais podem ter o desempenho degradado, e a rede pode apresentar todo tipo de problema misterioso. Então, como mantemos nosso sistema de produção o mais resiliente possível sob carga pesada? A primeira coisa que temos são as penalidades. Basicamente, quando um mecanismo é um ponto fora da curva, detectamos isso e tentamos reduzir o peso de roteamento atribuído a ele. Dessa forma, nós
16:15 damos a ele a chance de se recuperar sozinho, caso seja um problema temporário, ou podemos pedir a intervenção de uma pessoa ou substituir o hardware defeituoso. Em segundo lugar, temos as novas tentativas, uma técnica muito comum para mitigar problemas. No entanto, em alguns casos, elas podem piorar a situação, como quando o sistema está muito perto de entrar em colapso ou está muito carregado. As novas tentativas adicionam mais carga, e essa carga adicional causa
16:49 mais falhas e mais novas tentativas, o que é conhecido como tempestade de novas tentativas. Por isso, implementamos limites ou orçamentos para manter as novas tentativas dentro de uma faixa aceitável. Isso precisa até ser dinâmico, porque em condições normais podemos tolerar muito mais novas tentativas do que quando o sistema está muito carregado. Por fim, temos o descarte de carga, nosso último recurso quando a capacidade de produção não consegue atender à demanda crescente
17:22 por inference. Em vez de deixar todo o sistema falhar, descartamos proativamente uma parte do tráfego para que o sistema se degrade de forma gradual. Isso conclui nossa palestra de hoje. Obrigada por participar. Nós dois estaremos na área do nosso estande esta tarde. Se tiver mais perguntas, fique à vontade para ir até lá e conversar conosco. Obrigada. [aplausos]
Transcrição original
[00:12] Hi everyone, thanks for joining our talk. I’m Lou and this is my colleague Chenu. So we today we’re going to talk about the in uh we both work on the inference team at OpenAI and today we are going to talk about routing IM inference in production specifically how our system evolved from routing based on feedback loops driven by engine signals to a more explicit and a predictable policy which is still informed by engine signals. However, it’s more like the way we use it is different. So uh for the agenda today we’re going
[00:45] to begin by introducing the inference load balancer what it is what it does and how it has evolved and then Chenu will walk us through the newer control plane and data plane driven architecture uh what are the responsibilities of each and followed by a concrete case study of how we reduce the global network overhead and in the end I return to discuss the protection mechanisms that help keep the system stable and production level stress. So to begin with what is the inference load balancer and where it sit? So this
[01:20] is a very high level diagram of the system we are talking about. On the left hand side are the front end clusters. Those are the GPU cluster. Sorry, those are the CPU clusters that act as gateways into our system and they receive user requests then prepare them into the inference request that can be processed by the inference engines and on the right hand side are the engine clusters uh which are usually GPU clusters and each hosting multiple
[01:53] inference engines. So that’s why we they got the name of engine clusters and as you may already heard nowadays GPUs are pretty popular and expensive. So um sitting in the middle it is the IRB or inference load balancer. It actually runs on the front end clusters but is also a bridge into our inference stack. It has two main responsibilities select an engine and proxing the request. For this talk, we are going to focus on the engine selection part. So in some ways,
[02:25] IRB resembles a very traditional load balancer because a request usually targets a model and a model is backed by multiple engines. They may live on different clusters in different regions or even across the continents because that gives us a good resiliency towards localized degradation or cluster failures. However, the inference uh stack or the uniqueness of the inference introduces a lot of nuances like uh it has to consider a bunch of signals
[02:58] reported in real time like the well-known time to first token TTF time between output tokens also known as token throughput or time between tokens and other hairness and utilization signals. Besides there’s a important concept of a KV cache which is also well known but for example when the conversation already has a lot of the useful context cached in one engine sending the follow-up turns of the same conversation back to the same engine will avoid recomputation improve efficiency and uh reduce latency. So the
[03:33] combination of performance reliability locality cach awareness is what makes it such an interesting problem. Uh so how we attempted in the problem? Let’s take a look at the early days. And to be honest, early days in in this industry sounds a lot more historic than it really is. And the routing process at that time began with a fear of like each request may not be served by all the engines because of uh constraints such as capabilities or due uh restrictions
[04:06] due to compute or data residency. And among the remaining engines, IRB used a weighted consistent hashing to select the best destination engine for a request or of for certain user. Then the important question becomes where are the WS come from. So they were generated by a periodic feedback loop. The inference engines as mentioned earlier uh reports all kind of the signals we care about and the controller will periodically smooth out those signals and compute a
[04:40] performance score. The performance score then will be compared against the fleet average. Then the weight will be adjusted basically for each engine. is weight goes up if the performance is better or it goes down when the performance is worse than the fleet average and this generated weight will impact the routing and then it’s basically a uh control loop um conceptually it is very similar to the P controller and no this P controller will
[05:12] not help you care a Linux process but instead it’s a classic control theory technique that continuously steering the system towards its desired date and we just borrowed this important concept the proportional part of it and uh applied into our uh our load balancer. So it has a lot of nice properties. For example, it could combine the useful signals we care about into the single routing decision and because of the it adapt to the observed performance as what we
[05:44] mentioned earlier there’s a lot of constraints and those constraints might have the some engines basier because they can serve more requests more kind of request than the remaining but those basier signal will be fit into the next loop and resulting in the less constraint less constraint request can go to more of those kind of engines. So basically they self balanced out and to some extent this just means we don’t need to do a lot of manual intervention and it just works. However that kind of adaptability comes with big trade-offs
[06:17] because of the same reasons that it combined so many signals. It’s also very hard to reason about a particular routing decision or like why search engine get a higher weight than we expect. And every time we want to fine-tune towards some aspect, it’s all almost impossible to not impacting something else. And the load is not always very well very evenly distributed because uh sometimes a model is served by engines on different GPU skills and they have different characteristics. Then the
[06:51] problem becomes a lot more trickier and the feedback loop sometimes creates bad oscillations because when you shift an engine away some traffic the engine turns a bit cooler and this signal get fit to the controller. The controller now thinks that hey this engine can take a lot more traffic. then the some traffic going to be shifted back and forth between a few engines and disrupting the KV cache utilization. So all those limitations
[07:22] motivated us to rethink about the architecture and uh see if we have new ways to address the problem. So I’m going to hand over to Chenu to uh deep dive into the new architecture we tried out. >> Yeah, thank you L. So I’m going to talk about the architecture of the load balancer and how do we reduce the overall overhead with our routing algorithm. The load balancer answers one question
[07:53] uh for each request from a CPU cluster which engine should serve it. One most naive baseline might be round robin which send requests across engines evenly. But if you think a little bit more that doesn’t make sense because engines are not homogeneous they can have different hardware and capacity different health and also different distance from CPU cluster also run could break cache locality c related requests that could reuse the
[08:26] same engine cache might be sent to different engines. A probably better solution might be for each CPU cluster it choose the best engine from its own local view. But that’s not enough either. Think about one extreme case. Multiple CPU cluster route traffic to the same engines independently which could overload that engine while leave other engines underutilized. So what we need is a globally optimized
[08:56] solution, a control plane that has a global view for all the CPU cluster and GPU engines and could compute a globally optimized routing answers and the data plane can make a routing decision quickly based on the answer proved from the control plane. Now let’s look inside the control plane and data plane. In the data plane there is an engine selector which select engine for each request. It read the
[09:30] local routing state which includes the candidate engines and the routing weights for each candidate engines. Both of them are refreshed asynchronously in the background. So we don’t need to ask the control plane before we make a routing decision for each request. Also the data plane collects realtime engine signal such as number of ready replica engine house etc to surface fast local guard draw in the control plane. The data loader
[10:03] combines those live engine signals and never overhead. And with offline regressions of capacity, TTFT and TBOT, the optimizer could turn those data into routing weights and the control plane will publish the routing weight for each data plane to pull. In this way, no request need to wait on the data plane. The control plane continuously compute the next globally optimized routing way snapshot while the data plane make a routing decision based on the latest
[10:37] snapshot already installed locally. In summary, there are three important paths through the system. The first path is the inference request path. The request arrive to the CPU cluster and the data plane inside that CPU cluster will select engine for that request based on the local routing state and forward the request to the selected engines. The second pass is the engine signal pass. The system continuously collects real-time engine signal such as TTFT,
[11:12] TBOT, number of radio replica and engine house etc. Boost planes need those real-time engine signals. The control plane need them to compute a globally optimized routing way while the data plane need them to serve as fast local. And the third path is the routing way pass. The control plane compute and publish the routing way and the data plane pull the updates to its local cache. So only the first pass is synchronous
[11:44] but it’s fast and only local inside the data plane of the CPU cluster. The other two loops are asynchronous loop and they are to improve future routing decision. So that’s pretty much of the architecture part. But that still leaves one question. How do we compute those routing weights? But before answer that question, let’s answer another question first. Why not
[12:15] just send a request to the nearest engine? That’s because the traffic demand and GPU capacity are not geographically balanced. For example, in region one, CPU cluster A send 90 RPS and the nearby engine A can serve 100 RPS. So in this case nearest only is fine while in region two CPU cluster B send 120 RPS and the
[12:46] nearby engine B could only serve 100 RPS. So in this case if we insist on keeping everything local the extra 20 RPS need to wait on an overloaded engine B. While in region three we are only using 40 RPS of an 80 RPS engine C. That still leaves 40 RPS spare. So if we send the extra 20 RPS from cluster B to engine C, that will add network distance.
[13:17] But it could also avoid a probably much larger engine side waiting time. So in this case, a further engine might be faster end to end. That’s why we need something better than the nearest only routing. Now let’s open the black box of the optimizer. The optimizer accepts four types of input. The request from each CPU cluster, the network latency to each engine, the available engine capacity
[13:52] and health and also the TTFT, TBOT latency profiles that tell us how’s the engine side latency change as the low increases. And with those input the optimizer turn the input to the output routing weights. The routing way say for each CPU cluster what fraction of its traffic should go to each GPU engine. And the optimization goal is straightforward is to minimize the expected end to end latency across all
[14:27] routed traffic. The important part is that the end to end latency includes both the network distance and the engine side latency. That means a nearby engine might be attractive when it still has room to serve traffic while a further engine might be better if all the nearby engines are close to full. And the optimizer also need to respect several hard constraints. First it need to route all the traffic demand. Second it need to ensure all the engines stay
[15:02] within the effected capacity. Third it need to keep the routing weights non- negative. With this the controller control plane get the routing way from the optimizer and publish them and the data plane pull them and use them to make a globally optimized routing decision. And that’s pretty much of my part and Lou will continue to talk about the protection mechanisms in the system. Thanks Chenu. So as AI engineers we all
[15:38] kind of know that production in many cases are not behaving in the most ideal case. So clusters can fail, GPUs or individual nodes can degrade degree and networking can just get to all kind of mysterious issues. So how do we keep our production system uh heresy as much as possible under the heavy load? The first thing we have is the penalties. Basically when an engine is an outlier, we detect the try to reduce the routing weight to that engine. In that way, we
[16:15] give it a chance to either recover by themselves if there’s a uh if it’s some transient issue or we can have a human intervented out or replace the faulty hardware. And secondly, the retries which is a very common technique used to mitigate a problems. However, during some cases, it’s actually could make them even worse like when the system is very close to like a tip over or very heavy utilized retries, we are send more load and this more load we are cause
[16:49] more failure and cause more retries which is infamous retry storm. So we incre implemented caps or budget to constant retries into a acceptable region and this is actually even need to be dynamic because in the happy time or in the normal time we can tolerate a lot more retries than when the system are heavily utilized. And finally we have the load shedding which is our last result when the production capac uh capacity couldn’t meet the increasing
[17:22] amount of inference demands. So we instead try to have all the system fail. We basically proactively load shed a portion of the traffic to have the system degraded gracefully. So that pretty much concludes our talk today and uh thanks for joining us. Uh both of us will be around in our uh booth area this afternoon. So if you have further questions, feel free to walk uh to the area and and chat with us. Thank you. [applause]