2011-03-14 15 views
10

Nuestra aplicación está leyendo datos muy rápido a través de zócalos 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).Problema de rendimiento de socket TCP/IP de Java

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

Estamos bastante seguros de que esto no es GC, porque el registro del GC no muestra prácticamente GC completo, y en JDK 6 (por lo que entiendo) el GC predeterminado es paralelo, por lo que no debería detenerse haciendo Full GC).

Parece casi como si hay algún retraso para Selector.select(0) método de Java para devolver la disposición a leer, porque en la capa TCP, que los datos ya está disponible para ser leído (y tcpdump lo está leyendo).

Información adicional: en la carga máxima estamos procesando aproximadamente 6,000 x 150 bytes de media por mensaje, o aproximadamente 900 MB por segundo.

+0

Como dijo @Jim Lewis, es probable que haya una pérdida de tiempo debido al cambio de contexto, y no se puede controlar cómo implementa Java NIO internamente. Es completamente posible que la JVM agregue algunos gastos generales que no podrá eliminar. Dicho esto, sin ver más datos, realmente no puedo ofrecer una solución. –

+2

Bueno, limpié mis respuestas no aceptadas. No quiero que nadie piense que no valoro el tiempo que tomaron para responder la pregunta. –

+0

Podría ayudar a dar algunos detalles sobre jvm, kernel/distro, hardware – Matt

Respuesta

4

eden colección todavía incurre en una pausa STW por lo que 20ms puede ser perfectamente normal en función del comportamiento de asignación & tamaño/tamaño del conjunto en vivo.

+0

Después de muchas más pruebas, creación de perfiles, etc. Concluimos que GC, incluso el GC menor que usa ParallelGC parece detener todo. Las pausas varían de 2 ms a 20 ms. Hacer que el código sea más eficiente podría reducir el número de ciclos de GC, y quizás incluso el tiempo de GC. Entonces, esto afecta la latencia de las comunicaciones de socket, y parece que no se puede hacer nada. Probamos RTLinux, por lo que no hubo una mejoría importante. Comenzamos a investigar Realtime Java, pero no creíamos que fuera la mejor vía (costo-sabio y complejidad-sabio). –

+0

LA MAYORÍA del CMS está en paralelo. Solo hay una parte muy pequeña de STW ... que parece ser la de 20ms que ves (podrías atarla a los registros de GC).Si desea pausas predecibles, puede consultar el recopilador G1, pero tendrá más pausas generales que el CMS. – bwawok

3

¿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.

+0

No esperaría una fluctuación de 10-20ms para cualquier caja moderna que no esté seriamente sobrecargada, incluso unos pocos 00 son muchos. – Matt

+0

@Matt: Según tengo entendido, 10 ms es un valor típico para la longitud de una división de tiempo en un planificador de Linux/x86 no en tiempo real. Por lo tanto, si la llamada select() genera la CPU, podría tardar tanto tiempo para que ese trabajo se programe nuevamente. –

+0

Estoy tratando de entender su comentario: estamos ejecutando Red Hat Enterprise 5.4. 2 CPUs La máquina está ocupada principalmente con la aplicación Java y MySQL. Desactivar la actualización de la base de datos u otros procesos en el servidor parece no tener ningún impacto en los picos de latencia. ¿Cree que podemos abordar esto cambiando a una distribución de RTLinux? –

1

Desde el tcpdump faq:

cuando es troquelada vez que un paquete? CÓMO PRECISAR SON LAS HORAS DE TIEMPO?

En la mayoría de los sistemas operativos en los que tcpdump y carrera libpcap, el paquete es el tiempo sellada como parte del proceso de controlador de dispositivo de la interfaz de red o la pila de red, el manejo de la misma. Esto significa que el paquete no tiene el tiempo sellado en el instante en que llega al en la interfaz de red; después del paquete llega a la interfaz de red , habrá un retraso hasta se entrega una interrupción o la interfaz red se sondea (es decir, la interfaz red podría no interrumpe el anfitrión inmediatamente - el conductor puede ajustarse hasta sondear la interfaz si tráfico de la red es pesado, para reducir el número de interrupciones y procesar paquetes más por interrupción), y hay habrá un retraso adicional entre el punto de en el que comienza la interrupción siendo procesado y el la marca de tiempo es generada.

Así que las probabilidades son, la marca de tiempo se realiza en la capa del núcleo privilegiado, y los 20 ms perdidos es el contexto de conmutación de cabeza de nuevo a espacio de usuario y en Java y la lógica de selección de red JVM. Sin más análisis del sistema como un todo, no creo que sea posible hacer una selección afirmativa de la causa.

+0

Estaba hablando de su respuesta con otros tipos en nuestra oficina. Señalaron que los picos que estamos viendo son de hasta 40 ms. diferencia de tcpdump. Esa parece ser una diferencia demasiado grande para ser explicada por lo anterior. Es realmente el comportamiento inconsistente "spiking" que estamos tratando de corregir. –

+1

¿Está seguro de haber eliminado las operaciones de GC como una causa? ¿Qué porcentaje de solicitudes da como resultado un "pico"? –

2

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