root/mirror/edenwall/nulog2/branches/2.0/doc/nucentral.rst
| Revision 8102, 12.4 kB (checked in by haypo, 3 years ago) | |
|---|---|
|
|
Nucentral
Sommaire
1 De l'asynchrone
1.1 Introduction
NuCentral a un fonctionnement décrit par le schema suivant:
+-------+ +-------+
| comp3 | +-------+ | comp5 | +-------+
+-------+ | comp4 | +-------+ | comp6 |
| serv1 | +-------+ | serv1 | +-------+
| serv2 | | serv1 | | serv2 | | serv1 |
| serv3 | '-------' '-------' | serv2 |
'-------' \ / | serv3 |
\ \ / '-------'
\ \ / /
\_________+--------------+ /
| NuCentral1 |____/
.---------. +-------+------+ .--------.
| browser |=====| Nevow | SOAP |======| client |
'---------' '-------'------' '--------'
||
||
||
||
.--------. .-------.------.
| client |=====|XML-RPC| SOAP |
'--------' +-------+------+
| NuCentral2 |
+--------------+
/ \
/ \
+-------+ +-------+
| comp1 | | comp2 |
+-------+ +-------+
| serv1 | | serv1 |
| serv2 | '-------'
| serv3 |
'-------'
Légende:
_ : Liaison modulaire
= : Liaison HTTP (SOAP/XML-RPC/etc)
Vocabulaire:
- NuCentral: Application modulaire ayant pour but de mettre en relation les différents composants qui sont attachées à elle.
- Composant: Module de NuCentral qui peut proposer des services ou en appeler. Il peut également proposer des sites.
- Service: Méthode appartenant à un composant, pouvant être appellé par un autre composant.
- Site: Basé du Nevow, un composant peut demander à NuCentral de rendre disponible une ressource web.
- Client: Application indépendante qui appele par SOAP ou XML-RPC des services.
Techniquement, un appel se déroule comme suit :
Supposons un composant compA attaché à NuCentral2 et cherchant à appeler compB.serv1.
En premier lieu, le composant fait un appel à callService(), fonction de NuCentral2, avec le nom du composant compB, du service serv1, et les arguments passés.
NuCentral2 vérifie si le composant est un module local... Si c'est le cas :
- NuCentral2 localise que le composant est attaché à NuCentral1, fait un appel par SOAP à celui-ci.
- NuCentral1 appelle la fonction compB.serv1 et retourne le résultat.
- Si le résultat est un Deferred, c'est à dire que si une execution _asynchrone_ est requise, la lib SOAPpy va se charger d'y attacher le callback qui renverra le résultat directement.
- NuCentral2 reçoit le résultat et le renvoie à compA qui aura été bloqué pendant le temps de la demande.
Si jamais compB est attaché à NuCentral2 :
- NuCentral2 appele la fonction directement compB.serv1, puis retourne tout de suite le résultat.
- Si ce dernier est Deferred, il ne sera pas executé, et compA se retrouvera avec un objet de ce type...
Note: le fonctionnement du dialogue entre les serveurs NuCentral, notament pour la synchronisation des données, sera décrit dans le chapitre NuCentral-to-NuCentral.
1.2 Le problème
Ainsi que vu dans le paragraphe précédent, si jamais la fonction possède un mode de fonctionnement asynchrone, c'est à dire si elle retourne un objet de type Deferred, le comportement du côté du composant appelant sera différent que ça soit en local ou à distance.
Lorsque l'appel se fait directement, la procédure qui appelle la fonction et qui attends un résultat bloque directement, et ne peut attendre l'exécution du Deferred, puisque pour cela il serait nécessaire de rendre la main à Twisted !
Le problème que l'on rencontre ici est qu'on cherche à avoir un fonctionnement de type synchrone avec une application basée sur Twisted qui a un fonctionnement asynchrone.
1.3 La solution
La solution serait de rendre asynchrone le fonctionnement de NuCentral.
Cependant, comme toute fonction n'a pas un modèle asynchrone, il serait intéressant de garder les deux modes de fonctionnement.
Une solution à envisager serait la suivante :
Un service est taggable. C'est à dire que l'on pourrait déterminer, lors de la déclaration de ces fonctions, si celle-ci a un mode de fonctionnement synchrone ou non.
Un service taggé synchrone fonctionnnerait ainsi :
- Elle renverra obligatoirement le résultat tout de suite.
Un service taggé asynchrone aurait le comportement suivant :
- Si elle retourne un objet de type Deferred, il sera transmis tel quel à la procédure appelante.
- Si elle retourne le résultat directement, NuCentral assure la création d'un Deferred.
- La procédure appelante sera donc forcée de traiter le Deferred elle même, et donc soit de le passer à une couche plus basse telle que Nevow, soit d'ajouter un callback pour récupérer le résultat une fois l'execution déroulée.
On est ainsi assuré que le comportement d'un appel à un service sera le même pour le composant, que ce service soit local ou distant.
Le déroulement d'un appel à une fonction asynchrone serait le suivant :
Un composant compA attaché à NuCentral2 veut appeller compB.serv1, qui est une fonction taggée asynchrone.
La précedure de compA fait son appel à la fonction callService() de NuCentral2.
NuCentral2 détermine la localisation du composant. Deux cas se distinguent alors. Si compB est local:
- NuCentral2 fait appel à la fonction du service directement.
- Si le résultat renvoyé est un Deferred, il le transmet directement tel quel à l'appelant.
- Si le résultat n'est pas un Deferred, NuCentral2 en crée un et met le résultat dedans.
- La procédure appelante ajoute un callback au Deferred afin de récupérer le résultat.
Si compB est distant:
- NuCentral2 fait un appel SOAP à NuCentral1.
- NuCentral1 appelle le service.
- Si le résultat renvoyé est un Deferred, il va attendre que l'exécution se fasse, puis renvoie à NuCentral2 le résultat.
- Si le résultat n'est pas un Deferred, il va renvoyer le résultat directement. En effet, l'appel étant distant, il n'y a pas d'intérêt d'executer un Deferred car le résultat à renvoyer par SOAP se doit d'être le retour.
- NuCentral2 reçoit le résultat. Cependant, pour assurer une transparence de fonctionnement à compA, il crée un Deferred et met le résultat dedans.
- Ainsi compA n'a plus qu'à ajouter un callback afin de récupérer le résultat.
2 NuCentral-to-NuCentral
L'intérêt principal de NuCentral réside dans la transparence qu'il apporte pour l'appel de fonctions d'un composant à un autre, quelque soit la localisation physique de celui-ci (local ou distant).
La réalisation de ceci passe par une mise en relation de différents NuCentral, afin que lorsqu'un composant présent sur un NuCentral souhaite appeler un service, NuCentral sache où il se trouve et y fasse la requête.
2.1 Design
La mise en réseau des différents NuCentral devrait être faite en étoile.
En effet, un NuCentral maître serait désigné, et les NuCentral esclaves s'y connecteraient au lancement et à chaque mise à jour de leur liste de composants.
Voici à quoi devrait ressembler le schema :
.-------------.
| Esclave 1 |------- .-------------.
+-------+-----' | ------------| Esclave 2 |
| comp1 | \|/ \|/ +-------+-----'
| comp2 | .-------------. | comp3 |
'-------' | | | comp4 |
| Maître | | comp5 |
| | '-------'
'-----+-------+
/|\ | comp7 |
| | comp8 |
| '-------'
|
.-------------.
| Esclave 3 |
+-------+-----'
| comp6 |
'-------'
2.2 Avant-propos
La détermination du status de Maître ou Esclave se fait par le simple fait qu'un serveur possède ou non dans sa configuration un serveur SOAP auquel se connecter afin de s'annoncer.
L'esclave ne pourra pas accepter de requête d'annonce.
En revanche, on peut supposer qu'un réseau de NuCentral pourra être lui même déporté à un autre. C'est à dire qu'un NuCentral Maître pourrait se connecter à un autre NuCentral, comme esclave cette fois, afin d'annoncer tous les composants qu'il possède. Le problème dans ce schema là est qu'un autre NuCentral Client serait susceptible de se connecter à ce Maître alors qu'il voulait accéder à l'Esclave 3.
En bref ce cas est peut être compliqué à gérer alors qu'il peut paraitre inutile.
Le serveur défini dans sa configuration son mot de passe, et les clients doivent annoncer le mot de passe dans l'appel de fonction.
On passe uniquement la liste des composants et pas des services.
2.3 Protocole
Le déroulement d'une annonce se fait de cette manière :
-> Connexion de l'Esclave2 au Maître1 par SOAP, appel une fonction en passant le mot de passe et la liste des composants. <- Réponse du Maître1 avec la liste de ses composants et de ceux des autres esclaves. <- Maître1 envoie la liste des composants d'Esclave2 à tous les autres esclaves.
Par la suite, Esclave2 peut réenvoyer sa liste afin de la mettre à jour, ce qui informera tous les autres esclaves. Du coup Esclave2 pourra lui même être prévenu des mises à jour.
Chaque Esclave a maintenant la liste complète des composants disponibles et leur localisation. Il sera ainsi aisé à celui-ci de se connecter directement au NuCentral concerne.
2.4 Problèmes
2.4.1 Déconnexions
Le gros problème réside dans les déconnexions qui peuvent survenir sans préavis.
En effet, bien qu'à la fermeture propre de NuCentral, celui-ci devrait avoir l'amabilité d'informer le Maître de son indisponibilité, il est probablement possible qu'il disparaisse subitement en cas de crash, de coupure de courant, de réseau, etc.
Une solution peut se situer dans un système de ping par SOAP, mais cela me paraît être une solution peu élégante.
Une seconde solution serait que lorsqu'un NuCentral tente de se connecter à un NuCentral censé être disponible et qu'il échoue, il prévient le maître qui met à jour la liste.
2.4.2 Sécurité
Quelques questions de sécurité se posent. Tout d'abord du point de vue de l'authentification des esclaves. Le choix d'utiliser un mot de passe est plus correct, surtout que celui-ci sera transmis dans un tunnel chiffré (SSL).
Ensuite, l'authentification du maître est plus importante. Lorsque celui-ci fait son annonce aux esclaves, il devrait annoncer également un mot de passe ou autre.
Enfin, les composants doivent être empêchés d'appeler une fonction de synchronisation entre les NuCentral.
Il devrait être trivial de régler ces problèmes, mais la discussion s'impose afin de prendre dans chaque cas la meilleurs solution.
2.4.3 Réseau
Dans le présent brouillon, je décris un cas d'utilisation où tous les Nucentral sont sur le même réseau.
En effet, considérons la topologie réseau suivante:
.----------. |
| Esclave1 | | .----------.
'----------' | | Esclave2 |
\ | '----------'
\ | /
\ | /
.----------.
| Maître |
'----------'
|
|
On a un Esclave2 qui n'a pas d'accès direct à Esclave1 par le réseau.
L'Esclave2 ne pourra ainsi pas se connecter au Esclave1 si il veut faire une requête que celui-ci possède.
Ceci est un cas relativement tordu, mais qu'il faut peut être considérer.
