méthode la plus rapide (faible latence) pour la Communication entre Java et C / c++
j'ai une application Java, qui se connecte via une socket TCP à un" serveur " développé en C/C++.
les deux app & server tournent sur la même machine, une Solaris (mais nous envisageons éventuellement de migrer vers Linux). le type de données échangées est des messages simples (login, Login ACK, puis le client demande quelque chose, réponses du serveur). chaque message est d'environ 300 octets.
Actuellement nous utilisons des Sockets, et tout va bien, cependant je suis à la recherche d'un moyen plus rapide d'échanger des données (latence plus faible), en utilisant les méthodes IPC.
j'ai fait des recherches sur le net et j'ai trouvé des références aux technologies suivantes:
- mémoire partagée
- tuyaux
- files d'attente
- ainsi que ce qu'on appelle DMA (accès direct à la mémoire)
mais je n'ai pas pu trouver une analyse correcte de leurs performances respectives, ni comment les implémenter en JAVA et C / C++ (pour qu'ils puissent se parler), sauf peut-être des pipes que je pourrais imaginer comment faire.
quelqu'un peut-commentaires sur les performances et la faisabilité de chaque méthode dans ce contexte ? un lien vers des informations utiles sur la mise en œuvre ?
MODIFIER / METTRE À JOUR
suite aux commentaires et réponses que j'ai eu ici, j'ai trouvé des informations sur les Sockets de domaine Unix, qui semblent être construits juste au-dessus des tuyaux, et me sauverait toute la pile TCP. il est spécifique à la plateforme, donc je prévois de le tester avec JNI ou soit juds ou junixsocket .
les prochaines étapes possibles seraient la mise en œuvre directe de pipes, puis la mémoire partagée, bien que j'ai été averti du niveau supplémentaire de complexité...
merci pour votre aide
10 réponses
vient de tester la latence de Java sur mon Corei5 2,8 GHz, seul byte envoyer / reçu, 2 processus Java viennent d'apparaître, sans affecter de cœurs CPU spécifiques avec taskset:
TCP - 25 microseconds
Named pipes - 15 microseconds
spécifiant désormais explicitement les masques core, comme taskset 1 java Srv ou 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 !!!!
donc
TCP overhead is visible
scheduling overhead (or core caches?) is also the culprit
en même temps fil.sleep(0) (qui, comme strace montre causes d'un seul sched_yield() du noyau Linux appel à être exécuté) prend 0.3 microseconde - ainsi nommé tuyaux prévue à simple cœur ont encore beaucoup de frais généraux
quelques mesures de mémoire partagée: 14 septembre 2009 – Solace Systems a annoncé aujourd'hui que son API de plateforme de messagerie unifiée peut atteindre une latence moyenne de moins de 700 nanosecondes en utilisant un transport de mémoire partagé. http://solacesystems.com/news/fastest-ipc-messaging /
P.S.-j'ai essayé la mémoire partagée le lendemain sous forme de fichiers de mappage de mémoire, si l'attente occupée est acceptable, nous pouvons réduire la latence à 0,3 microseconde pour passer un seul octet avec un code comme celui-ci:
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
}
Notes: Thread.sleep (0) est nécessaire pour que 2 Processus puissent voir les changements de l'autre (Je ne connais pas d'autre moyen pour le moment). Si 2 processus sont forcés au même noyau avec taskset, le la latence devient 1.5 microsecondes - c'est un délai de commutation de contexte
P. P. S et 0,3 microseconde est un bon nombre! Le code suivant prend exactement 0.1 microseconde, tout en faisant une concaténation de chaîne primitive seulement:
int j=123456789;
String ret = "my-record-key-" + j + "-in-db";
P. P. P. S - espérons que ce n'est pas trop hors-sujet, mais finalement, j'ai essayé de remplacer le Fil de discussion.sleep(0) avec incrementing une variable int statique volatile (JVM arrive à rincer les caches CPU en faisant ainsi) et obtained - record! - 72 nanosecondes latence java-java processus de communication !
quand ils sont forcés au même noyau CPU, cependant, les JVM à incrémentation volatile ne se donnent jamais le contrôle l'un de l'autre, produisant ainsi exactement 10 millisecondes de latence-le quantum de temps Linux semble être de 5ms... Ceci ne doit donc être utilisé que s'il y a un noyau de rechange - sinon sleep(0) est plus sûr.
la question a été posée il y a quelque temps, mais vous pourriez être intéressé par https://github.com/peter-lawrey/Java-Chronicle qui supporte des latences typiques de 200 ns et des débits de messages de 20 m/seconde. Il utilise des fichiers cartographiés en mémoire partagés entre les processus (il persiste également les données qui le rend le moyen le plus rapide de persister des données)
DMA est une méthode par laquelle les périphériques matériels peuvent accéder à la RAM physique sans interrompre le CPU. Par exemple: un exemple courant est un contrôleur de disque dur qui peut copier des octets directement du disque à la mémoire vive. En tant que tel, il n'est pas applicable à IPC.
mémoire partagée et pipes sont tous les deux pris en charge directement par OSes modernes. En tant que tels, ils sont assez rapide. Les files d'attente sont typiquement des abstractions, par exemple implémentées sur des sockets, des pipes et/ou de la mémoire partagée. Cela peut ressembler à un plus lent mécanisme, mais l'alternative est que vous créer une telle abstraction.
voici un projet contenant des tests de performance pour divers transports IPC:
une arrivée tardive, mais a voulu signaler un open source project dédié à la mesure de la latence ping en utilisant Java NIO.
exploré/expliqué plus en détail dans ce post de blog . Les résultats sont (RTT in 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
dans le sens de la réponse acceptée. Système.l'erreur nanotime () (estimée en ne mesurant rien) est mesurée à environ 40 nanos donc pour la CIB le résultat réel peut être inférieure. Profiter.
Je ne sais pas grand-chose sur la communication native entre les processus, mais je suppose que vous devez communiquer en utilisant le code natif, auquel vous pouvez accéder en utilisant les mécanismes JNI. Donc, à partir de Java, vous appelleriez une fonction native qui parle à l'autre processus.
dans mon ancienne société, nous avons travaillé avec ce projet, http://remotetea.sourceforge.net / , très facile à comprendre et à intégrer.
avez-vous envisagé de garder les sockets ouverts, pour que les connexions puissent être réutilisées?
Oracle bug report on JNI performance: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069
JNI est une interface lente et donc les sockets TCP Java sont la méthode la plus rapide pour la notification entre les applications, mais cela ne signifie pas que vous devez envoyer la charge utile sur une socket. Utilisez LDMA pour transférer la charge utile, mais comme questions précédentes ont souligné, Java support for memory mapping n'est pas idéal et vous voudrez donc mettre en œuvre une bibliothèque JNI pour exécuter mmap.