GICOM
Application de commerce électronique

Etape 4: Sous-système bancaire persistant et fiable

Projet de M2GI option SRR et RICM3 option SR

Année Universitaire 2005-2006

Université Joseph Fourier

 

Contributeur(s) étape : Sacha Krakowiak, David Felliot, Fabienne Boyer, Sébastien Chassande, Didier Donsez

Encadrement M2GI/SRR : Didier Donsez, Sara Bouchenak

Encadrement RICM3/SR : Pierre-Yves Gibello, Maxime Martinasso

PLAN

1      Objectifs. 1

2      Principes d'implémentation. 4

2.1       Hiérarchie transactionnelle. 4

2.2       Contrôle de l'atomicité : protocole de validation à deux phases. 4

3      Réalisation du protocole de validation à deux phases. 9

3.1       Serveur de commerce. 11

3.2       Gestionnaires de transaction. 11

3.3       Objets persistents recouverables. 12

4      Contrôle de Concurrence. 12

4.1       Ordonnancement Total par Estampillage. 13

4.2       Ordonnancement Partiel par Estampillage. 16

5      Implantation de l'ordonnancement partiel (des transactions) par estampillage. 18

 

1      Objectifs

L'émission d'un ordre d'achat d'un client vers le serveur de commerce doit déclencher l'exécution des actions suivantes :

Ces trois actions doivent s’exécuter de manière indivisible (ou atomique) afin de respecter la cohérence de l'ensemble du système comprenant le serveur de commerce électronique, les banques, les fournisseurs et les clients.

 

Pour cela, ces actions doivent être exécutées dans le contexte d’une transaction. La transaction qui démarre peut soit se terminer par la validation des modifications effectuées, soit se termine par un abandon (abort) causé par le programme (qui propose par exemple la possibilité de se retracter avant la fin du traitement), par le système en cas de violation de contraintes d’intégrité ou en cas de défaillance (crash).du système. En cas d’abandon, l’état précédent du système doit être rétabli (rollback).

 

Les propriétés nécessaires au respect du bon fonctionnement du système sont propriétés ACID :

 

Le transaction fait donc passer le système d’information d'un état cohérent initial à un état cohérent final.

Comme l’ensemble du système est distribué sur plusieurs sites, la transaction est dite répartie.

Les transactions sont mises en œuvre par un système transactionnel au moyen de mécanismes de reprise sur panne et de contrôle de concurrence. Dans l’étape 4, vous implémenterez la terminaison des transactions avec le protocole de validation à 2 phases ( Two Phase Commit : 2PC) et le contrôle de concurrence par estampillage.

Quelles lectures pour en savoir plus :

J. Gray and A. Reuter, « Transaction Processing: Concepts and Techniques », Morgan-Kaufmann, 1993

Les transactions par son inventeur

P.A. Bernstein, E. Newcomer, «Principles of Transaction Processing for the Systems Professional», Ed. Morgan Kaufmann, 1997, ISBN 1-55860-415-4.

la bible des Moniteurs Transactionnels

P.A. Bernstein, V. Hadzilacos, N. Goodman, «Concurrency Control and Recovery in Database Systems», Ed. Addison-Wesley, 1987

beaucoup de  techniques de contrôle de concurrence et de reprise sur panne.

Besancourt, Cart, Ferrié, Guerraoui, Pucheral, Traverson, «Les Systèmes Transactionnels», Ed. Hermes, 1997, ISBN 2-86601-645-9.

la communauté française « noyaux transactionnels »

2      Principes d'implémentation

2.1   Hiérarchie transactionnelle

Nous proposons de réaliser un serveur CORBA gestionnaire de transactions indépendant du type d’applications gérées (bancaire, réservation de billet d’avion, …). Remarquons que l’OMG en spécifie un pour CORBA, appelé OTS (Object Transaction Service).

Les sites participant à la transaction réparti sont alors :

Le serveur de commerce initie la transaction en démarrage celle ci auprès du gestionnaire de transactions (TM : TransactionManager) global qui coordonnera la transaction jusqu’à sa terminaison complète. Sur chaque site participant aux transactions, un gestionnaire de transactions local gère l’enregistrement des ressources transactionnelles dites recouverables du niveau local vers le niveau global. Les ressources recouverables sont des objets dont il est possible de défaire les modifications effectuées tant que la transaction n’est pas complétement validée. Un objet recouverable peut être un objet persistant (Account, …) ou un objet dont l’action est réalisée qu’à la 2ème phase de validation (envoi différé de mail vers un fournisseur).

2.2   Contrôle de l'atomicité : protocole de validation à deux phases

La propriété d'atomicité doit être garantie dans le cadre d'un système réparti. Le mécanisme de validation doit assurer que toutes les mises à jour sont exécutées sur tous les sites ou qu'aucune ne le soit. Or chaque site est responsable de la validation des modifications locales effectuées par la transaction. En conséquence il est nécessaire de coordonner l'ensemble des validations afin d'empêcher la création d'incohérences.

Le protocole de validation à deux phases permet de coordonner les validations des actions effectuées par tous les sites participant à la transaction. Le principe consiste ici à diviser la transaction en deux phases. La phase 1 réalise la préparation des mises à jour des objets modifiés par la transaction. La phase 2, réalisée seulement en cas de succès de la phase 1, intègre effectivement les résultats des mises à jour

Le contrôle du système réparti est centralisé sous la direction d'un site appelé coordinateur global, les autres étant des participants.

Lors de l'étape 1, le coordinateur global demande aux autres sites s'ils sont prêts à commettre leurs mises à jour par l'intermédiaire du message Prepare. Si tous les participants répondent positivement, le message Commit est diffusé : tous les participants effectuent leur validation. Si un participant n'est pas prêt et répond négativement, le coordinateur demande à tous les autres sites de défaire la transaction avec le message Rollback.

Chaque intervenant (coordinateur global, coordinateur local ou participant) suit un diagramme d'état donné. Dans notre cas, chaque serveur de transactions local qui joue le rôle de coordinateur local,  suit le diagramme d'état d'un participant.

2.2.1   Coordinateur :

INITIAL : la réception de l'odre Begin  par le coordinateur fait passer celui-ci dans l'état INITIAL. Dans cet état, un identificateur de transaction est alloué, et diverses initialisations sont effectuées (journaux, etc).

PREPARE : la réception de l'ordre Commit par le coordinateur fait passer celui-ci dans l'état PREPARE. Dans cet état, il effectue la préparation de la transaction, qui consiste à envoyer aux participants une requête PREPARE, leur demandant d'effectuer la préparation de la validation des actions liées à la transaction. On doit assurer que les actions effectuées pendant la phase de préparation sont par la suite :

·        soit "défaisables", si l'on a exécutées ces actions durant le PREPARE

·        soit "faisables", si l'on a simplement enregistré les actions à faire durant le PREPARE

COMMITED : le coordinateur passe de l'état PREPARE à l'état COMMITED lorsqu'il a reçu la réponse VoteCommit de la part de tous les participants à qui il avait envoyé un ordre Prepare. Dans cet état, il envoie aux participants une ordre Commit, leur demandant de valider les actions liées à la transaction. Une panne du coordinateur durant l'état COMMIT engendre le "re-jeu" de la validation des modifications, jusqu'à ce que ce re-jeu soit entièrement terminé..

ABORTED or ROLLBACKED : le coordinateur passe de l'état PREPARE à l'état ABORTED/ROLLBACKED lorsqu'il a reçu la réponse VoteRollback de la part d’au moins un participant à qui il avait envoyé un ordre Prepare. Il passe également dans cet état si une panne arrive durant l'état PREPARE ou durant l’état initial. Dans cet état, il envoie aux participants un ordre Rollback, leur demandant de défaire les actions liées à la transaction.Une panne du coordinateur durant l'état ABORTED/ROLLBACKED engendre le "re-jeu" de l’abandon des modifications, jusqu'à ce que ce re-jeu soit entièrement terminé.

Si une panne du coordinateur arrive pendant la première phase, les participants doivent abandonner la transaction. Pour cela, au redémarrage, le coordinateur envoie une requête Rollback à tous les participants de la transaction jusqu’à ce que le rejeu de l’abandon de la transaction soit complètement effectuée

Si une panne du coordinateur arrive pendant la deuxième phase (état COMMITED or ABORTED/ROLLBACKED), les participants doivent valider ou abandonner la transaction. Pour cela, au redémarrage, le coordinateur envoie une requête Commit ou une requête Rollback à tous les participants de la transaction jusqu’à ce que le rejeu de la validation ou de l’abandon de la transaction soit complètement effectuée

2.2.2   Participant :

INITIAL : la réception d’un requête applicative (debit(), credit(), …) avec un nouveau contexte transactionnel (itentifiant de transaction) par une ressource recouverable provoque le passage du coordinateur local dans l'état INITIAL pour cette transaction, l’enrôlement auprès du coordinateur global ainsi que diverses initialisations (journaux, etc).

PREPARE : la réception de l'ordre Prepare par un participant fait passer celui-ci dans l'état PREPARE. Dans cet état, il effectue la préparation de la transaction, qui consiste à envoyer aux ressources recouverables éventuelles une requête PREPARE, leur demandant d'effectuer la préparation des actions liées à la transaction.

Dans tous les cas, on doit assurer que les actions effectuées pendant la phase de préparation sont par la suite :

·        soit "défaisables", si l'on a exécutées ces actions durant le PREPARE

·        soit "faisables", si l'on a simplement enregistré les actiosn à faire durant le PREPARE

READY : READY est l'état intermédiaire entre PREPARE et COMMITED/ABORTED pour un participant. Le participant passe automatiquement de l'état PREPARE à l'état READY lorsqu'il a fini d'exécuter les deux étapes du PREPARE. Dans cet état, il n'effectue pas d'actions, mais garantit simplement qu'en cas de panne, il est capable de se retrouver dans le même état que celui précédent la panne (état a la sortie du PREPARE), afin d'enchaîner sur une validation ou sur un abandon.

COMMITED : le participant passe de l'état READY à l'état COMMITED lorsqu'il reçoit le message Commit de la part du coordinateur. Dans cet état, il effectue l’envoi aux ressources recouverables éventuelles une requête Commit en leur demandant de valider les actions liées à la transaction.

ABORTED ou ROLLBACKED : le participant passe de l'état READY à l'état ABORT lorsqu'il reçoit le message Rollback de la part du coordinateur.  Dans cet état, il l’envoi aux ressources recouverables éventuelles une requête Rollback, leur demandant de défaire les actions liées à la transaction

Si une panne du participant arrive durant un de ces états, le coordinateur ne recevant pas de réponse à sa requête, détecte la panne. Au redémarrage du participant, ce dernier peut réclamer au coordinateur le devenir de la transaction et effectuer le rejeu de la validation ou de l’abandon de la transaction au niveau du participant.

2.2.3   Opérations idempotentes

On peut remarquer que les opérations de validation ou d’abandon peuvent être rejouées plusieurs fois par tout intervenant dans la transaction.  On devra s'assurer que cela ne pose pas de problèmes, en rendant ces opérations idempotentes si cela est nécessaire

On pourra toutefois accepter que l'unicité des messages adressés aux clients et aux fournisseurs (envoi de mail) ne soit pas assurée. Le destinataire (founisseur) peut donc recevoir plusieurs mails ayant le même identificateu. La gestion des commandes doit ignorer les duplicatas.

2.2.4   Traitement des pannes

On a pu remarquer à la lecture de la section précédente que les actions qui sont à effectuer en cas de panne dépendent de l'état dans lequel se trouve l'intervenant au moment de la panne. Pour connaître cet état, ainsi que pour être capable de "défaire" certaines actions, on utilisera des journaux (logs) dans lequel on enregistrera de manière synchrone les informations pertinentes. Le schéma de base est le suivant :

Ecrire (log, etat)
Ecrire(log, informations sur les actions à exécuter )
Exécuter (actions)

En cas de panne ou d'impossibilité à poursuivre la transaction, un intervenant doit être capable de défaire les actions déjà exécutées. Dans le doute, il peut décider de défaire une action qu'il n'a pas effectuée.

Si le coordinateur tombe en panne après l'émission du message Prepare, tout participant ayant voté prêt est alors bloqué en attente de recevoir le message Commit ou Rollback. Les participants attendent donc que le coordinateur redémarre. Une solution serait de forcer après un certain délai la transaction locale à passer dans l'état ABORTED/ROLLBACKED.  Le protocole de validation à trois phases permet de résoudre ce problème, mais pour des raisons de simplicité, il ne sera pas implémenté dans l'application demandée.

Les tableaux ci-dessous présentent les différentes pannes possibles et les reprises correspondantes.

Etat du coordinateur lors de la Panne

Reprise après panne

INITIAL

la transaction est oubliée

PREPARE

annuler les actions effectuées (passer dans l'état ABORTED/ROLLBACKED)

COMMITED

reprendre la validation

ABORTED/ROLLBACKED

reprendre l’abandon

 

Etat du participant lors de la Panne

Reprise après panne

INITIAL

la transaction est oubliée

PREPARE

annuler les actions effectuées (passer dans l'état ABORTED/ROLLBACKED)

READY

remettre le participant dans l'état READY 

COMMITED

remettre le participant dans l'état READY 

ABORTED/ROLLBACKED

remettre le participant dans l'état READY

3      Réalisation du protocole de validation à deux phases

Le protocole de validation utilisera le support de communication CORBA. L'implémentation des participants à la transaction nécessite de poser certaines hypothèses sur le support de communication utilisé :

Le protocole IIOP utilise des connexions TCP.

L’envoi et la récupération de mail par SMTP (Simple Mail Transfer Protocol) est également basé sur des connexions TCP mais il répond aux hypothèses posées.

L’appel à la validation (Commit) ou (Rollback) par le servlet de gestion des ordres d'achat ainsi que l’échange entre le coordinateur globales et les participants locaux, seront réalisés par des simples appels de méthodes distribués (requêtes CORBA). Un retour normal de l'appel de méthode Prepare signifiera que le participant a donné son accord pour la validation de la transaction. Un retour avec exception levée par CORBA ou par le participant signifiera que le participant est tombé en panne, ou bien a donné son désaccord pour valider la transaction. L’identifiant de transaction doit apparaître explicitement dans les requêtes pour véhiculer le contexte transactionnel. Par exemple, les méthodes métier d’Account doivent comporter l’identifiant de transaction (cf schéma).

Le schéma ci-dessous illustre le déroulement possible d'une transaction de transfert d’agent entre un compte client et un compte fournisseur.

Les envois de mail sont effectifs dans la 2ème phase de validation.

Figure : Démarrage de la transaction

 

Figure : Validation de la transaction se terminant sur un succès

 

Figure : Validation de la transaction se terminant sur un abandon

3.1   Serveur de commerce

L'ordre d'achat envoyé par le client est reçu par la servlet Buy. La transaction d'achat est constituée des opérations suivantes:

L'enregistrement des ordres d'achat s'effectuent sur le site du serveur de commerce. L'atomicité est contrôlée par propagation en continu : les ordres d'achat sont directement écrits dans la base de données pendant la phase de préparation. En cas de retour-arrière (rollback), les enregistrements doivent être effacés.
Remarque : l'atomicité aurait pu être gérée directement par la base de données. Cependant certains gestionnaires de bases de données (MySql) ne gèrent pas les transactions (elle fonctionne en mode auto-commit).

En cas de panne, la reprise sera gérée au redémarrage des serveurs.

3.2   Gestionnaires de transaction

Le gestionnaire global de transactions est accessible au travers d'une interface IDL.

Les méthodes destinées à l’initiateur de la transaction permettent de :

Les méthodes destinées aux participants de la transaction (les TM locaux) permettent de :

Le gestionnaire local de transactions est accessible par le gestionnaire global au travers d'une interface IDL dont les méthodes sont :

Chaque serveur gère de manière interne les transactions au moyen d’un objet Java Transaction.

En cas de panne, le redémarrage (restart) du gestionnaire de transactions procèdera automatiquement à la reprise de la panne si besoin est. Si la panne a eu lieu alors qu'une transaction était dans l'état READY, un nouvel objet Transaction sera créé pour représenter cette transaction, et réinitialisé convenablement pour que la transaction se retrouve à nouveau dans l'état READY.

3.3   Objets persistents recouverables

Les objets persistants recouverables sont des objets persistants. En conséquence, il hérite de la méthode save qui lui permettant de sauvegarder son état de façon atomique.

Cependant, deux méthodes supplémentaires sont ajoutées :

·        la méthode prepare sauvegarde l’état temporaire de l’objet en attendant le save qui est réalisé à la 2ème phase de la validation.

·        la méthode undo abandonne l’état temporaire tant que le save n’est réalisé.

Le seul type d’objets persistants recouverables dans l’application bancaire est Account.

4      Contrôle de Concurrence

Comme les transactions sont concurrentes pour l'accès aux objets recoverables, il s'agit de contrôler la concurrence afin de garder la propriété de consistance en rendant l'exécution entrelacée des transactions sérialisable.

Pour garantir la sérialisibilité, plusieurs techniques peuvent être utilisées.

·        Verrouillage à 2 phases

·        Estampillage

·        Certification

Les deux premières  techniques sont dites pessimistes car elles préviennent à priori les incohérences possibles. La troisième techniques est dite optimiste car elle ne vérifie l’existence d’incohérences réelles qu’au moment de la validation de la transaction.

Ces techniques sont présentées dans http://www-adele.imag.fr/~donsez/cours/bdcc.pdf

Un bon tour de la question est traité par BERNSTEIN, P. A., AND GOODMAN, N. Concurrency control in distributed database systems. ACM Comput. Survey. 13, 2 (June), 185- 221 et dans l’ouvrage référencé dans la bibliographie.

La technique choisie pour contrôler la concurrence dans les objets bancaires est l'ordonnancement partiel par estampillage. Nous commencerons par présenter l’ordonnancement Total par Estampillage pour comprendre l'ordonnancement partiel par estampillage. Bien que moins utilisé que le verrouillage à deux phase dans les systèmes transactionnels, l'ordonnancement partiel par estampillage offre l’avantage d’être plus simple à implanter dans le contexte du projet GICOM.

4.1   Ordonnancement Total par Estampillage

4.1.1   Principe :

Vérifier que les objets sont accédés par des transactions d’estampilles croissantes.

Le graphe de précédence reste donc sans circuit. L’ordre de précédence est celui des Estampilles

Dans le cas où une transaction est "en retard", elle est abandonnée (rollback) puis elle peut être relancée par l'initiateur avec une nouvelle estampille.

possibilité de famine : une transaction n’est pas garantie de se terminer dans un temps borné.

4.1.2   Algorithme :

lire(Transaction trs, RecoverablePersistentObject obj) {

/*

Lire ( Ti, O )

            SI E(O) = i

            ALORS

                        Exécuter la lecture

                        E(O):= i

            SINON

                        ROLLBACK(Ti)

*/

            int stamp=ojb.getStamp();

            if(stamp <= trs.xid) {

                        // Exécuter la lecture

                        ojb.setStamp(trs.xid)

            } else {

                        trs.rollback();

            }

}

 

 

ecrire(Transaction trs, RecoverablePersistentObject obj) [

/*

Ecrire ( Ti, O )

            SI E(O) = i

            ALORS

                        Exécuter l’écriture

                        E(O):= i

            SINON

                        ROLLBACK(Ti)

*/

            int stamp=ojb.getStamp();

            if(stamp <= trs.xid) {

                        // Exécuter l'écriture

                        ojb.setStamp(trs.xid)

            } else {

                        trs.rollback();

            }

}

 

4.1.3   Exemple 1

            T1        T2                   A

            100      200                  E=0

(1)       READ(A)                                E=100

 

(2)                   READ(A)                    E=200

 

(3)                   WRITE(A)      E=200

                                  

(4)       WRITE(A)                  Rollback T1

 

 

4.1.4   Exemple 2

            T1        T2                   A         B

            100      200                  E=0     E=0

(1)       READ(A)                                E=100

 

(2)                   READ(B)                    E=200

 

(3)       READ(B)                                Rollback T1

 

(4)                   WRITE(B)                  E=200

 

4.2   Ordonnancement Partiel par Estampillage

4.2.1   Principe

Ordonnancer des actions non permutables (Ecriture-Lecture, Lecture-Ecriture, Ecriture-Ecriture)

L'algorithme utilise 2 estampilles par objet pour distinguer les lectures et les écritures.

EL(G) contient l’estampille de la dernière transaction lecteur

EE(G) contient l’estampille de la dernière transaction écrivain

4.2.2   Algorithme

lire(Transaction trs, RecoverablePersistentObject obj)

/*

Lire ( Ti, O )

            SI EE(O) = i

            ALORS

                        Executer la lecture

                        EL(O):= Max( EL(O),i)

            SINON

                        ROLLBACK(Ti)

*/

 

 

            int readStamp=ojb.getReadStamp();

            int writeStamp=ojb.getWriteStamp();

            if( writeStamp<= trs.xid) {

                        // Exécuter la lecture

                        ojb.setReadStamp(Integer.Max(readStamp,trs.xid))

            } else {

                        trs.rollback();

            }

}

 

ecrire(Transaction trs, RecoverablePersistentObject obj) {

/*

Ecrire ( Ti, O )

                        SI EE(O) = i et EL(O) = i

                        ALORS

                                   Executer l’écriture

                                   EE(O):= i

                        SINON

                                   ROLLBACK(Ti)

*/

            int readStamp=ojb.getReadStamp();

            int writeStamp=ojb.getWriteStamp();

            if( readStamp<= trs.xid && writeStamp<= trs.xid) {

                        // Exécuter la lecture

                        ojb.setWriteStamp(trs.xid))

            } else {

                        trs.rollback();

            }

}

Tous les arcs du graphe de précédence sont dans l’ordre des estampilles (graphe sans circuit)

5      Implantation de l'ordonnancement partiel (des transactions) par estampillage

Les objets recouverables (recoverable) doivent contenir une estampille en lecture et une estampille en écriture.

Toute méthode d'objet recouverables doit tester si la transaction courante peut lire ou écrire l'objet avant de commencer l'exécution de la méthode.

Tout appel de méthode d'un objet recouverable peut lever un exception ConcurrencyControlException

Tout objet recouverable peut provoquer l'abandon de la transaction en cas de conflit en invoquant la méthode rollback() sur la transaction.

Question : Les estampillages sont ils des attributs transients ou persistants de l'objet recouverable ?

Question : Est il vraiment nécessaire de sauvegarder l'estampille en lecture quand l'objet est seulement accédé en lecture ?