Una vez que se establece una conexión entre el cliente y el servidor, el remitente envía los datos al receptor en forma de paquetes. Si la red está congestionada, los paquetes se descartan. Esto sucede cuando se llena el búfer de dispositivos intermediarios como el enrutador. El remitente TCP debe detectar si ha llenado los ‘búferes en los dispositivos intermedios’ y, de ser así, reducir la velocidad de transmisión para que la red pueda salir del ‘estado congestionado’. Pero hay un problema: nadie informa al remitente TCP sobre el estado de los ‘búferes’ en los dispositivos intermedios.
El remitente TCP ‘estima’ el estado de los búferes en los dispositivos intermedios por sí mismo y mantiene una variable para sí mismo, que se conoce como ventana de congestión (cwnd). El remitente nunca envía datos que superen el tamaño de la ventana de congestión. Digamos cwnd = 15 paquetes, entonces el remitente no puede enviar 16 paquetes a la red. Esta ‘estimación’ que se realiza en el remitente TCP representa la ‘ruta completa’ desde el remitente TCP hasta el receptor TCP. No es una estimación de la ocupación del búfer en ‘cada dispositivo intermedio’ entre el emisor TCP y el receptor TCP. Porque el remitente no puede saber el número de dispositivos intermediarios. Además, la ruta del paquete puede cambiar para la misma conexión. Diferentes paquetes pueden elegir diferentes rutas para llegar desde el remitente al receptor.
Entonces, ¿cómo comienza el ‘proceso de estimación’ en el remitente TCP ? ¿Cuál es el valor inicial de cwnd? La respuesta es un algoritmo de inicio lento.
Algoritmo de inicio lento:
Propósito: Iniciar el proceso de ‘estimación’ cwnd y llegar rápidamente a una ‘estimación decente’.
Algoritmo
- Comienza con un valor inicial de cwnd (el valor predeterminado es 10 segmentos en Linux, era 1 segmento en la década de 1980)
- El valor inicial de cwnd se almacena en una variable separada llamada ‘initcwnd’ en el kernel de Linux y es fijo.
- Cuando comienza el algoritmo, cwnd = initcwnd
- Otra forma de ver cwnd: ‘la cantidad máxima de segmentos que un remitente TCP puede transmitir sin esperar un acuse de recibo (ACK)’
- Una variable más importante se usa en TCP, que se llama ‘en vuelo’ o ‘tubería’
- inflight/pipe = la cantidad de paquetes que se enviaron pero no se recibió un ACK para esos paquetes, es decir, están ‘en vuelo’ o ‘en canal’ entre el remitente y el receptor
- inflight ≤ cwnd, pero se prefiere que inflight = cwnd para utilizar el ancho de banda de la red
Ilustración :
Inicialmente, cwnd = initcwnd = 10 segmentos. El remitente envía 10 segmentos en el vuelo sin esperar a que llegue el único acuse de recibo.
A la llegada de cada ACK, el remitente incrementa el cwnd en 1 segmento y envía 2 nuevos segmentos en la red.
cwnd = 10 + 1 = 11, el nuevo cwnd es 11 pero ahora solo hay 9 segmentos en vuelo. El remitente puede enviar segmentos por valor de cwnd en vuelo. Entonces, el remitente envía 2 segmentos más en vuelo.
inflight = inflight – 1 + 2 // -1 porque recibimos un ACK, +2 porque enviamos 2 nuevos segmentos
inflight = 10 – 1 = 9 + 2 = 11
Por lo tanto, si todos los segmentos se confirman con éxito, el cwnd ‘eventualmente’ se duplicará en un RTT. Los 10 ACK llegarán dentro de un RTT de tiempo al remitente y en ese momento cwnd se convertirá en 20. Ahora 20 segmentos están en vuelo.
conclusión clave
cwnd aumenta de manera continua, cada vez que llega un ACK. El remitente no duplica cwnd después de un RTT, sino que lo aumenta gradualmente en 1 cada vez que llega un nuevo ACK. El remitente TCP no espera que lleguen los ACK de ‘los 10 segmentos’ para aumentar el cwnd. Este comportamiento desperdiciará el ancho de banda de la red porque no se envían nuevos segmentos hasta que no se utilizan todos los ACK y el ancho de banda.
Reinicio de inicio lento:
Cuando cwnd alcanza su valor máximo de ssthresh o cuando se detecta una pérdida de paquete, se termina el inicio lento y se activa otro algoritmo que se encarga de eso.
Pero cuando la conexión TCP está inactiva durante un cierto período (igual a RTO), el remitente invalida su estimación de cwnd porque no se actualiza durante un tiempo. Cuando el remitente envía más segmentos después de ese período de tiempo definido después de estar inactivo, reinicia el algoritmo de inicio lento para estimar decentemente el tamaño de su ventana de congestión.
AIMD (Aumento Aditivo Disminución Multiplicativa):
Cuando ocurre una caída de paquete (es decir, el remitente TCP no recibe un ACK para un paquete específico) o cuando el algoritmo alcanza el ‘Umbral de inicio lento’, el inicio lento finaliza y comienza AIMD. Al comienzo de una conexión TCP, ssthresh = ∞. ssthresh se actualiza cuando se produce una caída de paquetes. Se actualiza como ssthresh = cwnd ÷ 2. AIMD reduce el cwnd en un 50 % cuando se detecta la pérdida de paquetes y aumenta el cwnd en 1 por RTT (no por ACK, a diferencia de Slow Start).
¿Cuál es el problema si se restablece la conexión TCP?
El remitente TCP tiene que obtener una ‘nueva estimación’ de cwnd que toma varios RTT. Ejemplo: suponga que cwnd = 1024 segmentos cuando la conexión TCP se restableció debido a un período de inactividad. Ahora el remitente TCP inicializa cwnd a 10 segmentos y usa un algoritmo de inicio lento para aumentar el cwnd. ¡Se necesitarían 10 RTT (1000 ms si un RTT es de 100 ms) para que el remitente TCP obtenga su cwnd en 1024 segmentos!
Comandos de Linux:
Jugando con SSR en el kernel de Linux con la ayuda de los siguientes comandos:
Comprobación de la configuración predeterminada de SSR en el kernel de Linux
$ sysctl net.ipv4.tcp_slow_start_after_idle
Salida esperada (significa que SSR está habilitado):
$ net.ipv4.tcp_slow_start_after_idle = 1
Deshabilite el reinicio de inicio lento (importante para servidores, no tanto para clientes)
$ sudo sysctl -w net.ipv4.tcp_slow_start_after_idle=0
Rendimiento esperado:
$ net.ipv4.tcp_slow_start_after_idle = 0
Publicación traducida automáticamente
Artículo escrito por pintusaini y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA