Escenario: Tenemos un número de clientes de Windows que regularmente suben archivos grandes (FTP/SVN/HTTP PUT/SCP) a servidores Linux que están a ~100-160ms de distancia. Tenemos un ancho de banda síncrono de 1 Gbit/s en la oficina y los servidores son instancias de AWS o están alojados físicamente en centros de distribución estadounidenses.
El informe inicial fue que las subidas a una nueva instancia del servidor eran mucho más lentas de lo que podrían ser. Esto se comprobó en las pruebas y desde múltiples ubicaciones; los clientes veían una velocidad estable de 2-5Mbit/s hacia el host desde sus sistemas Windows.
Me he escapado iperf -s
en una instancia de AWS y luego desde un Windows cliente en la oficina:
iperf -c 1.2.3.4
[ 5] local 10.169.40.14 port 5001 connected with 1.2.3.4 port 55185
[ 5] 0.0-10.0 sec 6.55 MBytes 5.48 Mbits/sec
iperf -w1M -c 1.2.3.4
[ 4] local 10.169.40.14 port 5001 connected with 1.2.3.4 port 55239
[ 4] 0.0-18.3 sec 196 MBytes 89.6 Mbits/sec
Esta última cifra puede variar significativamente en las pruebas posteriores, (Vagabundos de AWS) pero suele estar entre 70 y 130Mbit/s lo que es más que suficiente para nuestras necesidades. Wiresharking la sesión, puedo ver:
iperf -c
Windows SYN - Window 64kb, Scale 1 - Linux SYN, ACK: Window 14kb, Scale: 9 (*512)iperf -c -w1M
Windows SYN - Windows 64kb, Escala 1 - Linux SYN, ACK: Window 14kb, Escala: 9
Está claro que el enlace puede sostener este alto rendimiento, pero tengo que establecer explícitamente el tamaño de la ventana para hacer algún uso de ella, lo que la mayoría de las aplicaciones del mundo real no me permiten hacer. Los handshakes TCP utilizan los mismos puntos de partida en cada caso, pero el forzado escala
Por el contrario, desde un cliente Linux en la misma red una recta, iperf -c
(utilizando los 85kb por defecto del sistema) me da:
[ 5] local 10.169.40.14 port 5001 connected with 1.2.3.4 port 33263
[ 5] 0.0-10.8 sec 142 MBytes 110 Mbits/sec
Sin ningún tipo de forzamiento, escala como se esperaba. Esto no puede ser algo en los saltos intermedios o nuestros switches/routers locales y parece afectar a los clientes de Windows 7 y 8 por igual. He leído un montón de guías sobre el ajuste automático, pero estos son por lo general acerca de la desactivación de la escala por completo para trabajar en torno a mal kit de red doméstica terrible.
¿Alguien puede decirme qué está pasando aquí y darme una forma de solucionarlo? (Preferiblemente algo que pueda meter en el registro a través de GPO).
Notas
La instancia de AWS Linux en cuestión tiene la siguiente configuración del kernel aplicada en sysctl.conf
:
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
net.ipv4.tcp_rmem = 4096 1048576 16777216
net.ipv4.tcp_wmem = 4096 1048576 16777216
He utilizado dd if=/dev/zero | nc
redirigiendo a /dev/null
en el extremo del servidor para descartar iperf
y eliminar cualquier otro posible cuello de botella, pero los resultados son prácticamente los mismos. Las pruebas con ncftp
(Cygwin, Native Windows, Linux) escalan de forma muy similar a las pruebas iperf anteriores en sus respectivas plataformas.
Editar
He visto otra cosa consistente aquí que podría ser relevante:
Este es el primer segundo de la captura de 1MB, ampliado. Se puede ver Inicio lento en acción a medida que la ventana se amplía y el buffer se hace más grande. Hay entonces esta pequeña meseta de ~0.2s exactamente en el punto en el que la prueba iperf de la ventana por defecto se aplana para siempre. Este, por supuesto, escala a alturas mucho más vertiginosas, pero es curioso que haya esta pausa en el escalado (los valores son 1022bytes * 512 = 523264) antes de hacerlo.
Actualización - 30 de junio.
Seguimiento de las distintas respuestas:
- Activar CTCP - Esto no supone ninguna diferencia; el escalado de la ventana es idéntico. (Si lo he entendido bien, este ajuste aumenta la velocidad a la que se amplía la ventana de congestión en lugar del tamaño máximo que puede alcanzar)
- Habilitar las marcas de tiempo TCP. - Aquí tampoco hay cambios.
- Algoritmo de Nagle - Eso tiene sentido y, al menos, significa que probablemente puedo ignorar ese parpadeo particular en el gráfico como cualquier indicación del problema.
- archivos pcap: Archivo zip disponible aquí: https://www.dropbox.com/s/104qdysmk01lnf6/iperf-pcaps-10s-Win%2BLinux-2014-06-30.zip (Anonimizado con bittwiste, extrae hasta ~150MB ya que hay uno de cada cliente del SO para comparar)
Actualización 2 - 30 de junio
O, así que siguiendo la sugerencia de Kyle, he habilitado el ctcp y desactivado la descarga de la chimenea: Parámetros globales TCP
----------------------------------------------
Receive-Side Scaling State : enabled
Chimney Offload State : disabled
NetDMA State : enabled
Direct Cache Acess (DCA) : disabled
Receive Window Auto-Tuning Level : normal
Add-On Congestion Control Provider : ctcp
ECN Capability : disabled
RFC 1323 Timestamps : enabled
Initial RTO : 3000
Non Sack Rtt Resiliency : disabled
Pero, lamentablemente, no hay cambios en el rendimiento.
Sin embargo, tengo una pregunta de causa/efecto: Los gráficos son del valor RWIN establecido en los ACKs del servidor al cliente. Con los clientes de Windows, ¿estoy en lo cierto al pensar que Linux no está escalando este valor más allá de ese punto bajo porque el CWIN limitado del cliente impide que se llene incluso ese buffer? ¿Podría haber alguna otra razón por la que Linux está limitando artificialmente el RWIN?
Nota: He probado a activar el ECN por si acaso; pero ningún cambio, ahí.
Actualización 3 - 31 de junio.
No hay cambios tras desactivar la heurística y el autoajuste RWIN. He actualizado los controladores de red de Intel a la última (12.10.28.0) con el software que expone los ajustes de funcionalidad en las pestañas del administrador de dispositivos. La tarjeta es un 82579V Chipset on-board NIC - (Voy a hacer más pruebas de los clientes con realtek u otros proveedores)
Centrándome en la NIC por un momento, he probado lo siguiente (sobre todo descartando culpables poco probables):
- Aumentar los búferes de recepción de 256 a 2k y los de transmisión de 512 a 2k (ambos al máximo) - Sin cambios
- Desactivó toda la descarga de sumas de comprobación IP/TCP/UDP. - No hay cambios.
- Desactivación de la descarga de envíos grandes - Nada.
- Desactivado IPv6, programación QoS - Nada.
Actualización 3 - 3 de julio
Tratando de eliminar el lado del servidor Linux, inicié una instancia de Server 2012R2 y repetí las pruebas usando iperf
(binario cygwin) y NTttcp .
Con iperf
Tuve que especificar explícitamente -w1m
en ambos lados antes de que la conexión escalara más allá de ~5Mbit/s. (Por cierto, he podido comprobarlo y el BDP de ~5Mbits a 91ms de latencia es casi precisamente 64kb. Es el límite...)
Los binarios ntttcp mostraban ahora dicha limitación. Usando ntttcpr -m 1,0,1.2.3.5
en el servidor y ntttcp -s -m 1,0,1.2.3.5 -t 10
en el cliente, puedo ver un rendimiento mucho mejor:
Copyright Version 5.28
Network activity progressing...
Thread Time(s) Throughput(KB/s) Avg B / Compl
====== ======= ================ =============
0 9.990 8155.355 65536.000
##### Totals: #####
Bytes(MEG) realtime(s) Avg Frame Size Throughput(MB/s)
================ =========== ============== ================
79.562500 10.001 1442.556 7.955
Throughput(Buffers/s) Cycles/Byte Buffers
===================== =========== =============
127.287 308.256 1273.000
DPCs(count/s) Pkts(num/DPC) Intr(count/s) Pkts(num/intr)
============= ============= =============== ==============
1868.713 0.785 9336.366 0.157
Packets Sent Packets Received Retransmits Errors Avg. CPU %
============ ================ =========== ====== ==========
57833 14664 0 0 9.476
8MB/s lo pone a los niveles que estaba obteniendo con Windows explícitamente grande en iperf
. Extrañamente, sin embargo, 80MB en 1273 buffers = un buffer de 64kB de nuevo. Un wireshark adicional muestra un buen RWIN variable que regresa del servidor (factor de escala 256) que el cliente parece cumplir; así que tal vez ntttcp está reportando mal la ventana de envío.
Actualización 4 - 3 de julio
A petición de @karyhead, he hecho más pruebas y he generado algunas capturas más, aquí: https://www.dropbox.com/s/dtlvy1vi46x75it/iperf%2Bntttcp%2Bftp-pcaps-2014-07-03.zip
- Dos más
iperf
s, ambos desde Windows al mismo servidor Linux que antes (1.2.3.4): Uno con un tamaño de Socket de 128k y ventana de 64k por defecto (restringe a ~5Mbit/s de nuevo) y otro con una ventana de envío de 1MB y tamaño de socket de 8kb por defecto. (escala más alto) - Una
ntttcp
traza desde el mismo cliente de Windows a una instancia EC2 de Server 2012R2 (1.2.3.5). aquí, el rendimiento escala bien. Nota: NTttcp hace algo extraño en el puerto 6001 antes de abrir la conexión de prueba. No estoy seguro de lo que está sucediendo allí. - Un rastreo de datos FTP, cargando 20MB de
/dev/urandom
a un host linux casi idéntico (1.2.3.6) usando Cygwinncftp
. De nuevo el límite está ahí. El patrón es muy parecido usando Windows Filezilla.
Cambiar la iperf
La longitud del búfer marca la diferencia esperada en el gráfico de la secuencia temporal (muchas más secciones verticales), pero el rendimiento real no cambia.
11 votos
Un raro caso de un problema bien investigado que no está obviamente en la documentación. Bonito - esperemos que alguien encuentre una solución (porque de alguna manera creo que también me puede servir).
2 votos
Intente activar las marcas de tiempo RFC 1323, ya que están desactivadas por defecto en Windows, mientras que Linux las tiene activadas por defecto).
netsh int tcp set global timestamps=enabled
3 votos
El retraso de 200 ms es probablemente el algoritmo de Nagle en acción. A medida que los datos son recibidos por TCP en una conexión particular, envía un acuse de recibo de vuelta sólo si una de las siguientes condiciones es verdadera: No se envió ningún acuse de recibo para el segmento anterior recibido; Se recibe un segmento, pero no llega ningún otro segmento dentro de los 200 milisegundos para esa conexión.
2 votos
¿Hay alguna posibilidad de poner algunas capturas de paquetes de uno de los remitentes más lentos en algún lugar?
0 votos
He actualizado mi OP con los resultados de estas pruebas y los enlaces a los archivos de captura representativos.
0 votos
@SmallClanger: Respecto a "¿Podría haber alguna otra razón por la que Linux esté limitando artificialmente el RWIN?". No estoy seguro, pero estaría de acuerdo con tu teoría de que el RWIN no aumenta porque nunca está bajando. Sería una tontería hacerlo, porque eso significaría un mayor uso de memoria cuando no hay ninguna razón para tomar más memoria para el buffer de recepción.
0 votos
@SmallClanger: Mira también "Análisis de expertos" en las dos capturas. En la de Linux a Linux, se ven mensajes de ventana cero, acks duplicados, etc. Esto es en realidad lo que uno esperaría ver, ya que TCP es llevado a su límite y entonces impone algún control de flujo. En el caso de Windows a Linux, todo está limpio porque TCP no está "probado".
0 votos
@SmallClanger: Ah, y para ayudar a aclarar, mi gráfico si lo entiendo bien muestra el RWIN como está actualmente en el tiempo. En otras palabras, se trata de "bytes actualmente disponibles" en el buffer. Así que el RWIN siempre tiene mucho espacio.
0 votos
@SmallClanger: Otra suposición, prueba a jugar con
netsh int tcp show heuristics
/netsh interface tcp show heuristics disabled|enabled
0 votos
¿Son clientes de Windows 7 y más? Es una mierda. Desactivar el autotuning normalmente me lo arreglaba. Pero este parche parece que no se instala normalmente y parece solucionar el problema que describes. support.microsoft.com/kb/983528 .
0 votos
Netsh interface tcp set global autotuning=disabled suele funcionarme.
0 votos
@Matt Esta fue una de las primeras cosas que probé. Según tengo entendido el autotuning tiene que ver puramente con el RWIN y el ancho de banda de bajada. (Esto parece ser restringido de manera similar, pero el cambio de la configuración de sintonización automática no tuvo ningún efecto).
0 votos
@SmallClanger: ¿Cuál es la versión de tcpip.sys en tu sistema de pruebas?
0 votos
@GregAskew 6.1.7601.22648 en el cliente Win7SP1. 6.3.9600.17088 en el cliente Win8.1.
0 votos
Al paso que vamos parece que la respuesta correcta va a ser "Cambia todos tus clientes a Linux" ;-)
0 votos
@KyleBrandt - Probablemente aceptaría "lol, usa linux, nub" como respuesta. Parece el camino de menor resistencia en este momento :)
0 votos
@SmallClanger ¿has encontrado alguna solución? Me encuentro con el mismo problema.
0 votos
@AndréBorie - No lo he hecho. El problema que estaba bloqueado por esto (para mí) ha desaparecido y no he tenido tiempo de trabajar con algunas de las soluciones posteriores basadas en el registro sugeridas aquí. FWIW, estoy seguro de que CTCP es la ruta correcta, pero creo que hay problemas de implementación de TCP con ciertos paquetes de software que son el cuello de botella, incluso cuando CTCP está configurado correctamente.