EQProxy Load balancer y reverse proxy en Rust

Paridad

La matriz de paridad clasifica las 120 filas de referencia de HAProxy 3.4.6 LTS, nginx 1.27.1, ingress-nginx y Envoy API v3: 61 de HAProxy, 20 de nginx, 19 de ingress-nginx y 20 de Envoy. Ninguna queda sin clasificar, y ninguna clasificación se apoya en «compila, luego funciona».

Resultado de v0.9.1: 11 E1 · 88 E2 · 21 E3 · 0 sin clasificar. Eso no es paridad completa y la página no lo pretende.

Qué significa cada clase

ClaseSignificadoEvidencia exigida
E1Misma semántica observable que la referenciaUn caso del corpus diferencial que corre contra la referencia y EQProxy y pasa
E2Equivalente con una diferencia conocida y documentadaUn test del comportamiento y la diferencia nombrada en la fila
E3Fuera de alcance por decisiónUn ADR público y una alternativa

Un E1 solo se acepta si el corpus diferencial lo ejecuta: no se infiere de un test unitario ni de que el código parezca equivalente. Una fila cuyas semánticas compartidas están cubiertas pero cuyo conjunto de directivas no, conserva el E1 por lo cubierto y nombra lo que falta en la columna de diferencia.

Recuento por referencia

ReferenciaFilasE1E2E3
HAProxy 3.4.6613499
nginx203152
ingress-nginx193115
Envoy API v3202135
Total120118821

Las once filas E1 son: enrutamiento por host, ruta, cabecera y método, reescritura de URL y cabeceras y redirecciones de HAProxy (C3, C4, C5); hosts virtuales, location y cabeceras con X-Forwarded-For en nginx (B-N2, B-N3, B-N4); host y ruta, PROXY y X-Forwarded-*, y redirecciones y reescrituras en ingress-nginx (B-I2, B-I4, B-I6); enrutamiento avanzado y manipulación de cabeceras en Envoy (B-E3, B-E17).

Qué queda fuera

Lo que EQProxy no hace, por decisión escrita en un ADR:

Lagunas conocidas y semántica más estrecha

Además de lo anterior, v0.9.1 tiene límites que conviene leer antes de probar nada:

PuntoEstado
HTTP/3Experimental: navegadores y curl sobre h3 sin verificar, y las pruebas adversarias de QUIC del modelo de amenazas no se han ejecutado
UsuariosNinguno fuera del autor; la fase 9 de producción sigue pendiente
mapSolo coincidencia por equals
error_pages con format = "raw"Conserva el estado, el Content-Type y el cuerpo; el Date generado sustituye al del fichero
Date de un origen que no lo mandaSe retransmite tal cual: el proxy solo sella las respuestas que genera él
Respuesta interina 100 ContinueSin campos de cabecera
CachéSin stale-while-revalidate ni stale-if-error
Binarios de macOSNo son estáticos; solo los de Linux

Cómo se genera la evidencia

Dos arneses de Rust, ambos #[ignore] porque necesitan Docker.

Corpus diferencial (23/23). Levanta HAProxy 3.4.6, nginx, el dataplane de ingress-nginx y Envoy estático en contenedores, y compara cada caso contra EQProxy: estado, Location (ruta y consulta), cuerpos declarados y cabeceras declaradas, tras la normalización documentada. No compara tiempos, reutilización de conexiones, parámetros TLS ni bytes de páginas de error.

cargo test -p eqproxy-cli --test differential -- --ignored --nocapture

Matriz de migración (65/65). Cuatro configuraciones de origen escritas a mano y su traducción a eqproxy.toml enrutan caso por caso lo mismo: 13 casos declarados × 5 implementaciones. Los originales corren en contenedores y el binario eqproxy de forma nativa, todos delante de los mismos cinco backends de eco.

cargo test -p eqproxy-cli --test migration -- --ignored --nocapture

Un corpus en verde es la ausencia de un contraejemplo, no una prueba de equivalencia. La matriz de migración son 13 casos declarados, no una prueba para configuraciones arbitrarias: el método y sus límites están publicados junto a la evidencia.