Quizás con las conexiones modernas no se note demasiado, pero con un modem de 56k si que se sigue notando. Me refiero a la siguiente curiosidad que muchos sabrán y otros no y que me apetece contar: No estás utilizando la red y empiezas a bajarte algo, y la conexión pronto llega, si el servidor tiene el ancho de banda suficiente y la ruta entre él y tu equipo es adecuada, a su "tope". Sin embargo, si según te estás bajando ese archivo comienzas a bajarte otro, este segundo archivo comienza bajándose a un ancho de banda bajísimo, ridículo, que aumenta progresiva y lentamente al mismo tiempo que el ritmo de descarga del primer archivo disminuye. A veces, si la primera descarga baja muy rapido y/o la luna está en cuarto creciente, la segunda descarga empieza tan lento que simplemente no llega a empezar: Salta algún timeout en algún lado y se cierra la conexión. ¿Por qué ocurre todo esto?
La respuesta está en un control de congestión que se implementa en todas las pilas TCP/IP. Pero como tantas otras cosas, tiene su historia.
En los albores de internet, no existía ningún tipo de control de congestión verdadero. Simplemente se mandaban los paquetes a la máxima velocidad que daba de si la interfaz de red. Si la interfaz del receptor era muy lenta y no podía recibir todos los paquetes a esa velocidad, simplemente se perdían los paquetes (la red no es como un embudo: si metes más informacion de la que cabe no se "acumula", se pierde lo sobrante). El rápido emisor reenviaba lo perdido, y continuaba mandando más, hasta el proximo embotellamiento.
En los albores de internet esto funcionó bien, pero cuando creció internet este problema se hizo muy grande. Sospecho (no lo he confirmado, pero mi sentido arácnido me dice que mis sospechas son ciertas) que los orígenes del problema vinieron de la propia expansión de internet: En un inicio había pocos ordenadores conectados a internet, las redes eran financiadas por caros proyectos de investigación y siempre estaban a la última y tenían velocidades parecidas. Los embotellamientos no eran un gran problema. Pero cuando internet creció, las diferencias de capacidad entre unas redes y otras se acrecentaron. Y hubo que crear mayores redes de interconexión entre las principales redes, que a veces tenían menor ancho de banda que los equipos: Por mucho que un emisor y un receptor tuvieran una conexión de X KB/s, si entre ellas había una red con X/2 KB/s, la conexión solo iba poder ir a X/2 KB/s.
Esto hizo que en el 86 y en adelante empezaran a detectarse auténticos colapsos de internet, pérdida masiva de paquetes. Era imposible enviar datos a ciertos sitios y era imposible descargarse emacs de una vez, había que bajarselo en trocitos. En aquellos tiempos las grandes interconexiones de backbones de Internet iban a 56 Kbps. Cundió la duda: ¿Era TCP incapaz de escalar a mayores velocidades? ¿Había que rehacer toda la tecnología? ¿Dónde estaba el fallo? La solución se dió en la reunión USENIX de 1989. Se presentó una charla titulada "Congestión Avoidance and Control", que presentaba una serie de algoritmos, que fueron implementados en forma de parche en los sistemas operativos que controlaban los grandes núcleos de internet - BSDs. Se hizo un RFC que ordenaba literalmente implementar este sistema de congestión de control. Una de las personas que había escrito ese documento se llamaba Van Jacobson. Ha trabajado toda la vida en TCP/IP, ha escrito importantes documentos y ha colaborado tambien en varios RFCs. Los que hayan utilizado alguna vez un modem, ¿han oido alguna vez manejando pppd de una compresión de cabeceras IP apodada "VJ compression"? Pues las iniciales VJ pertenecen, efectivamente, a Van Jacobson. Por cierto: Este tipo aun trabaja en asuntos de TCP/IP, utiliza mucho con Linux, dice que Linux tiene la pila TCP/IP más rápida y mejor del planeta -esto va por los que dicen que Linux es un SO de juguete-, e incluso presentó una charla sobre una proposición de diseño de la pila tcp/ip para aprovechar las capacidades del hardware del futuro.
Pero me desvio. ¿En que consistía el sistema de control de congestión? Es un sistema simple: La técnica se apodaba "slow-start". Se empezaba mandando un paquete. Si el paquete llegaba correctamente -según el protocolo TCP, el receptor debe confirmar con un ACK la llegada del paquete-, la próxima vez se enviaban dos paquetes: Uno por el paquete por el que llegó el ACK, y otro más que se añade. Si esos dos llegaban bien, la siguiente vez se mandaban cuatro: dos por los ACKs, y otros dos que se añaden, uno por ACK. Etc. Cada conexión guarda en una variable el número de paquetes enviados, para saber cuantos necesitaba enviar la próxima vez. Asi, se comienza la conexión progresivamente, hasta llegar al límite de la conexión entre los dos equipos. Cuando se llegaba al límite -dejaban de llegar paquetes correctamente al receptor-, entraba en juego el control de congestión: en vez de incrementarse tan rápido se incrementaba más lentamente. ¿Y como se detecta la congestión? Pues cuando ocurre un timeout (no llega un ACK para un paquete en un tiempo limitado), se anota en una variable ssthresh (independiente para cada conexión) la mitad de la otra variable, la que controla el numero de paquetes que se envian, y se resetea la cantidad de paquetes que puede enviar la conexión a uno, desde el principio. Mientras la cantidad de paquetes sea menor que sshtresh, se sigue haciendo "slow-start", cuando llega a sshtresh -la mitad del ancho de banda que nos hizo llegar a un timeout anteriormente- se comienza a incrementar lentamente: control de congestión.
Es decir, aunque matemáticamente sea algo más dificil de entender, hace lo obvio: Manda paquetes hasta que ve que la conexión no da mas -se detecta un timeoput- y entonces empieza a enviar menos y a dejar de aumentar rapidamente el ritmo. A día de hoy existen algoritmos mucho más complejos y muy diferentes, optimizados para diferentes situaciones -en redes wireless hay muchas pérdidas de paquetes por razones distintas al ancho de banda, y con el slow-start el rendimiento es subóptimo- pero todos tienen algo en común con éste: El control de congestión.
¿Como se refleja esto en nuestras descargas, que es lo que motivó esta entrada? Fácil: Cuando empezamos a descargar un solo archivo, la velocidad aumenta rápidamente. Pero si estamos descargando un archivo y empezamos a descargar otro, la situación es distinta: La conexión ya está aproximadamente en su máximo. Eso provoca que la segunda conexión empiece a perder paquetes al no caber más datos en la conexión. El servidor que envia el segundo archivo, al detectar los timeouts provocados por las pérdidas, baja la velocidad de la conexión para adaptarse, y la aumenta lentamente, para controlar lo que él cree que es "congestión". Al mismo tiempo la primera descarga, ante este pequeño incremento de ancho de banda por parte de la segunda descarga, empieza a perder paquetes, con lo cual el servidor del primer archivo baja un poco la velocidad de envio. Y así es como más o menos las dos descargas empiezan a equilibrarse. A veces no llegan a equilibrarse, todo depende de mil factores, pero el sistema básico es este.
23 de marzo de 2007
¿Por qué las segundas descargas comienzan lentas?
Suscribirse a:
Enviar comentarios (Atom)
Gran artículo!
ResponderEliminarPropuesta de articulo:
ResponderEliminarEn top500.org hay un listazo de los 500 supercomputadores del mundo mas potentes, segun sus estadisticas alrededor del 80% llevan linux.
Cuando lo comentas a alguna otra persona (siempre windowsero), siempre te salta: claro, pq es gratis y se ahorran dinero.
Podrias escribir un post comentando los requerimientos de los SO de supercomputacion, los problemas existentes, las soluciones adoptadas...
Escelente articulo.
ResponderEliminarEs el mejor artículo que he leido esta semana, candidato a ser el mejor del mes.
ResponderEliminarMuy interesante, enhorabuena. Me gustan más estos que los de pérez reverte, los de política y similar :P
ResponderEliminarA New Way to look at Networking por Van Jacobson :
ResponderEliminarhttp://video.google.com/videoplay?docid=-6972678839686672840
simplementa acojonante.