W-01
upstreamer
L7 reverse proxy · hyper + tokio
Roteia por host e caminho, balanceia pela latência EWMA, limita cada IP de cliente com um token bucket, descobre upstreams no Kubernetes e troca toda a configuração sem lock, via ArcSwap, sem derrubar conexões. Medido contra os proxies que as pessoas realmente usam. Uma cauda bimodal de 40 ms acabou sendo o Nagle encontrando o delayed ACK: seis tentativas para achar, uma linha para corrigir.
- Health checks ativos e passivos
- Métricas Prometheus em porta separada
- jemalloc: ~6% da CPU estava no malloc
- Token buckets por IP
| Parâmetro | Condição | Valor |
|---|---|---|
| Vazão50 conexões, 500 mil req | 50 conexões, 500 mil req | 76.663req/s |
| Latência, p99,99menor entre todos os proxies testados | menor entre todos os proxies testados | 3,81ms |
| p99,99 antes da correçãoNagle + delayed ACK | Nagle + delayed ACK | 41ms |
| Limite de concorrência100% 2xx, igual ao backend | 100% 2xx, igual ao backend | 4.800conexões |
| upstreamer | 76.663 | |
|---|---|---|
| HAProxy | 70.503 | |
| nginx, auto | 69.477 | |
| nginx, 1 worker | 68.637 | |
| Caddy | 66.195 | |
| Apache | 57.518 | |
| 020k40k60k80k |
Mesmo harness da Fig. 0. Backend sozinho, sem proxy: 154.998 req/s.
| tentativa 0primeira execução | 41 |
|---|---|
| tentativa 1decay do jemalloc | 41 |
| tentativa 2thread de métricas | 41 |
| tentativa 3cpu pinning | 41 |
| tentativa 4remoção do arcswap | 41 |
| tentativa 5alocação de string | 41 |
| tentativa 6TCP_NODELAY | 4,15 |
As tentativas 1 a 5 (decay do jemalloc, thread de métricas, CPU pinning, remoção do ArcSwap, alocação de string) deixaram a cauda em 41 ms. A tentativa 6 foi uma linha: set_nodelay(true).