Está en la página 1de 4

inedit00: TCP Sockets: TIME_WAIT y los puertos efmero...

http://inedit00.blogspot.com/2012/02/hoy-vamos-explica...

Compartir

Informar sobre mal uso

Siguiente blog

Crear un blog

Acceder

inedit00
Recopilando pelusillas en mi ombligo con las que, algn da, dominar el Mundo entero! Muahaahahaha!

VIERNES, 17 DE FEBRERO DE 2012

TCP Sockets: TIME_WAIT y los puertos efmeros son poco amigos


Hoy vamos a explicar un poco qu es TIME_WAIT y cmo puede darte por culo un rato largo. [INTRODUCCIN] Todos sabemos que las conexiones TCP ( capa 4 en modelo OSI, tambin llamada capa de transmisi de datos ) tienen estados. Umm... bueno, igual no todos lo sabemos. Refresquemos un poco qu son esto de los estados TCP antes de empezar. TCP establece la conexin a tres vas[1]. Cuando se intenta establecer la conexin del host A al host B, el host A manda un paquete tipo SYN al host B. La conexin pasa a estar en un estado SYN_SENT. Cuando el host B le contesta con un paquete ACK-SYN, la conexin para a un estado llamado SYN_RECV. Cuando la conexin por n se establece pasa a estado ESTABLISHED. Tambin hay el estado LISTEN, que es el estado que tienen servicios tales como apache, memcached o sshd, esperando nuevas conexiones. Total, con todo esto nos tenemos que quedar con la copla de que una conexin TCP pasa por diferentes estados desde que se establece hasta que se cierra. La lista completa de estados se puede ver fcilmente haciendo un man netstat, y buscando el apartado State. Bien, entonces tenemos que los dos estados mas comunes son: ESTABLISHED conexiones establecidas y LISTEN, en el caso de que estemos en un servidor con varios servicios activos. Para ver una lista de las conexiones abiertas en nuestra mquina podemos hacer un: $ sudo netstat -pan --tcp | less

BUSCAR ESTE BLOG

Buscar

ARCHIVO DEL BLOG

2012 (21) mayo (1) abril (7) marzo (8) febrero (5) Puertos abiertos en el router: mala idea. TCP Sockets: TIME_WAIT y los puertos efmeros son ... Wikipedia, querida. Por qu no te preocupas por m... Fin de una poca... AKA adis trabajo, adis

[SUPOSICIN] Si ejecuto un script muy simple que haga peticiones HTTP contra mi servidor web local SUPONGO que no habr ningn problema (jeje, los cojones). Tengo un servidor Apache escuchando en el puero 80 en localhost. Problemos a ejecutar el siguiente comando en 5 consolas diferentes. $ while true; do curl localhost; done El comando "curl" abre una conexin TCP, hace una peticin HTTP, se le devuelve un resultado (que no nos importa lo mas mnimo, ahora mismo) y CIERRA LA CONEXIN TCP. O esto es lo que nosotros esperamos, vamos. Entiendo que tener 5 instancias del script hara que normalmente tuviese 5 conexiones en estado ESTABLISHED, pero esto, nunca debera ocasionar un problema a nivel de sistema. Hagamos la prueba. Ejecutamos cinco veces el script en consolas separadas, y en otra terminal ejecutamos: $ sudo watch -n 0.5 'netstat -pan --tcp | grep ESTABLISHED | wc -l' Pues efectivamente, nunca pasamos de 5 conexiones al mismo tiempo en estado ESTABLISHED pero... Umm.... pero al cabo de un minuto de estar ejecutando los scripts, el comando "curl" empieza a dar un error: curl: (7) Failed to connect to 127.0.0.1: Cannot assign requested address

CISCO CCNA 2011 (11) 2010 (32) 2009 (55)

DATOS PERSONALES

inedit00 Baleares, Spain Estudiante de Administracin de Sistemas Informticos, con intencin de aprender todo lo que se ponga por delante. Hace tan solo tres aos que conoc Linux. Me gusta. Me siento cmodo en el. Creo que en informtica, como en las dems disciplinas, se tiene que aprender sobre todos los temas que sean posibles y como ms conocimientos se tengan de cada cosa, mejor. Espero que encuentren algo de inters en este blog. Saludos. Ver todo mi perl

[PROBLEMA] WTF. A ver, tenemos tan solo 5 conexiones abiertas. El error del curl parece decirnos que no puede obtener un puerto de origen para establecer la conexin. Veamos porqu: Ejecutemos los scripts anteriores y pongamos un ltro diferente en el netstat: $ sudo 5329 $ sudo 13440 $ sudo 19348 $ sudo 21526 $ sudo 28214 netstat -pan --tcp | grep TIME_WAIT | wc -l netstat -pan --tcp | grep TIME_WAIT | wc -l netstat -pan --tcp | grep TIME_WAIT | wc -l netstat -pan --tcp | grep TIME_WAIT | wc -l netstat -pan --tcp | grep TIME_WAIT | wc -l

ETIQUETAS

linux (41)

out of topic (20) general (16) howto (15) seguridad (12) tips (10)
programacion (9) reexin (8) bash (6)

1 de 4

16/07/12 11:29

inedit00: TCP Sockets: TIME_WAIT y los puertos efmero...

http://inedit00.blogspot.com/2012/02/hoy-vamos-explica...

COJONES! Por algn motivo estan quedando chorrocientos sockets abiertos en estado TIME_WAIT! [QU ES TIME WAIT] Ahora que nos hemos puesto un poco en matria vamos a ver para que se usa el estado TIME_WAIT, y como puede llegar a ser un problema. De la denicin del man de nestat sacamos que: TIME_WAIT: The socket is waiting after close to handle packets still in the network. Umm... segn esto parece que la conexin no se cierra hasta que pase un tiempo para poder capturar los paquetes que se haban "perdido" por la red debido a posibles problemas de enrutamiento. Jummm... explicacin algo escueta. Sobre todo porque no dice cuanto vamos a tener que esperar. Vamos a investigar un poquito ms sobre el tema... El RFC 1122 en el apartado "Transport layer, TCP" [2] dice algo as como: When a connection is closed actively, it MUST linger in TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime). Vaaaale. Ahora ya tenemos un poco mas de informacin. Resulta que tenemos que esperarnos 2xMSL antes de que una conexin pase de TIME_WAIT a CLOSED ( y se libere la conexin ). Genial. Y ahora... Dnde coo puedo consultar el tamao del Maximum Segment Lifetime? Pues ejecutando este comando: $ cat /proc/sys/net/ipv4/tcp_n_timeout 30 Que en mi mquina Debian me da un resultado de 30 segundos. En mquinas con Ubuntu el valor acostumbra a ser 60, en mquinas Solaris acostumbra a ser 120. Entonces parece ser que, en mi mquina, tardar 2*MSL, o sea 2*30=60 segundos en liberar una conexin. El problema que hemos experimentado antes es que hay muchos sockets (conexiones) abiertas en estado TIME_WAIT. Cuando llegamos al lmite de conexiones efmeras del sistema, el kernel nos d un error diciendo "umm... me sabe mal, pero no me quedan puertos efmeros". Esto se traduce en el error que nos saca el "curl". O sea, no es problema del comando "curl" que vaya dejando conexiones abiertas, ya que si no tendramos muchas conexiones en estado ESTABLISHED, y no es el caso. Tampoco es problema del kernel, ya que ste implementa el RFC 1122 como dios manda. [PUERTOS EFMEROS] "Ei. Ei, espera. Cuando has empezado a hablar de puertos efmeros y toda esta mierda me he perdido. A ver si te explicas un poquito ms, macho." Veamos. Cuando establecemos una conexin TCP con nuestro navegador a un servidor Web, necesitamos un puerto de origen [3]. Estos puertos, se conocen como puertos efmeros. El protocolo TCP necesita denir un puerto origen y un puerto destino. En nuestro ejemplo, el puerto destino ser el 80 (servidor web), y el puerto origen ser un puerto efmero. El Kernel nos asigna un puerto efmero automticamente cuando establecemos una conexin nueva. Para ver el rango de puertos efmeros que tenemos denido podemos ejecutar: $ cat /proc/sys/net/ipv4/ip_local_port_range 32768 61000 Si hacemos 61000-32768 nos d 28232. Si os jais, es un nmero muy parecido al nmero de sockets en estado TIME_WAIT que tenamos cuando ha empezado a petar todo. Esto es debido a que un socket en estado TIME_WAIT todava es un socket activo. Es lo mismo como si estuviese en estado ESTABLISHED, por lo que est ocupando un puerto efmero. Si acumulamos muchos sockets en estado TIME_WAIT, vamos agotando los puertos efmeros. Cuando llegamos al lmite y tenemos reservados *todos* los puertos efmeros, al kernel no le queda otra que devolver error cada vez que se quiere crear un socket nuevo. Bonito, verdad? [POSIBLES SOLUCIONES] Bueno, una de ellas pasa por aumentar el nmero de puertos efmeros del sistema. Esto se puede conseguir simplemente ejecutando: $ sudo su - root $ echo "1025 61000" > /proc/sys/net/ipv4/ip_local_port_range Hecho esto, ahora disponemos de 60K puertos efmeros y no solo 30K. En realidad esto no es una solucin de nada. Simplemente tendremos que esperar 2 minutos y no 1 para que los procesos "curl" agoten el nmero de sockets. Estamos haciendo que el sistema aguante un poquito mas, pero ya est.

LINKS DE INTERS

Kriptpolis - Criptografa, Privacidad y Seguridad en Internet Ubuntuzando el Planeta GENBETA - Web + software Security by Default La comunidad de DragonJar

SUBSCRIBE VIA EMAIL

Enter your email address:

Subscribe
Delivered by FeedBurner

Otra solucin parece que puede venir modicando el parmetro 2*MSL. Si disminuimos este valor del MSL, los sockets en estado TIME_WAIT deberan estar en este estado durante menos tiempo. El parmetro es ajustable mediante el comando comentado anteriormente: $ sudo su -c 'echo 5 > /proc/sys/net/ipv4/tcp_n_timeout' Si probais de aplicar este cambio vereis que en realidad las conexiones en estado TIME_WAIT no se cierran a los 10 segundos como sera lo esperado (2*MSL; 2*5=10), sino que se siguien cerrando a los 60 segundos. Por qu ocurre esto? Simple. El valor "60 segundos" est hardcoded en el kernel de linux. As de bonito. Si miramos el chero /include/net/tcp.h lnea 105 del kernel de lnux veremos algo tal que as: #dene TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT state, about 60 seconds */

2 de 4

16/07/12 11:29

inedit00: TCP Sockets: TIME_WAIT y los puertos efmero...

http://inedit00.blogspot.com/2012/02/hoy-vamos-explica...

A partir de lnea 202 del chero /net/ipv4/tcp_minisocks.c vereis que hace uso intensivo de la variable TCP_TIMEWAIT_LEN, justo en la seccin donde dene el estado TCP_TIME_WAIT al socket TCP. Por lo que modicar a travs de las sysctls el parmetro "tcp_n_timeout" no va a servir de un carajo. Ni 2*MSL ni pollas. Harcoded en el cdigo. (Esto vulnera el RFC 1122 y la regla 2MSL? Si alguien lo sabe que por favor comente! Gracias )

La ltima solucin, que dista mucho de ser algo perfecto pasa por activar el tcp_tw_recycle y tcp_tw_reuse. Ambas directivas son bastante peligrosas, y vulneran explcitamente el RFC 1122. No deberan usarse en entornos de produccin o sin saber muy bien qu se est haciendo. La documentacin que he encontrado al respecto es [4] y [5]. TCP_TW_RECYCLE: It enables fast recycling of TIME_WAIT sockets. The default value is 0 (disabled). The sysctl documentation incorrectly states the default as enabled. It can be changed to 1 (enabled) in many cases. Known to cause some issues with hoststated (load balancing and fail over) if enabled, should be used with caution. $ echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle TCP_TW_REUSE: This allows reusing sockets in TIME_WAIT state for new connections when it is safe from protocol viewpoint. Default value is 0 (disabled). It is generally a safer alternative to tcp_tw_recycle Note: The tcp_tw_reuse setting is particularly useful in environments where numerous short connections are open and left in TIME_WAIT state, such as web servers. Reusing the sockets can be very eective in reducing server load. $ echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse O sea, usadlos, pero con mucho cuidado.

La solucin denitiva viene en forma de pregunta: Qu coo haceis creando 30K conexiones TCP en menos de un minuto, criaturas del Seor? Si habeis llegado aqu porque os habeis encontrado con el problema del TIME_WAIT en un servidor de produccin cuando reciba bastante trco os tengo que decir algo que no os va gustar: algo estis haciendo mal. En este caso no es suciente con cerrar las conexiones a la BBDD, caches, o lo que sea cada, vez que se hace una consulta. La solucin pasa por hacer pooling de conexiones y dems. REAPROVECHAR conexiones. Pero bueno, esto es otra guerra que se sale del alcance de este post. An as para dudas, ruegos y preguntas teneis los comentarios. Intentar ayudar hasta donde pueda/sepa.

[LTIMAS NOTAS] Ntese que este problema es provocado por la conjuncin de crear muchas conexiones por parte de un CLIENTE (importante este punto) durante un periodo muy corto de tiempo. Esto hace que se acumulen muchos sockets abiertos (bueno, o no-cerrados, para ser mas exactos) en estado TIME_WAIT. Cuando se llega al punto que la suma de todos los sockets en dicho estado es igual al nmero de puertos efmeros de la mquina, el kernel no es capaz de crear sockets nuevos hasta que no se liberan recursos, devolviendo un error a cualquier proceso que intente crear una conexin nueva (ntese que las conexiones ya establecidas seguirn funcionando normalmente). Espero que les haya gustado el post. La zona de comentarios est disponible para hacer preguntas, o proponer soluciones alternativas al problema. Un saludo, Jan. [1] http://danred.wordpress.com/2009/09/28/establecimiento-de-conexion-tcp-de-3-vias/ [2] http://www.rfc-editor.org/rfc/rfc1122.txt pgina 87 [3] Recordemos que un socket est formado por un IP Origen - Puerto Origen - IP Destino - Puerto Destino. [4] http://www.speedguide.net/articles/linux-tweaking-121 [5] http://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

Publicado por inedit00 en 19:05 Etiquetas: linux, red

2 comentarios:
Nicols Andrade 12 de julio de 2012 06:30 Muchas gracias por este texto! Me sacaste muchsimas dudas que tena respecto a mis servidores de produccin. Responder

inedit00

12 de julio de 2012 10:25

Gracias a t por el comentario!! Estoy contento de que te haya servido. No veas para descubrir todo esto nosotros solos en el trabajo. Los sntomas del problema es que el servidor de produccin se caa si le hacas MUCHAS peticiones. Resulta que la capa de servicios de nuestra aplicacin haca unas 100 consultas a MongoDB (que son muy rpidas y esto no est mal) pero sin usar un pool de

3 de 4

16/07/12 11:29

inedit00: TCP Sockets: TIME_WAIT y los puertos efmero...

http://inedit00.blogspot.com/2012/02/hoy-vamos-explica...

conexiones. Fail. Por lo que por cada peticin en la pgina web se hacan 100 consultas a la BBDD, lo que signicaban 100 sockets en TIME WAIT. Se arregl temporalmente con el TCP_RECICLE y TCP_REUSE pero acabamos modicando la aplicacin para que usara Pools de conexiones y problema resuelto. Un saludo! Responder Introduce tu comentario...

Comentar como: Seleccionar perl...

Publicar

Vista previa

Entrada ms reciente Suscribirse a: Enviar comentarios (Atom)

Pgina principal

Entrada antigua

Con la tecnologa de Blogger.

4 de 4

16/07/12 11:29

También podría gustarte