Comunicación punto a punto RDMA para sistemas LLM

Herdanza elegante para patróns de comunicación LLM emerxentes

AutoresPerplexity Research

Os sistemas de LLM tradicionalmente baseáronse en comunicacións colectivas para patróns paralelos estruturados no adestramento e na inferencia. Porén, as cargas de traballo emerxentes, como a inferencia desagregada, o encamiñamento de mestura de expertos (MoE) e a axuste fina por aprendizaxe por reforzo asincrónica, demandan a flexibilidade da comunicación punto a punto.

O noso artigo de investigación máis recente presenta TransferEngine, unha biblioteca de comunicación portátil baseada en RDMA que funciona en diferentes controladores de interface de rede (NIC), incluíndo NVIDIA ConnectX-7 e AWS Elastic Fabric Adapter (EFA). Demostramos a súa eficacia en tres sistemas de produción en Perplexity AI:

Prefill e descodificación desagregados: transferencia de KvCache capa por capa mediante escrituras paginadas e observadores UVM, o que permite que as instancias de prefill e descodificación se dimensionen de forma independente.

Transferencia de pesos para a posadestramentos de RL en menos de 2 segundos: sincronización de pesos extremadamente rápida entre nós de adestramento e inferencia.

Habilitación de modelos de un billón de parámetros en AWS EFA: operacións de despacho e combinación de MoE de baixa latencia utilizando primitivas de dispersión e barreira, acadando unha latencia de vangarda en ConnectX-7 e a primeira implementación viable compatible con AWS EFA.

Este artigo céntrase no propio TransferEngine, a biblioteca de comunicación que alimenta estes sistemas. Lea o artigo de investigación completo en arXiv e explore o código en GitHub.

Motivación

As comunicacións colectivas sobresaen en patróns paralelos estruturados como o paralelismo de tensores e o paralelismo de datos, mais impoñen restricións que limitan a súa aplicabilidade ás cargas de traballo emerxentes:

Membresía fixa: os colectivos requiren establecer un mundo de comunicación global no momento da inicialización, cunha configuración sincronizada en todos os participantes. Para a inferencia desagregada, isto é problemático xa que o número de instancias de prefill e descodificación debe dimensionarse dinámicamente en resposta aos patróns de tráfico.

Formas de tensor uniformes: os colectivos asumen que todos os participantes intercambian tensores con formas e tipos de datos idénticos. No encamiñamento de MoE, o número de tokens enviados a cada experto depende dos datos e descóbrese en tempo de execución, o que obriga aos colectivos densos de todos a todos a encher ata tamaños de búfer no peor dos casos.

Ordenación de operacións: as API colectivas forzan semánticas sincronizadas, mesmo cando as aplicacións só necesitan saber que un conxunto de operacións rematou. Por exemplo, na transferencia de KvCache, todas as páxinas da instancia de prefill á instancia de descodificación poden chegar en calquera orde. Do mesmo xeito, nas actualizacións de pesos de RL, todos os tensores de pesos poden transferirse de forma independente sen restricións de orde.

A comunicación punto a punto baseada en RDMA aborda naturalmente estas limitacións, mais tres barreiras impediron a súa adopción:

Limitacións da biblioteca: aínda que torch.distributed e NCCL proporcionan API punto a punto como Send/Recv, estas operacións aínda heredan semánticas e limitacións colectivas.

Diversidade de hardware: as NIC NVIDIA ConnectX con transporte de conexión fiable (RC) son a configuración de RDMA máis común, o que garante a entrega en orde. Os provedores de nube como AWS utilizan hardware diferente; o Elastic Fabric Adapter (EFA) con transporte de datagramas fiables escalables (SRD) entrega mensaxes fóra de orde. EFA tamén require agregar catro NIC de 100 Gbps (ou dúas NIC de 200 Gbps) para acadar un ancho de banda de 400 Gbps.

Portabilidade de software: as bibliotecas RDMA existentes padecen de peches de provedor. DeepEP require RDMA iniciado por GPU (IBGDA) dispoñible só en ConnectX. NVSHMEM presenta unha grave degradación do rendemento en EFA. As bibliotecas como Mooncake e NIXL carecen de soporte para EFA ou seguen en desenvolvemento inicial. Como resultado, non existe ningunha solución viable entre provedores para a inferencia de LLM.

TransferEngine

TransferEngine aborda estas barreiras a través de catro capacidades fundamentais:

Suposicións de transporte comúns: no canto de apuntar a unha NIC específica, TransferEngine asume unicamente que o transporte subxacente é fiable mais desordenado, é dicir, a intersección das garantías proporcionadas polos transportes RC e SRD.

Sincronización ImmCounter: unha nova primitiva para a notificación de finalización que funciona sen depender da orde das mensaxes, o que permite que o mesmo código se execute tanto en transportes ordenados (RC) como desordenados (SRD).

Sorteo de múltiples NIC: xestión transparente de múltiples NIC por GPU, fragmentando automaticamente as transferencias para maximizar o ancho de banda.

Superficie de API mínima: un pequeno conxunto de operacións suficientes para construír patróns de comunicación complexos.

Deseño do sistema TransferEngine, que mostra as rutas de solicitude e devolución, traballadores de CPU, buffers UVM, GPUs e NICs en dous dominios GPU/NUMA.

TransferEngine xera un fío de traballo por GPU. Cada traballador xestiona un DomainGroup que coordina de 1 a 4 NIC RDMA, dependendo da plataforma de hardware (un único ConnectX-7 proporciona 400 Gbps, mentres que EFA require catro adaptadores de 100 Gbps ou dous adaptadores de 200 Gbps). Dentro dun DomainGroup, cada Domain é específico do hardware e xestiona unha única NIC, manexando a xestión de pares de colas, o envío de traballos e a sondaxe de finalización.

Cada instancia de TransferEngine expón un único enderezo principal para a identificación e descuberta de pares. Os pares remotos intercambian estruturas NetAddr que codifican enderezos de rede e pódense serializar para a comunicación fóra de banda. Todos os pares nun sistema deben usar o mesmo número de NIC por GPU. Esta configuración uniforme permite que TransferEngine fragmente as transferencias de forma intelixente: ao iniciar unha transferencia, tanto a orixe como o destino saben exactamente que NIC están dispoñibles, o que permite o equilibrio de carga automático en todos os adaptadores.

Deseño da API

TransferEngine expón unha API mínima que abstrae a complexidade das interfaces RDMA subxacentes.

rust
#[serde] struct NetAddr(Bytes); #[serde] struct MrDesc{ ptr: u64, rkeys: Vec<(NetAddr, u64)> } struct MrHandle(NonNull<c_void>); type Offset = u64; struct Pages{ indices: Vec<u32>, stride: u64, offset: Offset } struct PeerGroupHandle(u64); struct ScatterDst{ len: u64, src: Offset, dst: (MrDesc,Offset)} enum OnDone { Callback(fn () -> ()), Flag(Atomic<bool>) } trait TransferEngine { fn main_address() -> NetAddr; // Memory Region Management fn reg_mr(ptr, len, device) -> (MrHandle, MrDesc); // Two-sided Send/Recv fn submit_send(addr: NetAddr, msg: &[u8], cb: fn () -> ()); fn submit_recvs(len: u64, cnt: u64, cb: fn (&[u8]) -> ()); // One-sided Write fn expect_imm_count(imm: u32, count: u32, cb: fn () -> ()); fn submit_single_write(len: u64, imm: Option<u32> src: (MrHandle, Offset), dst: (MrDesc, Offset), OnDone); fn submit_paged_writes(page_len: u64, imm: Option<u32>, src: (MrHandle, Pages), dst: (MrDesc, Pages), OnDone); // One-sided Write to a group of peers fn add_peer_group(addrs: Vec<NetAddr>) -> PeerGroupHandle; fn submit_scatter(h: Option<PeerGroupHandle>, OnDone, imm: Option<u32>, src: MrHandle, dst: Vec<ScatterDst>); fn submit_barrier(h: Option<PeerGroupHandle>, OnDone, imm: u32, dst: Vec<MrDesc>); // Watcher for CPU-GPU synchronization fn alloc_uvm_watcher(cb: fn(u64,u64) -> ()) -> NonNull<u64>; }

A API consta de varios compoñentes clave:

Rexistro de memoria

As operacións RDMA requiren que as rexistren as rexións de memoria coa NIC antes da transferencia de datos. A función reg_mr toma un punteiro, unha lonxitude e un dispositivo, devolvendo dous controladores:

MrHandle: un controlador local usado como orixe para as transferencias

MrDesc: un descriptor serializable que se pode intercambiar con pares remotos para permitirlles escribir na memoria rexistrada

A estrutura MrDesc contén unha lista de enderezos de rede remotos e unha clave remota (unha por NIC) que conceden acceso remoto á rexión de memoria. Este deseño manexa de forma natural as configuracións de múltiples NIC.

Envío/Recepción bilateral

Para mensaxes pequenas e mensaxes do plano de control de estilo RPC, TransferEngine proporciona submit_send e submit_recvs:

submit_send: envía a mensaxe a un par remoto identificado por NetAddr. A mensaxe cópiase internamente, polo que o chamador pode reutilizar ou liberar inmediatamente o búfer.

submit_recvs: publica un conxunto de búferes de recepción. Cando chega unha mensaxe, invócase unha devolución de chamada cos datos recibidos. O búfer devólvese automaticamente ao conxunto despois de que se complete a devolución de chamada.

Escritura unilateral

Para transferencias de datos masivos, TransferEngine ofrece operacións de escritura unilateral sen copia:

submit_single_write: transfire unha rexión contiguamente desde a orixe ata o destino

submit_paged_writes: transfire páxinas non contiguas especificadas por índices, saltos e despracamentos

Ambas as operacións aceptan un valor inmediato opcional de 32 bits que se entrega ao receptor de forma atómica ao completarse.

O motor fragmenta automaticamente as grandes transferencias en múltiples NIC para maximizar o ancho de banda.

Grupos de pares e operacións masivas

Para operacións dirixidas a múltiples pares (comúns no encamiñamento de MoE), TransferEngine ofrece primitivas optimizadas:

add_peer_group: preresistra un conxunto de enderezos de pares para unha busca rápida

submit_scatter: envía diferentes anacos de datos a cada par do grupo

submit_barrier: envía unha notificación exclusiva de inmediato a todos os pares (transferencia de cero bytes)

Estas operacións están optimizadas para obter unha baixa latencia mediante a caché de estruturas de datos internas e a creación de modelos de solicitudes de traballo RDMA, evitando a sobrecarga de configuración repetitiva.

Observador UVM: sinalización de GPU a CPU

Un desafío clave nos sistemas de LLM é coordinar as transferencias RDMA co progreso da GPU. Idealmente, a transferencia de datos debería comezar en canto a GPU produce saída, pero sondar a GPU desde a CPU é ineficiente.

TransferEngine aborda isto con observadores UVM: localizacións de memoria virtual unificada que poden ser anovadas por kernels de GPU (mesmo dentro de gráficos CUDA) e sondadas de xeito eficiente pola CPU usando GDRCopy. Cando se aloca un observador UVM, rexístrase unha devolución de chamada que se invoca sempre que a GPU actualiza o valor.

Isto permite patróns como a transferencia de KvCache capa por capa: despois de que cada capa de transformador se complete, a GPU incrementa o observador, o que desencadea unha transferencia RDMA do KvCache desa capa mentres as capas seguintes continúan calculando.

Notificación de finalización

TransferEngine proporciona mecanismos de notificación de finalización tanto para o lado do iniciador (o chamador de submit_write) como para o lado do receptor (o destino das operacións de escritura).

Notificación no lado do iniciador: cando se envía unha operación de escritura, o chamador pode elixir ser notificado ao completarse mediante unha función de devolución de chamada ou un indicador atómico. Esta notificación confirma que os datos se transferiron correctamente desde o búfer de orixe.

Notificación no lado do receptor: a innovación clave é o ImmCounter, un compoñente que realiza un seguimento dos contadores indexados por números inmediatos de 32 bits. Cando unha operación de escritura leva un valor inmediato, o ImmCounter do receptor increméntase de forma atómica coa entrega de datos. A función expect_imm_count permite que o receptor rexistre unha devolución de chamada que se dispara cando un valor inmediato específico alcanza un reconte obxectivo. Os contadores pódense sincronizar de forma transparente coa GPU a través de GDRCopy, sondarse directamente ou monitorizarse mediante devolucións de chamada.

Este mecanismo do lado do receptor proporciona unha sincronización fiable sen requirir a ordenación de mensaxes. Funciona igualmente ben en NIC ConnectX (que garanten a entrega en orde a través do transporte RC) e NIC EFA (que entregan mensaxes fóra de orde a través do transporte SRD).

Implementación

TransferEngine está implementado en Rust, optimizando coidadosamente as asignacións, a creación de fíos e a sincronización para minimizar a latencia e acadar un alto rendemento. O motor xera un fío de traballo por DomainGroup, cada un ancorado a un núcleo de CPU no nodo NUMA ao que están conectados os dispositivos, minimizando tanto a programación como a latencia de acceso á memoria. As estruturas de datos específicas dun dominio asígnanse despois da fixación para garantir que a memoria estea reservada no nodo NUMA correcto. Un fío de traballo manexa ata 4 Domains (cada un xestionando unha única NIC), mentres que outro fío dedicado sonda a GPU para actualizar os observadores UVM. A comunicación entre fíos realízase a través de colas libres de bloqueos.

A API reenvía as solicitudes ao DomainGroup que serve ao dispositivo axeitado, e o primeiro tamén serve ao host. Nun bucle axustado, o traballador do dominio busca novos traballos, priorizando o envío de novas solicitudes. Dependendo do hardware e da configuración, as solicitudes divídense e equilíbrase a carga entre os Domains dispoñibles. A primeira escritura dunha solicitude composta envíase inmediatamente á cola de envío da NIC. Unha vez esgotadas as novas solicitudes, o traballador procede a avanzar nas operacións pendentes, publicando escrituras para encher a canalización de hardware. Posteriormente, as colas de finalización son sondadas para consultar as transferencias rematadas e os incrementos inmediatos de contadores. Os eventos agrúpanse para ofrecer notificacións por transferencia, entregando a transferencia a un fío de devolución de chamada dedicado compartido por todos os grupos.

A fragmentación dentro dun DomainGroup é flexible. As transferencias poden apuntar a NIC específicas por índice. Unha soa escritura pódese dividir. As transferencias paginadas, as operacións de dispersión e de barreira, que se traducen en varias escrituras, poden fragmentarse en todas as NIC.

Optimizacións específicas de hardware

Os Domains dentro de TransferEngine están especializados e optimizados para o hardware baixo o seu control:

AWS EFA: a implementación de EFA utiliza libfabric, xestionando un dominio de fábrica por NIC dentro do DomainGroup. As decisións e optimizacións clave de implementación inclúen:

Escrituras de tamaño cero: EFA difire da especificación RDMA ao requirir descritores de destino válidos mesmo para escrituras de tamaño cero. Por tanto, TransferEngine aplica descritores válidos para todas as transferencias.

Creación de modelos de solicitudes de traballo: preenche previamente e retén os campos comúns das estruturas de libfabric antes de publicar, reducindo a sobrecarga por operación para transferencias masivas e operacións de grupos de pares

NVIDIA ConnectX-7: a implementación de ConnectX-7 utiliza libibverbs con transporte RC. As decisións e optimizacións clave de implementación inclúen:

Pares de colas UD para saúdos: cada Domain utiliza un par de colas de datagramas non fiables (UD) para intercambiar saúdos de conexión RC.

Pares de colas RC separados: crea 2 pares de colas RC por par, un para operacións Send/Recv bilaterais e outro para operacións Write e WriteImm unilaterais. Esta separación é necesaria porque tanto as finalizacións de Recv como as de WriteImm consumen solicitudes de traballo na orde de publicación, o que permite semánticas de Recv de alto nivel mentres se admite WriteImm sen interferencias.

Creación de modelos de solicitudes de traballo: preenche previamente os campos comúns das estruturas de solicitudes de traballo para transferencias masivas e grupos de pares.

Encadeamento de solicitudes de traballo: liga ata 4 solicitudes de traballo a través do punteiro next de ibv_send_wr, reducindo o número de chamadas de timbre á NIC.

Orde relaxada: activa IBV_ACCESS_RELAXED_ORDERING para permitir transaccións PCIe fóra de orde entre a NIC e a memoria da GPU.

Conclusión

Ao apuntar á intersección de garantías entre diferentes transportes RDMA e introducir a sincronización independente da orde a través de ImmCounter, TransferEngine proporciona unha base portátil para a comunicación punto a punto nos sistemas de LLM. A biblioteca é de código aberto e está dispoñible en GitHub, e animamos á comunidade a explorala e construír sobre ela para patróns de comunicación emerxentes en sistemas de aprendizaxe automática a gran escala.

Cita

BibTeX
@online{perplexity2025RdmaPointToPointCommunicationForLlmSystems,
  author = {{Perplexity} and Nandor Licker and Kevin Hu and Vladimir Zaytsev and Lequn Chen},
  title = {{RDMA point-to-point communication for LLM systems}},
  date = {2025-11-05},
  url = {https://www.perplexity.ai/hub/blog/rdma-point-to-point-communication-for-llm-systems}
}