Chiron (3/11) : le sourçage d'événements

15 views
Skip to first unread message

Laurent Caillette

unread,
Jan 23, 2018, 1:45:57 AM1/23/18
to tec...@googlegroups.com

Dans le billet précédent nous avons passé en revue les tares majeures du SGBDR et les nuisances occasionnées à l'activité de développement. Nous allons maintenant étudier une solution qui non seulement résoud le problème de la persistance, mais simplifie dramatiquement le développement, les tests, le déploiement et l'exploitation. 

J'ai déjà mentionné plusieurs fois l'architecture "LMAX"
. L'idée c'est qu'une application serveur reçoit des messages en entrée. Ces messages définissent une succession de changements d'états. Toutes les données "chaudes", c'est à dire l'état de l'application, résident entièrement en mémoire vive. Les messages sont traités séquentiellement donc de façon complètement déterministe. Comme il n'y a pas de concurrence d'accès il n'y a pas de verrouillage donc pas de commutation entre fils d'exécution et donc pas d'invalidation des caches du processeur (voir article précédent sur Netty). Comme la séquence de messages en entrée définit l'état de l'application, il suffit de persister les messages et de les rejouer pour restaurer un état antérieur. Ce modèle de conception s'appelle le "sourçage d'évènements" ("Event Sourcing"
). 

Donc là en dix lignes on vient de pulvériser la notion même de SGBDR. On vient aussi de tripler (au moins) les performances de l'équipe de développement. J'explique.

--- Le code applicatif c'est du Java délivré de tous les compromis nécessaire à une projection objet-relationnel. Genre, les entités persistantes immuables et les collections de Guava pour pas un rond de plus. 

--- On dégage tout le code pour faire rentrer les objets du code applicatif dans le SGBDR et on organise un pot de départ pour le consultant Hibernate. Le code de persistance qui écrit et lit les messages est le même que pour se parler sur le réseau. 

--- Le code de migration des données est embarqué dans le code applicatif. Quand on persiste des messages, on persiste leur version de schéma. N'importe quelle version de l'application doit savoir lire tous les schémas antérieurs. Avantage : le code de migration s'écrit et se teste en pur Java.

--- Le code de requêtage c'est juste des parcours de listes d'objets en mémoire et on organise un pot de départ pour le consultant Oracle. 

--- La modélisation applicative se fait en décrivant les messages en entrée et en sortie. On finance les pots de départ avec l'économie réalisée sur la license de PowerAMC.

--- Cette modélisation sous forme de messages se décline immédiatement en tests unitaires.

--- La séquence de messages est une piste d'audit au grain le plus fin. On peut la sauvegarder sur un système tiers (genre Amazon S3). Oui ça veut dire que l'application sait gérer ses propres sauvegardes, donc encore un pot de départ, cette fois pour l'administrateur système.

--- Comme le code applicatif est parfaitement séquentiel, il n'y a plus de problèmes de concurrence d'accès (plus de détails là-dessus très bientôt).

Sérieux, le sourçage d'événements c'est de la bombe. Il anéantit des problèmes majeurs qui plombent les développement basés sur des SGBDR. Tu vois ça tu te dis : "Non je peux pas c'est de la triche." Mais toute l'informatique c'est de la triche et donc ta paye aussi. Je sens que la triche ne va pas poser problème longtemps.

Bon il y a des questions qui se posent. Que se passe-t-il quand le journal devient trop gros ? Deux cas de figure.

Déjà il se peut que ça n'arrive jamais parce que l'application remet périodiquement la plupart des données à zéro, par exemple en début de journée. Les données chaudes peuvent devenir froides, c'est à dire qu'on les historise. Est-ce que ça ne va pas nous faire retomber dans le problème d'avant ? Mais on a vu avec l'exemple du modèle en étoile que les problèmes disparaissaient quand on s'abstenait de toute mise à jour ou suppression. Si le type de données s'y prête on peut utiliser une base documentaire comme Lucene et bénéficier de ses impressionnantes capacités d'indexation. On peut aussi ressortir un SGBDR juste pour me faire enrager.

Si le journal dépasse une certaine taille, on peut le compresser en prenant un instantané de l'état, puis en l'incluant au début d'un nouveau journal (git et Prevayler font déjà ça).

Lors d'une reprise sur panne, il faut que le rejeu du journal s'effectue assez rapidement. Mais comme la logique applicative ne comporte pas d'entrées-sorties c'est normalement le cas. Pour certains calculs coûteux on déclenche un traitement asynchrone dont seul le résultat sera journalisé. 

Bien sûr le sourçage d'événements ne convient pas pour tout. Maintenant un petit exercice.

Considérons toutes les applications d'informatique de gestion qu'on connaît. Combien satisfont les critères suivants :
- Toutes les données chaudes tiennent dans le tas d'une JVM.
- Un seul serveur absorbe toute la charge, considérant qu'on peut consommer la totalité de son temps processeur.

Si on compte toutes les applications d'informatique de gestion utilisées en interne, je dirais au moins la moitié, peut-être les trois quarts. Il y a des applications qui traitent des volumes importants mais dont les données cessent très vite d'être chaudes. Il y a des applications qui nécessitent des serveurs en grappe parce qu'on n'arrive pas à utiliser plus de `15 %` de leur processeur. Donc là je ne sais pas pour qui c'est une bonne nouvelle, mais je viens d'amputer les vendeurs de SGBDR de la moitié de leur revenus (c'est pas tout à fait vrai dans la mesure où les gros trucs sont facturés plus cher). 

Une autre question toute simple : s'il y a un seul serveur, que se passe-t-il en cas de panne ? C'est une question de budget. 

Si on est riche on met en place une solution de réplication basée sur la garantie de l'unicité d'un dirigeant au sein d'un groupe de serveur. Ça se fait grâce aux protocoles Paxos ou "Raft"
, qui garantissant que tous les membres d'un groupe voient bien le même état. Je n'ai étudié que Raft, qui est conçu pour être plus simple que Paxos. Comme Raft est basé sur un journal d'événements, il y a une compatibilité fondamentale avec le modèle du sourçage d'événements. Notons que la réplication de journal est le grand classique des systèmes distribués puisque c'est là-dessus que se basent git ou la Blockchain. 

Je ne veux pas m'étendre maintenant sur cette histoire de journal répliqué en temps réel vu que ça mérite un livre entier. Tout ce qu'il faut retenir c'est que le sujet demeure hors de portée du grand public ; heureusement il y a moyen de se rabattre sur une solution de type "DRBD"
, qui réplique une partition sur une machine distante (ou plusieurs).

Dans le prochain épisode nous verrons plus en détail le cycle de vie du journal.

Chris Z

unread,
Jan 23, 2018, 8:17:23 AM1/23/18
to tec...@googlegroups.com
Super billet.

J'ai déjà mis en oeuvre des archi Event Sourcing (DD+ CQRS) en java et scala/akka, avec plus ou moins de succès, car même si l'approche solutionne pas mal de problèmes, elle en soulève aussi quelques uns, parfois complexes (dont les plus insolubles: humains).

Quelques questions:

> L'idée c'est qu'une application serveur reçoit des messages en entrée. Ces messages définissent une succession de changements d'états.

Tu ne distingue pas commande/evènement ?

> Le code de requêtage c'est juste des parcours de listes d'objets en mémoire et on organise un pot de départ pour le consultant Oracle.

Mmm, j'ai du mal à voir. Le requêtage du modèle (in-memory state) peut-être complexe à implémenter (tri, filtre, pagination). L'implémentation des filtres nécessite des maintiens d'index. Simple pour une recherche par clé (un simple tableau associatif ramène la complexité de recherche de O(n) en O(1)). Mais pour une recherche géographique... Ce point là, je l'adresse justement par la partie Q (du CQRS), avec une bd dénormalisée taillée pour la nature de la donnée et des requêtes.

Mais, là où ça devient tricky, c'est sur l'acceptation d'une commande (apply) qui doit s'assurer du respect des règles métiers. Certaines de ces règles sont traditionnellement gérées par les contraintes d'intégrité de la base, ce qui est pratique. En l'abscence de base, le travail doit être fait dans le code. J'ai rien contre, bien au contraire, mais, l'implémentation se heurte à la problématique précédente, l'exploration efficace du modèle (index).

> La modélisation applicative se fait en décrivant les messages en entrée et en sortie. On finance les pots de départ avec l'économie réalisée sur la license de PowerAMC.

Quid du modèle (état) ? Pour moi l'effort est plus grand: modèle + commande + event (avec diagramme de transitions).

> Comme le code applicatif est parfaitement séquentiel, il n'y a plus de problèmes de concurrence d'accès (plus de détails là-dessus très bientôt).

Tu utilises un seul fil d'exécution pour toute l'appli ? Ou tu as une approche acteur ?

> Toutes les données chaudes tiennent dans le tas d'une JVM.

J'ai eu un soucis de perf avec ça. J'ai plutôt opté pour un stockage off-heap.

Christophe

--
Vous recevez ce message, car vous êtes abonné au groupe Google Groupes "techos".
Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse techos+unsubscribe@googlegroups.com.
Pour envoyer un message à ce groupe, envoyez un e-mail à l'adresse tec...@googlegroups.com.
Visitez ce groupe à l'adresse https://groups.google.com/group/techos.
Pour obtenir davantage d'options, consultez la page https://groups.google.com/d/optout.

Laurent Caillette

unread,
Jan 23, 2018, 8:58:36 AM1/23/18
to tec...@googlegroups.com
Salut Christophe,

Voilà des super-questions ! 

Je ne distingue pas les commandes et les événements. Une commande est persistée si elle affecte l'état du système. Si on a une commande de requêtage pur on ne la persiste pas. Si une commande pourrit l'état de l'application mais que la journée continue alors il faudra peut-être que les versions suivantes soient capables de reproduire le comportement pourri si on veut rejouer à l'identique le journal produit par une vieille version. Ça semble horrible mais ça ne doit pas arriver trop souvent. 

Les règles d'intégrité des données dans la base de données, bof bof. C'est horrible à écrire avec des procédures stockées. Ou alors on a les contraintes déclaratives, mais elles ne permettent pas tout. Finalement tout faire à la main en Java c'est ridiculement simple. Et ça n'empêcherait pas d'utiliser un générateur de POJO avec des contraintes déclaratives (ça doit sûrement exister).

J'aborderai la conservation de données sur le long terme dans un épisode suivant, et ça répondra à la question du requêtage. Mais en deux mots, oui la base de données historique dénormalisée avec juste des ajouts c'est bien. En amont il y a eu moyen de retravailler la requête (par exemple vérifier les permissions).

Mais tout est question de volume. Je travaille avec des volumes pour lesquels parcourir toutes les données dans le tas de la JVM c'est très correct. Sinon, euh... je ferais moins le malin.

Concernant la modélisation, ça dépend où tu vois la complexité. Moi je la vois dans la façon de coupler le client avec le serveur. Mais ça c'est le fait d'une interface graphique assez sophistiquée.

La logique applicative utilise un fil d'exécution dédié, oui. J'ai lu ce que disaient les mecs de LMAX et ça m'a convaincu. Je reparlerai des perfs, mais je réussis à saturer un serveur octocœur parce que la couche réseau prend beaucoup de temps (la sérialisation n'est pas très optimisée). Avec le Reactor il y aurait moyen de distribuer les traitements applicatifs sur plusieurs cœurs, ce qui reviendrait à l'approche acteur que tu évoques. Chiron ne dit pas comment câbler la logique applicative, vu que le Reactor est parfait pour ça.

Ouais l'utilisabilité du tas de la JVM c'est aussi une histoire de volumes. Mon propos c'est qu'en-dessous de certains volumes on peut réaliser des simplifications inouïes.

Je retiens le problème numéro un que tu identifies avec l'approche CQRS/sourçage d'événements : les humains. Là il y a moins de magie, les gens peuvent moins se cacher derrière des outils qui font n'importe quoi. Sur 2 prestataires venus bosser avec le sourçage d'événements j'ai rapidement dégagé les 2. Sur un projet orienté SGBDR j'aurais peut-être mis plus de temps à voir les dégâts.





Reply all
Reply to author
Forward
0 new messages