UP | HOME

Modèle conceptuel - Application aux services

Table of Contents

1 Services

9 principes (inspirés de l'ouvrage "SOA: Principles of Service Design", disponible sur Campus, pour les détails (chap. 6 à 13))

1.1 Echange de messages

  • Agents produisant et consommant des messages, possédant un état
  • Communication entre agents des messages via des canaux

1.2 Contrats

  • Interface contractuelle entre serveurs et clients

1.3 Couplage faible

  • Boîte noire

1.4 Abstraction

Interface abstrayant différentes caractéristiques de la boîte noire :

  • implémentation (technologie, programmation)
  • qualité de service.

1.5 Réutilisabilité

  • 1 service, * clients
  • Conséquence : concurrence et répartition

1.6 Isolation

  • Isolation de la boîte noire
  • Un seul accès : l'interface

1.7 Absence d'état de session

Degré de cette propriété à examiner relativement

  • au nombre de requêtes actives (pendantes),
  • au nombre de sessions actives.

Définition : une session est une unité d'interactions entre deux ou plusieurs agents (typiquement, deux agents, un client et un serveur).

Exemple : la réservation d'un billet de train

Définition : un serveur est dit sans état (stateless) si la taille de son état ne varie pas en fonction du nombre de sessions actives. Elle peut en revanche varier (linéairement) en fonction du nombre de requêtes actives.

Remarque : on devrait donc dire "sans état de session".

Concrètement, le serveur ne gère pas les sessions. Ce sont les clients qui doivent les gérer en communiquant systématiquement l'état de la session au serveur, qui à son tour renvoie au client le nouvel état de celle-ci.

On pourrait donc dire qu'un serveur est dit sans état (stateless) lorsque l'état d'une session est gérée de manière décentralisée, et avec état (stateful) lorsqu'elle est gérée de manière centralisée.

Analogie avec les fonctions : un serveur stateless correspond à une fonction calculant (entre autres choses) un nouvel état à partir d'un état reçu en argument, alors qu'un serveur stateful correspond à une fonction impure, possédant un état modifiable.

1.7.1 Exercice : automate

On cherche à décrire un service proposant la reconnaissance de langages réguliers fermés par préfixe : ce sont les langages reconnus par des automates dont tous les états sont finals. Précisément, on s'intéressera au langage (ab)*+ (ab)*a formé d'une succession, éventuellement vide, de mots ab, suivi possiblement d'un a. Par exemple, ab, aba et abab sont trois mots reconnus alors que le mot abaa n'est pas reconnu. Pour reconnaître ce langage, on utilise un automate à deux états, UN et DEUX.

../medias/soc_automata_ab-star.svg

Automate reconnaissant le langage ((ab) + (ab) a)

1.7.1.1 Implémentation du serveur avec état (Stateful)

Le serveur est implémenté suivant les règles chimiques suivantes. Il propose trois canaux de communication, initier pour commencer, accepter pour réaliser une transition de l'automate et clore pour terminer l'exécution en cas de succès. Son état est formé des atomes Session(n) indiquant que la prochaine session aura le numéro n et Execution(n, etat) indiquant que l'exécution de la session n est dans l'état etat.

initier(ar) & Session(n) -> ar(n, OK) & Session(n + 1) & Execution(n, UN)

Si le message initier(ar) est reçu alors que le numéro de session est n, alors la session n commence dans l'état UN et le client reçoit sur le canal ar qu'il a transmis un accusé de réception indiquant le numéro de session.

accepter('a', n, ar) & Execution(n, UN) -> ar(n, OK) & Execution(n, DEUX)

Si le message accepter('a', n, ar) est reçu alors que l'exécution de la session n est dans l'état UN, alors l'état devient deux et le client reçoit sur le canal ar qu'il a transmis un accusé de réception indiquant le numéro de session.

accepter('b', n, ar) & Execution(n, DEUX) -> ar(n, OK) & Execution(n, UN)

Règle chimique analogue à celle précédente pour la seconde transition.

accepter(x, n, ar) & Execution(n, e) -> ar(n, KO) ((x, e) != ('a', UN) et != ('b', DEUX))

Pour toutes les autres cas, le client reçoit un message d'erreur sur le canal transmis ar et l'exécution est close.

clore(n) & Execution(n, e) ->

Si le message clore(n) est reçue, alors la session n est close : il n'y a plus d'atome Execution(n, e).

1.7.1.2 Implémentation du client du serveur avec état (Stateful)

Le client possède un état formé du mot en cours de reconnaissance et d'un statut de contrôle, soit Debut, EnCours, Succes et Echec. Il utilise le canal rep pour recevoir les accusés de réception.

Debut & Mot('a'::'b'::'a'::'b')

Le client a pour état initial un mot, par exemple abab, et le statut de contrôle Debut. :: est l'opérateur de concaténation.

Debut -> initier(rep) & EnCours

Le client commence par initier l'exécution. Il transmet le canal rep et passe dans l'état EnCours.

EnCours & rep(n, OK) & Mot(l::mot) -> accepter(l, n, rep) & Mot(mot) & EnCours

Lorsque le client reçoit un accusé de réception OK et que le mot restant à reconnaître (l::mot) n'est pas vide, le client envoie au serveur la première lettre l du mot, et passe au reste du mot (mot).

EnCours & rep(n, OK) & Mot(VIDE) -> clore(n) & Succes

Lorsque le client reçoit un accusé de réception OK et que le mot restant à reconnaître est vide (valeur VIDE), le client envoie au serveur le message de clôture de l'exécution et termine avec succès la reconnaissance du mot.

EnCours & rep(n, KO) & Mot(m) -> Echec

Lorsque le client reçoit un accusé de réception KO, le client termine par un échec la reconnaissance du mot.

1.7.1.3 Implémentation du serveur sans état (Steteless)

Le serveur précédent a pour inconvénient de maintenir l'état de chacune des exécutions en cours. Le passage à l'échelle pose problème. De plus, en cas de panne, les exécutions ne peuvent pas être reprises. On préfère donc déporter la gestion des états du serveur aux clients. Le serveur sans état propose deux canaux de communication, initier pour commencer, accepter pour réaliser une transition de l'automate. Son état est formé de l'atome Session(n) indiquant que la prochaine session aura le numéro n.

Modifier les règles chimiques précédentes de manière à transmettre l'état de l'automate dans chaque communication.

initier(ar) & Session(n) -> ar(n, UN) & Session(n + 1) 
accepter('a', n, UN, ar) > ar(n, DEUX) 
accepter('b', n, DEUX, ar) -> ar(n, UN) 
accepter(x, n, e, ar) -> ar(n, KO) ((x, e) != ('a', UN) et != ('b', DEUX))
1.7.1.4 Implémentation du client du serveur sans état (Stateless)

Même question pour le client.

Debut & Mot('a'::'b'::'a'::'b')
Debut -> initier(rep) & EnCours
EnCours & rep(n, e) & Mot(l::mot) -> accepter(l, n, e, rep) & Mot(mot) & EnCours (e != KO) 
EnCours & rep(n, e) & Mot(vide) -> Succes (e != KO)
EnCours & rep(n, KO) & Mot(m) -> Echec

1.8 Découverte de services

soc_discovery.png

Figure 1: Architecture pour la découverte de services (source : SOA, de Thomas Erl)

1.8.1 Exercice : spécification d'un annuaire de services

Implémenter un annuaire de services possédant deux canaux, l'un permettant de publier un service, l'autre de requérir un service.

canaux fournis :

  • publier(canal, info, ret) : publication sur le registre du service accessible par "canal" et correspondant à la description "info"
  • requerir(info, ret) : requête permettant de récupérer un canal correspondant à la description "info"
1.8.1.1 Solution

Etat : Table(info, canal) (on suppose pour simplifier que deux canaux distincts ne sont pas décrits identiquement, autrement dit que Table est une relation fonctionnelle.)

// Cas d'une première publication
publier(canal, info, ret) & (Table(info, _) inactive) -> ret(PUBLIE) & Table(info, canal)
// Cas d'une mise-à-jour
publier(canal, info, ret) & Table(info, k) -> ret(MAJ) & Table(info, canal)

// Cas d'une requête satisfaite
requerir(info, ret) & Table(info, canal) -> ret(canal) & Table(info, canal)
// Cas d'une requête non satisfaite
requerir(info, ret) & (Table(info, _) inactive) -> ret(AUCUN_SERVICE)

1.9 Composition

Formes duales de composition : bibliothèques contre frameworks, serveurs contre orchestrateurs

Définition d'une bibliothèque et d'un framework

  • Cas élémentaire : fonction principale (main) appelant une fonction adjointe f
  • Bibliothèque = implémentation de la fonction adjointe f

    L'utilisateur définit la fonction principale main et y utilise la fonction adjointe f.

  • Framework = implémentation de la fonction principale

    L'utilisateur implémente la fonction adjointe f pour paramétrer la fonction principale main.

Deux rôles pour un service

  • Serveur : analogue d'une bibliothèque
  • Orchestrateur (client) : analogue d'un framework

2 Services SOAP

Instanciation des principes précédents à l'aide de normes dans le cadre d'une modèle orienté processus (et non ressources)

Forme de système RPC ("remote procedure call") adapté au Web et favorisant l'interopérabilité

2.1 Première génération de services Web (2000)

La première génération de services Web se compose ainsi :

  • un langage pour décrire les interfaces : Web Services Description Language (WSDL),
  • un langage pour décrire les types de données : XML Schema Definition Language (XSD),
  • un langage pour décrire le type des messages échangés : SOAP (initialement Simple Object Access Protocol),
  • une technologie pour découvrir de nouveaux services : Universal Description, Discovery, and Integration (UDDI), et
  • une configuration de base : WS-I Basic Profile.

Cette première génération, adoptée rapidement, présente cependant de nombreux défauts : des fonctionnalités indispensables pour une programmation concurrente et répartie sont absentes.

2.2 Seconde génération de services Web (extensions WS-*) (2006)

La première génération ne permet pas de résoudre des problèmes classiques concerant la répartition et la concurrence. La seconde génération permet de pallier cette faiblesse en fournissant une riche collections de normes, plus sophistiquées.

  • WS-Policy
  • WS-Security
  • WS Atomic Transaction
  • WS ReliableMessaging
  • WS-Addressing
  • (etc.)

2.3 Représentation dans le modèle conceptuel

Service SOAP = ensemble d'opérations op

k(op, arg, ret) : invocation de l'opération op appartenant au service k avec les arguments arg

2.3.1 Forme générique

Serveur : consommation de la requête et production de la réponse, avec une possible modification de l'état

k(op, arg, ret) & Etat(s) ---> ret(val) & Etat(s')

La flèche —> signifie que le résultat n'est pas obtenu en général par une réduction atomique, mais par une suite de réductions.

Client

// Production de la requête et blocage en attente de la réponse
... -> k(op, arg, ret) & Blocage(ret)
// Consommation de la réponse avec déblocage
Blocage(ret) & ret(val) ->

Pendant le blocage, aucune action ne se produit dans la même activité (thread), excepté l'émission du message.

Propriétés

  • Canal : port d'entrée
  • Protocole requête-réponse synchrone (communication asynchrone mais avec blocage du client)
    • Côté client : la production de la requête a pour successeur (suivant le temps logique) la consommation de la réponse.

2.3.2 Communication asynchrone sans blocage

Il est possible d'éviter le blocage, en passant à une communication asynchrone par une mise en attente, correspondant à la promesse d'une réponse future. Cf. la solution proposée pour réaliser une communication asynchrone au-dessus d'un protocole requête-réponse synchrone.

3 Services Rest

Modèle orienté ressources

  • 2000 : Fielding - Formalisation du style d'architecture REST (Representational State Transfer)
  • 2003-2004 : "REST started getting some traction with developers working with Internet-facing services in 2003/2004 - at least with them actually associating their services with the moniker "REST" - most visibly with two high profile, self-described "REST APIs": Flickr, and Amazon. Interestingly, both services also offered parallel SOAP based interfaces, but neither saw much use compared to the "REST API". As a result, the REST community embraced these services and used them as a means to further explain the value and appeal of using the REST style on the Web." (Citation de Mark Baker : cf. http://www.infoq.com/articles/mark-baker-hypermedia)
  • 2007 : Richardson, L. and Ruby, S. (2007) Restful web services. O’Reilly. Première formalisation

3.1 Les cinq principes

3.1.1 Adressabilité des ressources

Langage des URI (Uniform Resource Identifiers)

scheme://authority/path?query#fragment

3.1.2 Interface uniforme

CRUD = Create Read Update Delete

en http : PUT GET (PUT ou POST) DELETE

3.1.3 Représentation des ressources

1 ressource -> * représentations (différents formats, langues, etc.)

3.1.4 Communication sans état

cf. supra

3.1.5 Canaux (hyperliens) comme moteur de l'état applicatif

HATEOAS = Hypermedia as the Engine of Application State

On peut voir une ressource comme un état d'une application. Un client interagit avec l'application dans un état donné, puis une requête peut provoquer un changement d'état : le serveur répond alors en transmettant un hyperlien vers la ressource correspondant à l'état suivant de l'application.

3.2 Exercice sur les méthodes HTTP

Deux propriétés importantes :

  • pureté des fonctions (absence d'effets, "safe methods") : GET
  • idempotence des méthodes (deux requêtes consécutives ont le même effet qu'une requête) : PUT, GET, DELETE

La pureté des fonctions garantit la possibilité de mettre en cache. L'idempotence permet de répéter des requêtes sans effets observables, ce qui est utile pour gérer la perte de messages. La pureté implique l'idempotence.

Ces deux propriétés permettent de classer les méthodes HTTP, comme nous allons le voir.

  • pur, idempotent : GET
  • pur, non idempotent : absurde
  • impur, idempotent : PUT, DELETE
  • impur, non idempotent : POST

Représentation des méthodes dans le modèle chimique

Canal en deux composantes :

  • composante principale indiquant la ressource mère
  • composante secondaire identifiant la sous-ressource de la ressource mère

Notation : k/id pour la ressource mère k et la sous-ressource id

Message consistant en :

  • la méthode CRUD (ici verbes du protocole http)
  • les informations pertinentes
  • le canal de retour

notation : (CRUD, info, ret)

3.2.1 Création d'une ressource

k/id(PUT, val, ret) : création d'une nouvelle ressource à l'adresse k/id (définie par le client) et de valeur val

k/id(PUT, val, ret) & (Ressource(id, _) inactive)-> ret(OK) & Ressource(id, val)
  • condition : absence de Ressource(id, _) dans l'état du serveur
  • modification de l'état qui s'agrandit
  • idempotence

3.2.2 Lecture d'une ressource

k/id(GET, ret) : lecture de la ressource id

k/id(GET, ret) & Ressource(id, val) -> ret(val) & Ressource(id, val)
  • pureté (pas d'effets de bord puisque l'état est inchangé
  • idempotence

3.2.3 Mise-à-jour d'une ressource

Mise-à-jour absolue : PUT (à comparer avec la création)

k/id(PUT, val, ret) : mise-à-jour de la ressource à l'adresse k/id avec la valeur val

k/id(PUT, val, ret) & Ressource(id, u) -> ret(OK) & Ressource(id, val)
  • modification de l'état sans création de nouvelle ressource
  • idempotence

Mise-à-jour relative : POST (mnémotechnique : POST sur un forum)

k(POST, val, ret) : mise-à-jour de la ressource mère d'adresse k, avec création d'une nouvelle sous-ressource d'adresse k/id, où id est un nouvel identifiant créé par le serveur

k(POST, val, ret) & GenerateurIdentifiant(id) -> 
  ret(id) & Ressource(id, val) & GenerateurIdentifiant(id+1)
  • création d'une sous-ressource dont l'adresse k/id est récupérée par le client
  • pas d'idempotence

3.2.4 Destruction d'une ressource

k/id(DELETE, ret) : destruction de la ressource d'adresse k/id

k/id(DELETE, ret) & Ressource(id, val) -> ret(OK)
k/id(DELETE, ret) & (Ressource(id, _) inactive) -> ret(KO)
  • destruction d'une (sous-)ressource connue du client
  • idempotence

Version history: v1: 2016-10-19.
Comments or questions: Send a mail.
The webpage content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.