2010-10-17 17 views
1

Salutations, Je n'ai pas pu fournir tous les détails dans la question, alors voici les détails clés.Comment puis-je éviter les goulots d'étranglement lors de l'utilisation de jni dans une application/un service Web Java?

J'ai une DLL native (et un .so correspondant) enveloppant une bibliothèque statique, qui est créée par le langage de programmation d'Eiffel. J'ai écrit un wrapper C++ autour de la lib statique, et je l'ai exposé avec succès à Java. Cependant, si j'utilise cette DLL dans une application web, les choses vont devenir compliquées. Le problème est que plusieurs threads java accèdent au même code C++, où le contexte natif (?) Est maintenu entre les appels par différentes classes & instances. Pour utiliser la fonctionnalité du code Eiffel, il faut initialiser le moteur d'exécution Eiffel depuis C++, puis utiliser les bibliothèques Eiffel pour utiliser les classes Eiffel de C++. Malheureusement, cela signifie que toutes les demandes entrantes vers le serveur Java se retrouvent dans un seul emplacement en C++ (dans la DLL native), où il n'y a qu'une seule exécution d'Eiffel. Cette situation m'oblige à sécuriser l'intégralité du thread d'exécution Eiffel et une seule opération effectuée par un thread Java peut utiliser le code Eiffel en passant par JNI. J'ai le sentiment que cela peut rapidement devenir un problème d'évolutivité. Je pense que je peux avoir besoin d'un pool de processus, chacun chargeant une copie de la même DLL (ou .so sous * nix) qui sera servi aux threads entrants de Java. Ainsi, une fois la bibliothèque partagée chargée, le code C++ créera, disons 10 processus, et les threads entrants du côté Java seront alloués à ces processus via le code C++. Le flux d'événements est le suivant:

Le thread Java accède au code natif (C++) dans la bibliothèque partagée. vérifie le code natif dont les processus sont disponibles à partir du pool de processus fait usage de l'un des processus via ipc, marquant occupé (probablement à l'aide d'un fil?)

C'est le seul moyen de la plate-forme cross que je pouvais penser à charger en toute sécurité le même morceau de code (classes Eiffel Runtime et eiffel) sans aucun problème de sécurité.

Tout ceci est dû au fait que l'exécution d'Eiffel est un composant coûteux et global, que je dois exposer via JNI.

Ou devrais-je simplement aller avec les opérations thread safe, où un seul thread est servi à partir de JNI à tout moment? Y a-t-il un truc que je peux faire avec Java pour créer des conteneurs jvm isolés et légers utilisant chacun un seul moteur d'exécution Eiffel?

Vos commentaires seraient les bienvenus.

Cordialement Seref

Répondre

1

Première question: si vous aviez plusieurs copies de la DLL chargées dans des processus distincts seraient-ils fonctionner correctement? En supposant «oui», votre idée d'avoir plusieurs copies en cours d'exécution semble avoir un potentiel. (En fait, il y a une autre question à poser d'abord: je suppose que la ré-implémentation de l'Eiffel en Java a déjà été examinée et prouvée trop difficile?)

Mon inclination serait d'abord de vérifier si votre simple, Une approche unique, sans risque pour les threads, peut donner des performances suffisantes. Si ce n'est pas le cas et que vous avez besoin d'évolutivité, alors une autre possibilité est d'envisager d'utiliser plusieurs meachine (ou machines virtuelles) bon marché - cela a le grand mérite de la simplicité. Il ne faut pas beaucoup d'effort de développement pour coûter plus que quelques machines. Sinon, votre idée d'un pool de processus de «service» semble être une idée raisonnable.Il existe de nombreuses possibilités de communication inter-processus (IPC). Presque par définition, vous passez beaucoup de temps dans le service pour chaque appel (sinon vous auriez un problème?), Auquel cas le mécanisme IPC réel n'a pas besoin d'être hautement optimisé - privilégiez la simplicité et la facilité d'administration. Je regarderais d'abord une approche basée sur la file d'attente en utilisant JMS - oui il y a beaucoup d'autres options, y compris RMI ou sockets de bas niveau - mais JMS a deux avantages: c'est très facile et l'évolutivité tombe, le demandeur une file d'attente, n'a jamais besoin de savoir combien de processus de service il peut y avoir. Il est également intéressant de noter que sur certaines plates-formes de fournisseurs, il existe des implémentations C++ de JMS (XMS est celle que j'utilise) et par conséquent, vous n'avez même pas utilisé Java dans le processus de service.

Elaborer: la position de départ est

WS-Client ---WS Call ---> WS in Web App ---JNI--->C++/Eiffel 

Je suggère d'utiliser

WS-Client ---WS Call ---> WS in Web App --JMS enq--> Q --JMS deq--> Java---JNI--->C++/Eiffel 

ou

WS-Client ---WS Call ---> WS in Web App --JMS enq--> Q --XMS deq--->C++/Eiffel 

Les réponses peuvent être retournés sur les files d'attente de réponse temparary avec le message de demande contient une Répondre au nom Q et aux informations de corrélation.

En fait, ce dernier modèle est à peu près ce que fait mon application actuelle, avec de bonnes performances. Je pense que l'absence de Java dans le moteur C++/Eiffel pourrait être une victoire. Si cette utilisation pseudo-synchrone de JMS semble peu attrayante, alors mon alternative serait d'utiliser des EJB avec des interfaces distantes. L'idée encore une fois est de pousser tout le travail d'évolutivité dans l'infrastructure.

+0

La base du code Eiffel est énorme, aucune chance de la réécrire pour le moment. Je cherchais un moyen de créer plusieurs jvms de sandboxing, ou des instances de serveur d'applications qui utilisent toutes la DLL sécurisée d'un thread unique en arrière-plan. Je ne vois pas comment je peux utiliser JMS avec une demande de service Web entrant, qui doit se connecter à un backend jni, pourriez-vous expliquer cela un peu plus? Merci pour la réponse de toute façon. – mahonya

+0

J'ai élargi un peu. Nous utilisons ce modèle avec un certain succès. – djna

+0

Cela semble prometteur, merci pour la mise à jour. Je ne suis pas sûr que je puisse obtenir le mécanisme pour retourner la réponse si. Je ferais probablement attendre l'appel de service Web jusqu'à ce qu'il reçoive une réponse à sa demande de la file d'attente jms. C'est probablement un meilleur moyen d'assurer la sécurité des threads sans entrer dans les détails des mécanismes de sécurité des threads C++ ou JNI. – mahonya