java c++ performance ipc latency

el método más rápido(baja latencia) para la comunicación entre procesos entre Java y C/C++



performance ipc (10)

¿Ha considerado mantener los enchufes abiertos, para que las conexiones puedan reutilizarse?

Tengo una aplicación Java que se conecta a través de un socket TCP a un "servidor" desarrollado en C / C ++.

tanto la aplicación como el servidor se ejecutan en la misma máquina, una caja de Solaris (pero estamos considerando migrar a Linux eventualmente). tipo de datos intercambiados son mensajes simples (inicio de sesión, inicio de sesión ACK, luego el cliente pide algo, el servidor responde). cada mensaje tiene alrededor de 300 bytes de longitud.

Actualmente estamos usando Sockets, y todo está bien, sin embargo, estoy buscando una manera más rápida de intercambiar datos (latencia más baja), utilizando métodos IPC.

He estado investigando la red y surgieron referencias a las siguientes tecnologías:

  • memoria compartida
  • tubería
  • colas
  • así como lo que se conoce como DMA (Direct Memory Access)

pero no pude encontrar el análisis adecuado de sus respectivas actuaciones, ni cómo implementarlas en JAVA y C / C ++ (para que puedan hablar entre sí), excepto tal vez tuberías que podría imaginar cómo hacerlo.

¿Alguien puede comentar sobre los desempeños y la viabilidad de cada método en este contexto? cualquier puntero / enlace a información de implementación útil?

EDITAR / ACTUALIZAR

A raíz de los comentarios y las respuestas que recibí aquí, encontré información sobre Unix Domain Sockets, que parecen estar construidos solo sobre pipes, y me ahorraría toda la pila TCP. es específico de la plataforma, por lo que planeo probarlo con JNI o ​​con juds o junixsocket .

los próximos pasos posibles serían la implementación directa de tuberías, luego la memoria compartida, aunque he sido advertido del nivel adicional de complejidad ...

gracias por tu ayuda


Acaba de probar la latencia de Java en mi Corei5 2.8GHz, solo envío / recepción de un solo byte, 2 procesos Java recién generados, sin asignar núcleos de CPU específicos con el conjunto de tareas:

TCP - 25 microseconds Named pipes - 15 microseconds

Ahora especifica explícitamente máscaras de núcleo, como taskset 1 java Srv o taskset 2 java Cli :

TCP, same cores: 30 microseconds TCP, explicit different cores: 22 microseconds Named pipes, same core: 4-5 microseconds !!!! Named pipes, taskset different cores: 7-8 microseconds !!!!

asi que

TCP overhead is visible scheduling overhead (or core caches?) is also the culprit

Al mismo tiempo, Thread.sleep (0) (que como muestra la cadena provoca que se ejecute una sola llamada al kernel de Linux sched_yield ()) toma 0.3 microsegundos, por lo que los tubos con nombre programados para un solo núcleo aún tienen mucha sobrecarga

Algunas mediciones de memoria compartida: 14 de septiembre de 2009 - Solace Systems anunció hoy que su API de plataforma de mensajería unificada puede lograr una latencia promedio de menos de 700 nanosegundos utilizando un transporte de memoria compartida. http://solacesystems.com/news/fastest-ipc-messaging/

PD: intenté la memoria compartida al día siguiente en forma de archivos mapeados en memoria. Si la espera ocupada es aceptable, podemos reducir la latencia a 0.3 microsegundos para pasar un solo byte con un código como este:

MappedByteBuffer mem = new RandomAccessFile("/tmp/mapped.txt", "rw").getChannel() .map(FileChannel.MapMode.READ_WRITE, 0, 1); while(true){ while(mem.get(0)!=5) Thread.sleep(0); // waiting for client request mem.put(0, (byte)10); // sending the reply }

Notas: Thread.sleep (0) es necesario para que 2 procesos puedan ver los cambios de los demás (aún no sé de otra manera). Si 2 procesos se fuerzan al mismo núcleo con el conjunto de tareas, la latencia se convierte en 1,5 microsegundos, eso es un retraso en el cambio de contexto

PPS - ¡y 0.3 microsegundos es un buen número! El siguiente código toma exactamente 0.1 microsegundos, mientras que hace una concatenación de cadena primitiva solamente:

int j=123456789; String ret = "my-record-key-" + j + "-in-db";

PPPS - Espero que esto no sea demasiado fuera de tema, pero finalmente traté de reemplazar Thread.sleep (0) con el incremento de una variable int volátil estática (JVM pasa para vaciar las cachés de la CPU al hacerlo) y obtuve - ¡registro! - 72 nanosegundos de latencia java a la comunicación de proceso java !

Sin embargo, cuando se fuerzan al mismo CPU Core, las JVM de incremento volátil nunca ceden el control entre ellas, produciendo exactamente una latencia de 10 milisegundos. El tiempo de Linux parece ser de 5ms ... Entonces esto debería usarse solo si hay un núcleo adicional. de lo contrario, dormir (0) es más seguro.



DMA es un método mediante el cual los dispositivos de hardware pueden acceder a la memoria RAM física sin interrumpir la CPU. Por ejemplo, un ejemplo común es un controlador de disco duro que puede copiar bytes directamente desde el disco a la RAM. Como tal, no es aplicable a IPC.

La memoria compartida y las tuberías son compatibles directamente con sistemas operativos modernos. Como tal, son bastante rápidos. Las colas son típicamente abstracciones, por ejemplo, implementadas sobre tomas de corriente, tuberías y / o memoria compartida. Esto puede parecer un mecanismo más lento, pero la alternativa es crear una abstracción de este tipo.



Hace algún tiempo se planteó la pregunta, pero podría estar interesado en https://github.com/peter-lawrey/Java-Chronicle que admite latencias típicas de 200 ns y rendimientos de 20 M mensajes / segundo. Utiliza archivos mapeados en memoria compartidos entre procesos (también persiste en los datos, lo que hace que la forma más rápida de conservar los datos)


Informe de errores de Oracle sobre el rendimiento de JNI: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069

JNI es una interfaz lenta, por lo que los sockets TCP de Java son el método más rápido para la notificación entre aplicaciones, sin embargo, eso no significa que deba enviar la carga útil a través de un socket. Use LDMA para transferir la carga útil, pero como lo han señalado las preguntas anteriores , el soporte de Java para la asignación de memoria no es ideal y usted querrá implementar una biblioteca JNI para ejecutar mmap.


No sé mucho acerca de la comunicación nativa entre procesos, pero supongo que necesita comunicarse usando código nativo, al que puede acceder utilizando mecanismos JNI. Entonces, desde Java llamarías a una función nativa que habla con el otro proceso.


Si alguna vez considera utilizar el acceso nativo (ya que su aplicación y el "servidor" están en la misma máquina), considere JNA , tiene menos código repetitivo para que usted pueda manejar.


Una llegada tardía, pero quería señalar un proyecto de código abierto dedicado a medir la latencia del ping con Java NIO.

Más explorado / explicado en esta publicación de blog . Los resultados son (RTT en nanos):

Implementation, Min, 50%, 90%, 99%, 99.9%, 99.99%,Max IPC busy-spin, 89, 127, 168, 3326, 6501, 11555, 25131 UDP busy-spin, 4597, 5224, 5391, 5958, 8466, 10918, 18396 TCP busy-spin, 6244, 6784, 7475, 8697, 11070, 16791, 27265 TCP select-now, 8858, 9617, 9845, 12173, 13845, 19417, 26171 TCP block, 10696, 13103, 13299, 14428, 15629, 20373, 32149 TCP select, 13425, 15426, 15743, 18035, 20719, 24793, 37877

Esto está en la línea de la respuesta aceptada. El error de System.nanotime () (estimado al medir nada) se mide a alrededor de 40 nanos, por lo que para el IPC el resultado real podría ser menor. Disfrutar.