¿Por qué un servidor no enviaría un paquete SYN / ACK en respuesta a un paquete SYN?

46

Últimamente, nos hemos dado cuenta de un problema de conexión TCP que se limita principalmente a los usuarios de Mac y Linux que navegan por nuestros sitios web.

Desde la perspectiva del usuario, se presenta como un tiempo de conexión muy largo con nuestros sitios web (> 11 segundos).

Hemos logrado rastrear la firma técnica de este problema, pero no podemos entender por qué está sucediendo o cómo solucionarlo.

Básicamente, lo que sucede es que la máquina del cliente está enviando el paquete SYN para establecer la conexión TCP y el servidor web lo recibe, pero no responde con el paquete SYN / ACK. Después de que el cliente ha enviado muchos paquetes SYN, el servidor finalmente responde con un paquete SYN / ACK y todo está bien para el resto de la conexión.

Y, por supuesto, la patada al problema: es intermitente y no ocurre todo el tiempo (aunque ocurre entre el 10 y el 30% del tiempo)

Estamos utilizando Fedora 12 Linux como sistema operativo y Nginx como servidor web.

Captura de pantalla del análisis de Wirehark

Captura de pantalla del análisis de Wirehark

Actualizar:

Desactivar el escalado de la ventana en el cliente detuvo el problema. Ahora solo necesito una resolución del lado del servidor (no podemos hacer que todos los clientes hagan esto) :)

Actualización final:

La solución fue desactivar el escalado de ventanas TCP y las marcas de tiempo TCP en nuestros servidores que son accesibles al público.

codemonkey
fuente
1
Creo que tendremos que ver que suceda algo.
coredump
¿Tiene alguna acls o reglas basadas en DNS inverso? Es posible que necesite ver más que solo la conexión entre el cliente y el servidor. Tal vez una búsqueda de DNS está agotando el tiempo de espera?
Zoredache
@coredump: aquí hay una captura de pantalla del análisis de Wirehark que muestra el problema i.imgur.com/Bnzrm.png (no pude descubrir cómo exportar solo la transmisión ...)
codemonkey
@ Zoredache: no, no tenemos ninguna acls o reglas basadas en DNS inverso. Este es un servidor web público y permitimos que todos accedan a él
codemonkey
Solo una corazonada, pero ¿está haciendo algún tipo de limitación de velocidad de conexión entrante en el servidor? Digamos, con iptables?
Steven lunes

Respuestas:

15

Tuvimos exactamente el mismo problema. Solo deshabilitar las marcas de tiempo TCP resolvió el problema.

sysctl -w net.ipv4.tcp_timestamps=0

Para que este cambio sea permanente, ingrese una entrada /etc/sysctl.conf.

Tenga mucho cuidado al deshabilitar la opción Escala de ventana TCP. Esta opción es importante para proporcionar el máximo rendimiento a través de Internet. Alguien con una conexión de 10 megabit / seg tendrá una transferencia subóptima si el tiempo de ida y vuelta (básicamente igual que el ping) es superior a 55 ms.

Realmente notamos este problema cuando había múltiples dispositivos detrás del mismo NAT. Sospecho que el servidor podría haberse confundido al ver marcas de tiempo de dispositivos Android y máquinas OSX al mismo tiempo, ya que ponen valores completamente diferentes en los campos de marca de tiempo.

mcdizzle
fuente
44
En caso de que alguien más termine aquí por el mismo agujero del conejo que acabo de bajar: antes de desactivar las marcas de tiempo TCP o el escalado de ventanas, lo que puede tener graves consecuencias de rendimiento en un enlace de alto tráfico, verifique si tcp_tw_recycle es su problema: stackoverflow .com / preguntas / 8893888 / ...
nephtes
12

En mi caso, el siguiente comando solucionó el problema con la falta de respuestas SYN / ACK del servidor Linux:

sysctl -w net.ipv4.tcp_tw_recycle=0

Creo que es más correcto que deshabilitar las marcas de tiempo TCP, ya que las marcas de tiempo TCP son útiles para un alto rendimiento (PAWS, escalado de ventanas, etc.).

La documentación tcp_tw_recycleindica explícitamente que no se recomienda habilitarlo, ya que muchos enrutadores NAT conservan las marcas de tiempo y, por lo tanto, se activa PAWS, ya que las marcas de tiempo de la misma IP no son consistentes.

   tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)
          Enable fast recycling of TIME_WAIT sockets.  Enabling this
          option is not recommended for devices communicating with the
          general Internet or using NAT (Network Address Translation).
          Since some NAT gateways pass through IP timestamp values, one
          IP can appear to have non-increasing timestamps.  See RFC 1323
          (PAWS), RFC 6191.
lav
fuente
1
buena explicación aquí: vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux En el lado del servidor, no habilite net.ipv4.tcp_tw_recycle a menos que esté bastante seguro de que nunca tendrá dispositivos NAT en la mezcla.
Gnought
1
En mi caso, net.ipv4.tcp_tw_recyclees la verdadera razón. Gracias.
bluearrow
tcp_tw_recycle se ha eliminado en núcleos recientes. ¿Hay otra solución igual? @nephtes implica que deshabilitar la marca de tiempo perjudica el rendimiento.
MappaM
Como tcp_tw_recycle se ha eliminado, el problema no debería volver a ocurrir, ya que solo ocurrió con un valor no predeterminado de tcp_tw_recycle.
Lav
5

Me pregunto, pero ¿por qué para el paquete SYN (marco # 539; el que fue aceptado), faltan los campos WS y TSV en la columna "Información"?

WS es TCP Window Scaling y TSV es Timestamp Value . Ambos se encuentran en el campo tcp.options y Wireshark aún debería mostrarlos si están presentes. ¿Tal vez la pila TCP / IP del cliente reenvió un paquete SYN diferente en el octavo intento y esa fue la razón por la que se reconoció de repente?

¿Podría proporcionarnos los valores internos del marco 539? ¿SYN / ACK siempre viene para un paquete SYN que no tiene WS habilitado?

Hans Solo
fuente
@Ansis: aquí hay algunas capturas de pantalla para los detalles del cuadro 539 (tuve que hacerlo en dos partes): i.imgur.com/D84GC.png e i.imgur.com/4riq3.png
codemonkey
@codemonkey: su octavo paquete SYN parece ser diferente de los primeros siete paquetes SYN. ¿El servidor responde con SYN / ACK al SYN del cliente solo cuando el campo tcp.options tiene un tamaño de 8 bytes (los primeros siete paquetes SYN probablemente tengan tcp.options de tamaño 20 bytes)? ¿Puede deshabilitar el escalado de la ventana TCP en el lado del cliente para ver si el problema desaparece? Parece un problema con la pila TCP / IP en el lado del servidor o el firewall mal configurado en alguna parte ...
Hans Solo
@Ansis: sí, he estado mirando eso desde que lo señaló y todos los demás paquetes SYN son de 24 bytes. Intentaré deshabilitar el escalado de ventanas en el cliente y volveré a verificar los resultados por la mañana.
codemonkey
@Ansis: al desactivar el escalado de ventanas en el cliente, se detuvo el problema. ¡Gracias! Sin embargo, ahora necesito descubrir cómo solucionar esto en el lado del servidor (ya que no podemos hacer que todos nuestros clientes deshabiliten el escalado de Windows) :) El servidor en cuestión tiene net.ipv4.tcp_windows_scaling = 1
codemonkey
@Codemonkey: Estoy de acuerdo en que deshabilitar WS en todos los clientes no es una solución, pero al menos hemos rastreado el problema hasta WS / Packet Size. Para encontrar aún más la causa, debemos analizar cómo está configurado su firewall. ¿Se pueden establecer conexiones TCP con WS a diferentes puertos TCP? ¿De diferentes fuentes de IP?
Hans Solo
4

Nos encontramos exactamente con el mismo problema (realmente nos llevó bastante tiempo fijarlo al servidor sin enviar sincronización).

"La solución fue desactivar el escalado de ventanas tcp y las marcas de tiempo tcp en nuestros servidores que son accesibles al público".

Alex Li
fuente
2

Para continuar con lo que ha dicho Ansis, he visto problemas como este cuando el cortafuegos no es compatible con TCP Windows Scaling. ¿Qué firewall de marca / modelo hay entre estos dos hosts?

joeqwerty
fuente
El firewall es un cuadro de Fedora 13 que usa iptables. net.ipv4.tcp_windows_scaling también está configurado en 1 en esta máquina
codemonkey
2

La falta de SYN / ACK podría deberse a límites demasiado bajos de su protección SYNFLOOD en el firewall. Depende de cuántas conexiones crea el usuario del servidor. El uso de spdy reduciría el número de conexiones y podría ayudar en una situación en la que net.ipv4.tcp_timestampsapagar no ayuda.

brablc
fuente
1

Este es el comportamiento de un socket TCP de escucha cuando su reserva está llena.

Ngnix permite que el argumento del backlog para escuchar se establezca en la configuración: http://wiki.nginx.org/HttpCoreModule#listen

escuchar 80 backlog = num

Intente configurar num a algo más grande que el predeterminado, como 1024.

No garantizo que una cola de escucha completa sea realmente su problema, pero esto es una buena primera cosa para verificar.

akramer
fuente
gracias por el consejo. Lo intentaré. Hemos establecido la acumulación en el nivel del sistema operativo, pero no explícitamente en la configuración de Nginx. Actualizaré con el resultado.
codemonkey
no cambió el comportamiento en absoluto. Supongo que no es el problema. o el único problema ...
codemonkey
1
el parámetro de registro de nivel de aplicación controla el tamaño de la cola para las conexiones tcp completadas, es decir, el apretón de manos de 3 vías finalizado, es decir, la sincronización recibida, por lo que no coincide con la situación de OP
ygrek
1

Acabo de descubrir que los clientes TCP de Linux cambian su paquete SYN después de 3 intentos y eliminan la opción Escala de ventana. Supongo que los desarrolladores del kernel pensaron que esta es una causa común de falla de conexión en Internet

Explica por qué estos clientes logran conectarse después de 11 segundos (el TCP SYN sin ventanas ocurre después de 9 segundos en mi breve prueba con la configuración predeterminada)

Jeroen van Bemmel
fuente
0

Tuve un problema similar, pero en mi caso fue la suma de verificación TCP la que se calculó incorrectamente. El cliente estaba detrás de un veth y ejecutando ethtool -K veth0 rx off tx off hizo el truco.

Baroudi Safwen
fuente