Nucentral

Sommaire:

I.  De l'asynchrone
|- 1. Introduction
|- 2. Le problème
`- 3. La solution

II. NuCentral-to-NuCentral
|- 1. Design
|- 2. Avant propos
|- 3. Protocole
`- 4. Problèmes
   |- a. Déconnexions
   |- b. Sécurité
   `- c. Réseau

I. De l'asynchrone

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 II. NuCentral-to-NuCentral.

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.

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ée 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
  distingues 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.

II. 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 (en local ou à distance).

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.

1. Design

La mise en réseau des différents NuCentral devrait être faite en étoile.

En effet, un NuCentral Master 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:

.-----------.
|  Slave 1  |---------                    .-----------.
+-------+---'        |        ------------|  Slave 2  |
| comp1 |           \|/      \|/          +-------+---'
| comp2 |           .-------------.       | comp3 |
'-------'           |             |       | comp4 |
                    |   Master    |       | comp5 |
                    |             |       '-------'
                    '-----+-------+
                     /|\  | comp7 |
                      |   | comp8 |
                      |   '-------'
                      |
              .-----------.
              |  Slave 3  |
              +-------+---'
              | comp6 |
              '-------'

2. Avant-propos

La détermination du status de Master ou Slave 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'anoncer.

L'esclave ne pourra pas accepter de requettes d'anonce.

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 Master pourrait se connecter à un autre NuCentral, comme esclave cette fois, afin d'anoncer 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 Master alors qu'il voulait accéder au Slave 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 anoncer dans l'appel de fonction le mot de passe.

On passe uniquement la liste des composants et pas des services.

3. Protocole

Le déroulement d'une anonce se fait dans les grandes lignes ainsi

-> Connexion de Slave2 à Master1 par SOAP, appel une fonction
   en passant le mot de passe et la liste des composants
<- Réponse de Master1 avec la liste de ses composants et de
   ceux des autres esclaves.
<- Master1 envoie la liste des composants de Slave2 à tous
   les autres esclaves.

Par la suite, Slave2 peut réenvoyer sa liste afin de la mettre à jour, ce qui informera tous les autres esclaves. Du coup Slave2 pourra lui même être prévenu des mises à jour.

Chaque Slave 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.

4. Problèmes

a. 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 Master 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 parraît d'une laideur sans nom.

Une seconde solution serait que lorsqu'un NuCentral tente de se connecter à un NuCentral qui est censé être up, si il échoue, il prévient le master de ceci qui met à jour la liste.

b. 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 passera en crypté par SSL.

Ensuite, l'authentification du master est plus importante. Lorsque celui-ci fait son anonce aux esclaves, il devrait anoncer également un mot de passe ou une connerie de ce genre.

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.

c. Réseau

Dans le présent brouillon, je décris un cas d'utiliser ou tous les nucentral sont sur le même réseau.

En effet, considérons la topologie réseau suivante:

.--------.    |
| Slave1 |    |       .--------.
'--------'    |       | Slave2 |
     \        |       '--------'
      \       |      /
       \      |     /
        .----------.
        |  Master  |
        '----------'
              |
              |

On a un Slave2 qui n'a pas d'accès direct à Slave1 par le réseau.

Le Slave2 ne pourra ainsi pas se connecter au Slave1 si il veut faire une requette que celui-ci possède.

Ceci est un cas relativement tordu, mais à considérer peut être je pense.