OpenVPN sobre TCP: rto_min no arregla el bloqueo en cabeza de cola
Un flujo de bytes externo entrega en orden, así que un solo segmento perdido puede detener cada flujo interno. Un temporizador interno más largo cambia un reloj, no esa restricción.
Una shell interactiva sobre el túnel se congela durante varios segundos mientras se ejecuta una copia de archivos, y luego continúa como si nada hubiera pasado. La descarga es lo único con un problema, pero la shell también espera, y ambas se recuperan en el mismo momento. Ese patrón es la firma de un flujo fiable que transporta muchas conversaciones, y sobrevive a casi todos los ajustes que la gente prueba primero.
Vale la pena leer el síntoma con cuidado porque apunta a un mecanismo y no a un ajuste: la pausa es compartida, así que la causa es compartida, y el objeto compartido es la conexión externa. Todo lo demás en el registro parece normal mientras ocurre.
El síntoma: todo se pausa a la vez
Dos conexiones internas que se atascan juntas son la pista. Una descarga lenta y una shell lenta son conversaciones TCP separadas con números de secuencia y estado de congestión separados, así que un fallo en una no debería tocar a la otra. Cuando se pausan al unísono, algo por encima de ellas está ordenando sus bytes.
Ese algo es el transporte del túnel. En modo TCP, OpenVPN escribe los paquetes encapsulados en una sola conexión TCP hacia el par, y el contrato de TCP es la entrega en orden de un único flujo de bytes. Los bytes posteriores no se entregan a la aplicación antes que los que faltan, sin importar a qué conversación interna pertenezcan.
Fíjese en lo que el síntoma no dice. No dice que la ruta esté rota, que el servidor esté sobrecargado o que el cifrado sea lento. Esos producen formas distintas: rendimiento uniformemente bajo, tiempos de espera o fallos que afectan a una dirección. Una pausa compartida que termina cuando se retransmite un segmento perdido es específicamente un efecto de orden.
Un flujo de bytes externo, muchas conversaciones internas
Imagine el túnel transportando una descarga y una shell al mismo tiempo. Se pierde un segmento de la conexión externa. Los segmentos siguientes pueden llegar al host receptor, y la pila TCP receptora los acusará recibo, pero no puede entregarlos hacia arriba hasta que se rellene el hueco. Por lo tanto, OpenVPN no tiene nada que leer para la shell, aunque los bytes de la propia shell llegaron hace mucho.
Esto es bloqueo en cabeza de cola dentro de una conexión, y no requiere que las dos aplicaciones compartan una conexión interna. Comparten la externa, lo cual basta.
El efecto de segundo orden lo empeora. Un emisor interno que no ve acuse de recibo puede retransmitir datos que la capa externa ya está tratando de entregar. Esa retransmisión se convierte en tráfico adicional del túnel en una ruta que acaba de demostrar que puede perder segmentos, así que el trabajo de recuperación compite con la recuperación que importa.
Nada de esto garantiza un colapso. En una ruta limpia con idas y vueltas cortas y colas generosas, el arreglo puede ser perfectamente utilizable durante años. El fallo aparece cuando pérdida, retraso y profundidad de cola se alinean, y por eso los informes se agrupan en enlaces ascendentes congestionados y enlaces móviles en lugar de oficinas bien aprovisionadas.
Por qué un temporizador interno más largo no puede ayudar
Elevar el tiempo de espera mínimo de retransmisión en una ruta, con rto_min, pospone la retransmisión por temporizador del tráfico TCP generado localmente que usa esa ruta. Es un control real con un efecto real, y aborda el problema de segundo orden y no el primero.
ip route show
ip route show cache 2>/dev/null | head
ss -tin dst 10.70.0.1
Lo que no puede hacer es liberar bytes externos fuera de orden, recuperar el segmento perdido más rápido ni hacer que el servidor de aplicaciones remoto adopte el mismo temporizador. La pila receptora sigue entregando en orden, y el emisor del extremo lejano sigue usando sus propias mediciones de ida y vuelta.
Tampoco desactiva los demás mecanismos de recuperación de pérdidas. Donde una pérdida real exige recuperación por temporizador, un mínimo mayor hace que la aplicación espere más antes de actuar, que es lo contrario de lo que necesita una sesión sensible a la latencia.
Un suelo fijo de doce segundos aparece en los consejos sobre este tema como si la existencia de un túnel TCP lo implicara. El temporizador de retransmisión descrito en la RFC 6298 se deriva del tiempo de ida y vuelta medido con retroceso exponencial, así que un suelo constante es una decisión de política para una ruta concreta y no un requisito del protocolo. Aplicado de forma amplia, oculta el síntoma mientras cambia la recuperación de cada flujo que cubre esa ruta.
Qué hace y qué no hace tcp-nodelay
La opción de túnel que desactiva el almacenamiento en búfer estilo Nagle en el socket de transporte tiene un propósito estrecho: impide que las escrituras pequeñas esperen más datos antes de transmitir. Eso ayuda al tráfico interactivo a evitar un retraso adicional en una ruta por lo demás sana.
No convierte el transporte en uno sin orden, y no acorta la recuperación tras un segmento perdido. Una shell que se pausa por un tiempo de espera de retransmisión seguirá pausándose con esa opción activada, porque la opción nunca tocó la regla de orden.
Confundir ambas cosas es fácil porque las dos se describen como correcciones de latencia. Una elimina una espera artificial introducida por el búfer; la otra exigiría cambiar lo que el transporte garantiza, algo que no hace ninguna opción de socket.
Cómo comparar transportes de forma justa
Si el operador lo permite y ambos servicios existen, compare un servicio UDP y un servicio TCP que transporten la misma carga por la misma ruta de acceso al mismo servidor. Cambiar de país, proveedor o generación de servidor entre las dos pruebas introduce una variable que dominará el resultado.
Fíjese en la pausa compartida en lugar de en una cifra de rendimiento. Varias aplicaciones internas atascándose juntas durante una pérdida externa es la observación que identifica el bloqueo en cabeza de cola; una sola cifra más baja en un test de velocidad no lo hace.
Las capturas autorizadas en la interfaz del túnel y en la interfaz física separan las dos capas con claridad, porque las retransmisiones internas y externas pertenecen a conexiones distintas con espacios de secuencia distintos. Ver retransmisiones internas mientras el flujo externo muestra un hueco es la evidencia directa.
Cambiar a UDP elimina el flujo fiable adicional y deja que el TCP interno haga su propia recuperación. No promete pérdida cero ni baja latencia, y un enlace ascendente saturado, colas sobredimensionadas o un problema de MTU seguirán necesitando arreglo. El tráfico fuera del túnel nunca se queda retenido detrás del hueco de secuencia del túnel, aunque todavía puede sufrir cuando ambas rutas comparten un enlace congestionado, y ese cuello de botella compartido merece su propia investigación en lugar de plegarse en esta.