Cerrar enlace TCP TIME_WAIT
Después de actualizar un servicio de aplicación en línea, descubrimos que la disponibilidad del servicio era impredecible: algunas veces estaba disponible para el público y otras veces dejaba de estar disponible repentinamente. Después de iniciar sesión en el host donde está alojado el servicio y verificar con el comando netstat, encontramos que hay miles de conexiones en el host en estado TIME_WAIT.
Después de muchas capas de análisis, descubrimos que TIME_WAIT es el culpable. ¿Por qué sucede esto? Nuestro servicio de aplicaciones necesita proporcionar servicios al mundo exterior iniciando conexiones TCP. Cada conexión ocupa un puerto local. Si hay demasiadas conexiones en el estado TIME_WAIT en condiciones de alta concurrencia, de modo que los puertos locales disponibles se agoten, el servicio de la aplicación no funcionará correctamente. Después de un tiempo, el sistema reciclará y cerrará la conexión TIME_WAIT, lo que liberará el puerto local para su uso y el servicio de la aplicación parecerá funcionar normalmente. Esto se puede hacer repetidamente para que tenga un período de inactividad seguido de uno o dos minutos de funcionamiento normal.
Entonces, ¿por qué hay tantas conexiones TIME_WAIT? Esto comienza con las cuatro ondas de TCP. Escribí esta imagen en mi manuscrito.
Cuando finaliza la conexión TCP, el host 1 primero envía un mensaje FIN. El host 2 ingresa al estado CLOSE_WAIT y envía una respuesta ACK. El host 2 obtiene EOF al leer la llamada y notifica a la aplicación que cierre activamente la conexión. operación enviando un mensaje FIN. El host 1 recibe el mensaje FIN y envía una respuesta ACK, momento en el que el host 1 ingresa al estado TIME_WAIT.
El tiempo que el host 1 permanece en TIME_WAIT es fijo, hasta 10 segundos. El host 1 permanece en TIME_WAIT durante un período de tiempo fijo, el doble de la vida útil máxima del segmento (MSL), comúnmente conocido como 2 MSL. Como la mayoría de los derivados de BSD, Linux tiene un campo codificado llamado TCP_TIMEWAIT_LEN con un valor de 60 segundos. En otras palabras, el sistema Linux permanecerá en TIME_WAIT durante 60 segundos fijos.
El host 1 entrará entonces en estado de apagado. ¿Por qué esta vez?
Solo la parte que inicia la terminación de la conexión ingresará al estado TIME_WAIT.
En primer lugar, esto es para garantizar que la parte de cierre pasivo reciba el último ACK para ayudarle a cerrar correctamente.
TCP está diseñado para ser totalmente tolerante a fallos; por ejemplo, TCP supone que los mensajes producirán errores y deberán retransmitirse. Aquí, si el mensaje ACK del Host 1 en la figura no se transmite correctamente, el Host 2 retransmitirá el mensaje FIN.
Si el host 1 no permanece en el estado TIME_WAIT, sino que ingresa directamente al estado CERRADO, perderá el contexto del estado actual y solo podrá responder mediante la operación RST, lo que generará un error en el lado de apagado pasivo.
Ahora que el Host 1 sabe que está en el estado TIME_WAIT, puede volver a emitir el mensaje ACK después de recibir el mensaje FIN, lo que permite que el Host 2 ingrese al estado CERRADO normal.
La segunda razón tiene que ver con las "encarnaciones" de conexiones y los mensajes errantes, para permitir que segmentos duplicados de conexiones antiguas desaparezcan naturalmente en la red.
Sabemos que en la red, por diversos motivos (como reinicio del router o fallo repentino del enlace), los mensajes suelen tardar un tiempo en llegar a su destino. Si llega un paquete perdido y la conexión representada por la conexión TCP cuádruple (IP de origen, puerto de origen, IP de destino, puerto de destino) ya no existe, entonces el paquete se descartará naturalmente.
Consideremos un escenario donde se interrumpe la conexión original y luego se recrea el "avatar" de la conexión original, que en realidad es un avatar porque la conexión es exactamente igual que el quad de conexión original, si un segmento Si el mensaje perdido se recibe después de un cierto período de tiempo, se confundirá con el "avatar" de la conexión, que es la conexión original cuádruple. Si el paquete perdido llega después de un período de tiempo, se confundirá con un segmento TCP de la "encarnación" de la conexión, lo que tendrá un impacto en las comunicaciones TCP.
Por lo tanto, TCP diseñó un mecanismo según el cual 2MSL es lo suficientemente largo como para que los paquetes en ambas direcciones sean descartados, de modo que los paquetes de conexión originales desaparezcan naturalmente de la red y vuelvan a aparecer. generado por la nueva encarnación.
El primero es el uso de memoria. En la actualidad, parece que no es un gran problema y básicamente se puede ignorar.
El segundo es la ocupación de recursos del puerto. Una conexión TCP ocupa al menos un puerto local. Cabe señalar que los recursos del puerto también son limitados. Los puertos abiertos suelen ser 32768?61000, que también se pueden especificar a través de net.ipv4.ip_local_port_range. Si hay demasiados estados TIME_WAIT, no se pueden crear nuevas conexiones.
El método forzado es utilizar el comando sysctl para reducir el valor del sistema. Este valor predeterminado es 18000; una vez que el número de conexiones TIME_WAIT en el sistema excede este valor, el sistema restablecerá todas las conexiones TIME_WAIT y solo imprimirá un mensaje de advertencia. Este método es demasiado tosco y causa más problemas de los que resuelve, por lo que no se recomienda.
Este método es bueno, pero la desventaja es que requiere "un poco" de conocimiento del kernel para recompilarlo.
Este método es bueno, pero la desventaja es que requiere "un Poco" conocimiento del kernel para recompilar el kernel. Compile el kernel