socket servidor recibir programming online metodos geeks for enviar ejemplos datos datagrama concepto con cliente clase calculadora java sockets tcp nio low-latency

servidor - Problema de rendimiento de socket Java TCP/IP



sockets java (4)

Nuestra aplicación está leyendo datos muy rápido sobre sockets TCP / IP en Java. Estamos utilizando la biblioteca NIO con Sockets y Selector sin bloqueo para indicar que está listo para leer. En promedio, los tiempos generales de procesamiento para leer y manejar los datos leídos son de menos de milisegundos. Sin embargo, con frecuencia vemos picos de 10-20 milisegundos. (corriendo en Linux).

Usando tcpdump podemos ver la diferencia de tiempo entre la lectura de tcpdump de 2 mensajes discretos, y comparar eso con nuestro tiempo de aplicación. Vemos que tcpdump parece no tener retraso, mientras que la aplicación puede mostrar 20 milisegundos.

Estamos bastante seguros de que esto no es GC, porque el registro del GC prácticamente no muestra el GC completo, y en JDK 6 (por lo que entiendo) el GC predeterminado es paralelo, por lo que no debería detener los hilos de la aplicación (a menos que haga GC completo) .

Parece casi como si hubiera algún retraso para que el método Selector.select(0) Java devuelva la disponibilidad para leer, porque en la capa TCP, los datos ya están disponibles para ser leídos (y tcpdump lo está leyendo).

Información adicional: a una carga máxima estamos procesando aproximadamente 6.000 x 150 bytes de media por mensaje, o alrededor de 900 MB por segundo.


¿Su código Java se está ejecutando bajo RTLinux, o alguna otra distribución con capacidad de programación en tiempo real? Si no, 10-20 mseg de jitter en los tiempos de procesamiento parece completamente razonable y esperado.


Desde el faq de tcpdump :

¿CUÁNDO HAY UN PAQUETE CON EL TIEMPO INDICADO? ¿CUÁN PRECISO ES EL TIEMPO DE SELLOS?

En la mayoría de los sistemas operativos en los que se ejecutan tcpdump y libpcap, el paquete tiene un sello de tiempo como parte del proceso del controlador de dispositivo de la interfaz de red, o la pila de red, que lo maneja. Esto significa que el paquete no tiene marca de tiempo en el instante en que llega a la interfaz de red; una vez que el paquete llega a la interfaz de red, habrá una demora hasta que se entregue una interrupción o se encuente la interfaz de red (es decir, la interfaz de red podría no interrumpir el host de inmediato; el controlador puede configurarse para sondear la interfaz si la red el tráfico es intenso, para reducir el número de interrupciones y procesar más paquetes por interrupción), y habrá un retraso adicional entre el momento en que la interrupción comienza a procesarse y se genera la marca de tiempo.

Por lo tanto, las probabilidades son que la marca de tiempo se crea en la capa de kernel privilegiado y la pérdida de 20 ms se refiere a la sobrecarga de conmutación de contexto al espacio de usuario y a Java y la lógica de selector de red de las JVM. Sin más análisis del sistema como un todo, no creo que sea posible hacer una selección afirmativa de la causa.


La colección eden todavía incurre en una pausa STW por lo que 20 ms puede ser perfectamente normal dependiendo del comportamiento de la asignación y el tamaño / tamaño del montón del Live Set.


Tuve el mismo problema en un servicio de Java en el que trabajo. Al enviar repetidamente la misma solicitud al cliente, el servidor bloquearía en el mismo lugar en la corriente durante 25-35 ms. Apagar el algoritmo de Nagle en el socket me solucionó esto. Esto se puede lograr llamando a setTcpNoDelay (verdadero) en el Socket. Esto puede provocar una mayor congestión de la red porque los ACK ahora se enviarán como paquetes separados. Consulte http://en.wikipedia.org/wiki/Nagle%27s_algorithm para obtener más información sobre el algoritmo de Nagle.