J'ai une application Java, connectée via une socket TCP à un "serveur" développé en C / C ++.
l'application et le serveur fonctionnent sur la même machine, une boîte Solaris (mais nous envisageons de migrer vers Linux à terme). le type de données échangées est de simples messages (login, login ACK, puis le client demande quelque chose, le serveur répond). chaque message mesure environ 300 octets.
Actuellement, nous utilisons Sockets, et tout va bien, mais je recherche 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:
- la memoire partagée
- tuyaux
- files d'attente
- ainsi que ce qu'on appelle DMA (Direct Memory Access)
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 tuyaux que je pourrais imaginer comment faire.
Quelqu'un peut-il commenter les performances et la faisabilité de chaque méthode dans ce contexte? un pointeur / lien vers des informations utiles sur la mise en œuvre?
MODIFIER / METTRE À JOUR
suite au commentaire et aux réponses que j'ai obtenus ici, j'ai trouvé des informations sur les sockets de domaine Unix, qui semblent être construites juste au-dessus des tuyaux, et me sauveraient toute la pile TCP. c'est spécifique à la plate-forme, donc je prévois de le tester avec JNI ou juds ou junixsocket .
Les prochaines étapes possibles seraient l'implémentation directe des tuyaux, puis la mémoire partagée, même si j'ai été averti du niveau supplémentaire de complexité ...
Merci de votre aide
Réponses:
Je viens de tester la latence de Java sur mon Corei5 2,8 GHz, un seul octet envoyé / reçu, 2 processus Java juste générés, sans attribuer des cœurs de processeur spécifiques avec le jeu de tâches:
Spécifiant maintenant explicitement les masques de base, comme le jeu de tâches 1 java Srv ou le jeu de tâches 2 java Cli :
alors
Dans le même temps, Thread.sleep (0) (qui, comme le montre strace, entraîne l'exécution d'un seul appel de noyau Linux sched_yield ()) prend 0,3 microseconde - les tubes nommés planifiés sur un seul cœur ont donc encore beaucoup de surcharge
Quelques mesures de mémoire partagée: 14 septembre 2009 - Solace Systems a annoncé aujourd'hui que son API de plate-forme de messagerie unifiée peut atteindre une latence moyenne de moins de 700 nanosecondes en utilisant un transport de mémoire partagée. http://solacesystems.com/news/fastest-ipc-messaging/
PS - a essayé la mémoire partagée le lendemain sous la forme de fichiers mappés en mémoire, si une 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:
Notes: Thread.sleep (0) est nécessaire pour que 2 processus puissent voir les changements de l'autre (je ne connais pas encore d'autre moyen). Si 2 processus forcés au même cœur avec un ensemble de tâches, la latence devient 1,5 microsecondes - c'est un délai de changement de contexte
PPS - et 0,3 microseconde est un bon nombre! Le code suivant prend exactement 0,1 microseconde, tout en effectuant une concaténation de chaîne primitive uniquement:
PPPS - j'espère que ce n'est pas trop hors sujet, mais finalement j'ai essayé de remplacer Thread.sleep (0) par l'incrémentation d'une variable int statique volatile (JVM arrive à vider les caches CPU en le faisant) et obtenu - enregistrez! - Communication de processus java à java de latence de 72 nanosecondes !
Cependant, lorsqu'elles sont forcées au même cœur de processeur, les JVM à incrémentation volatile ne se cèdent jamais le contrôle, produisant ainsi une latence exacte de 10 millisecondes - le quantum de temps Linux semble être de 5 ms ... Donc, cela ne devrait être utilisé que s'il y a un noyau de rechange - sinon, sleep (0) est plus sûr.
la source
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 vers la RAM. En tant que tel, il ne s'applique pas à IPC.
La mémoire partagée et les canaux sont tous deux pris en charge directement par les systèmes d'exploitation modernes. En tant que tels, ils sont assez rapides. Les files d'attente sont généralement des abstractions, par exemple implémentées sur des sockets, des tubes et / ou de la mémoire partagée. Cela peut ressembler à un mécanisme plus lent, mais l'alternative est que vous créez une telle abstraction.
la source
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 prend en charge des latences typiques de 200 ns et des débits de 20 M messages / seconde. Il utilise des fichiers mappés en mémoire partagés entre les processus (il persiste également les données, ce qui en fait le moyen le plus rapide de conserver les données)
la source
Voici un projet contenant des tests de performances pour divers transports IPC:
http://github.com/rigtorp/ipc-bench
la source
Si jamais vous envisagez d'utiliser l'accès natif (puisque votre application et le "serveur" sont sur la même machine), pensez à JNA , il a moins de code standard à gérer.
la source
Une arrivée tardive, mais souhaitait signaler un projet open source dédié à la mesure de la latence ping à l'aide de Java NIO.
Plus exploré / expliqué dans ce billet de blog . Les résultats sont (RTT en nanos):
Cela va dans le sens de la réponse acceptée. L'erreur System.nanotime () (estimée en ne mesurant rien) est mesurée à environ 40 nanos, donc pour l'IPC, le résultat réel peut être inférieur. Prendre plaisir.
la source
Je ne connais pas grand-chose à la communication inter-processus native, mais je suppose que vous devez communiquer en utilisant du code natif, auquel vous pouvez accéder à l'aide de mécanismes JNI. Ainsi, à partir de Java, vous appelleriez une fonction native qui communique avec l'autre processus.
la source
Dans mon ancienne entreprise, nous travaillions avec ce projet, http://remotetea.sourceforge.net/ , très facile à comprendre et à intégrer.
la source
Avez-vous envisagé de garder les prises ouvertes pour que les connexions puissent être réutilisées?
la source
Rapport de bogue Oracle sur les performances JNI: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069
JNI est une interface lente et les sockets Java TCP sont donc la méthode la plus rapide pour la notification entre les applications, mais cela ne signifie pas que vous devez envoyer la charge utile via une socket. Utilisez LDMA pour transférer la charge utile, mais comme les questions précédentes l' ont souligné, la prise en charge de Java pour le mappage mémoire n'est pas idéale et vous voudrez donc implémenter une bibliothèque JNI pour exécuter mmap.
la source