Micro
services
Qui suis-je ?
Benoît Chanclou

Le complément
de NodeJS
Base de données
NoSQL

Unitaires,
d'intégration,
de charge
Micro-
Service
Pourquoi les
micro-services ?
Cheminement
- Historique
- Parallélisation de services
- Du macro au micro
Historique
Loi de Moore
On arrive aux limites
La puissance de calcul
depuis 10 ans
- les fréquences stagnent
- la puissance d'un cœur n'augmente presque plus
La puissance augmente
car
le nombre de cœurs augmente
=>
Nécessité de paralléliser
Néanmois
Parallélisation
- tous les algorithmes ne sont pas parallélisables
Sinon on utiliserait que des processeurs de cartes graphiques - algorithmes adapté au calcul intensif
cas particuliers du calcul numérique - complexe à mettre en œuvre
Multi-thread, dead lock, accès concurrents, mutex, ...
Gérer de nombreuses requêtes
Requêtes simples, multiples & indépendantes
- Simple :
Pas de processus complexe - Multiples & indépendantes :
Processus parallèlisables
A quel niveau gérer
Processus multi threads
- c'est complexe à programmer
- coûteux en ressources (switch de contexte)
=> réponse la programmation réactive (aka asynchrone)
Plusieurs processus
- les OS sont faits pour cela
Montée en charge
Plus de requêtes
=>
Plus de processus
Quels outils
- Des OS qui gérent
- les processeurs multi-cœurs
- le multi-processus
- Des frameworks réactifs (asynchrones et monothreads)
- Des bases de données
- multi-instances
- ultra performantes
Gérer
la complexité
Qu'est ce qu'un monolithe ?
(aka le macro-service)
Un service
- gros
- complexe
- plein de fonctions
- d'un seul bloc
Le monolithe
Au début
- Petit et rapide
- Facile à mettre en oeuvre
- Tout est au même endroit
Le monolithe
Avec le temps
- Gros et lent
- Difficulté à maîtriser la complexité
- Accumulation de dette technique
- Maintenance de plus en plus coûteuse
Le coût d'un monolithe
- Coût exponentiel
- Régulièrement "on efface tout et on recommence"
coût / fonction
temps
Le coût d'un monolithe
-
Moyens exponentielsMoyens constants - Recommencer => tunnel
- Concurrence des petits
coût cumulé
temps
richesse fonctionnelle
tunnel
développement d'une nouvelle version
release de la version
coût cumulé
- Moyens exponentiels
Le phénix
- Régulièrement "on efface tout et on recommence"
causes
- coût exponentiel
- technologies obsolète
- problème de recrutement
- nouvelle technologie
- concurrence
Microservice
Le microservice
- Un monolithe qui ne grandit pas
- Dette technique raisonnable
- Un coût de maintenance raisonnable
- Le coût cumulé tend à stagner
coût cumulés
temps
Architecture microservice
- Des boîtes noires qui échangent des messages
- Chaque service ne connait son voisin que via son interface API
coûts cumulés
temps
Ce qu'il ne faut pas faire
Les dangers
Formaliser les règles de conception
Danger #1 : Complexité
Composants micro-service
- simplicité de chaque composant
- complexité entre composants
=> formaliser les règles de communication
du code spaghetti au plat de spaghetti
Danger #1 : Complexité
Définir des normes pour les protocoles
- formats des données
- format des échanges
synchrone, asynchrone (callback), offline
Danger #2 : Pannes
Augmentation du nombre de composants
- Augmentation du nombre de pannes possibles
- composant qui ne répond pas
- panne réseau
- ...
Danger #2 : Pannes
Définir des normes pour le fonctionnement
- service minimum
- résilience aux pannes
- redéploiement automatique
Rappel : Performance
Ordre de grandeur du temps d'accès
- Registres / instruction : ~1ns
- Mémoire : ~10ns
- Accès SSD : ~10µs
- Base de données : ~1ms
- Appel API: ~100ms
Un appel d'API c'est extrêmement lent
Danger #3 : Performances
Augmenter le nombre d'appels API
- Augmenter le temps de latence
- Augmenter le temps de réponse
Danger #3 : Performances
Définir des normes d'utilisation
- éviter les appels en cascade
- éviter les appels inutiles
Danger #4 : Déploiement/ops
Augmentation du nombre de composants
- Augmentation du nombre de déploiements
- Augmentation des logs
Danger #4 : Déploiement/ops
Définir des solutions
- Industrialisation du déploiement
- déploiement automatique à partir de git
- auto scaling
-
Surveillance des logs
- alertes automatiques
- monitoring
Les contraintes et avantages
Pour que les dangers
deviennent des
risques acceptables
Les points clés d'un microservice
- Élastique
- Résilient
- Composable
- Minimal
- Complet
Les points clés
Élastique
- il peut y avoir une ou plusieurs instances
- permet la montée en charge
Les points clés
Résilient
- ne doit pas planter si un autre est indisponible
- lors d'une interruption dû à une mise à jour
- lorsque la base est momentanément indisponible
Les points clés
Composable
- seule l'API définit le service
- pas de couplage
- éviter les services de conversion de format
Les points clés
Minimal
- responsabilité unique
- pas de fonctionnalités inutiles
Les points clés
Complet
- toutes les fonctionnalités nécessaires
- il doit être autonome
- possède sa propre base de données
Quelques analogies avec la POO
SOLID
- Simple responsibility principle
- Open/close principle
- Liskov substitution principle
- Interface segregation principle
- Dependency inversion principle
Corollaires
Stateless
L'élasticité implique que toute requête soit
- stateless
- self content
Autorisation
le système est ouvert
- tout est accessible
=> utilisation d'un contrôle d'accès
=> être authentifier
Autorisation
le système doit être performant
ne pas dépendre d'un service d'authentification
=> via token self content
Utilisation de JWT
Droits d'accès
- le service définit et gère
- ses propres rôles
- ses propres droits
Configuration
- le service définit et gère sa propre configuration
Découverte du service
- ce n'est pas WSDL SOAP
- néanmoins des standards apparaissent
- OpenAPI (swagger) permet de spécifier l'API
- JWT permet de gérer l'authentification
- Docker permet de déployer
- ...
Format d'échange
- utilisation de normes pour le format des données
- existantes
- ou à créer
- protocole RESTful pour le CRUD des ressources
- HATEOAS
Webhooks
- ils sont pour les services
ce que sont les messages pour les objets - évitent le couplage
Vie des services
- les services peuvent évoluer
- se scinder si deux rôles
- ou fusionner si couplage
Principaux types
Typologie des services
Différentes types de services ayant chacun leur rôle
- référentiels
- fonctionnels
- intermédiateurs
- orchestrateurs/chorégraphes
Référentiel
Rôle
- Fournir une API CRUD sur des entités
- Gérer les droits d'accès aux entités
- Stocker les entités
- Dédoublonner les entités
- Gérer l'historique des entités
- Valider les données des entités
Remarque
Valider une donnée ≠ les champs sont définis
- ce n'est pas imposer des champs non nul
- c'est vérifier leur format, valider leur valeur
Rendre obligatoire un champs est
du domaine métier
pas du domaine du référentiel
Exemples
Applifarm
- Tiers, Animaux, Contrats, Formulaires,...
Tactilia
- Tiers, Animations, Formulaires, Tablettes,...
Le référentiel Tiers est un must-have
cf. RGPD
Fonction
Rôle
- Réaliser une ou des fonctions
- Gère les droits d'accès aux fonctions
Exemples
- Envoyer un SMS
appeler l'API du brocker de SMS - Fusionner des données
données + modèle => pdf - Effectuer un virement
appeler l'API de la banque - ...
Intermédiateur
Rôle
- S'insérer entre deux services aux formats incompatibles
- Convertir des données d'un format vers un autres
Exemples
- conversion d'un format de tiers
- au format adullact
- au format VCard
- ...
Orchestrateur
Rôles
- Composer une fonction complexe en appelant les autres services
- Réaliser le séquencement entre les services
Exemples
- Des fonctions métier complexes
Remontée et traitement de données - ...
Remarques sur
les types
et la conception
Typologie des services
Différentes types de services
- référentiels
- fonctions
- intermédiateur
- orchestre/chorégraphe
- ...
chacun a son rôle
- si plusieurs rôles dans un même service

Choses communes
La plupart des services ont en commun
- l'exposition des informations et status
- le contrôle d'accès
- les webhooks
- le multi-tenant & configurations
- la gestion des ressources
Multi-tenant & Configuration
Multi-tenant
- partager un même service entre
- plusieurs locataires
- plusieurs utilisations
- tenant ≠ client
Configuration
Plusieurs parties :
- paramètres globaux du service
- paramètres associés à chaque tenant
Mise à jour de
configuration
- A froid
Par fichier de configuration
nécessite un redémarrage - A chaud
Par API
peut se faire à chaud
Configuration par API
plusieurs sous-parties
- paramètres globaux du service accessibles à l'administrateur
- associés à chaque tenant
- paramètres accessibles à l'administrateur (privés)
- paramètres accessibles au manager (publics)
Informations
& Status
Informations
- liens de découverte
- liste des rôles
- version
- Swagger/OpenAPI
- license
Status
- état du service
- états des dépendances
Contrôle d'accès
Distinguer les rôles
Rôles ≠ Groupes
Groupe
Le groupe dont on fait parti, c'est lié à :
- l'organigramme
- la hiérarchie
- les unités
- ...
exemples :
- marketing, stagiaires, permanents, développeur, rh,...
Un utilisateur peut faire parti de plusieurs groupes
Rôle
Le rôle que l'on a vis-à-vis du service, dépend de ce qu'on a le droit de faire :
- administrateur : gère l'ensemble du service
- manager : gère un tenant du service
- utilisateur : utilise le service
Les rôles peuvent être déclinés en sous-rôles pour plus de finesse
- rédacteur, contrôleur,...
Exemple
On a un utilisateur chez un intégrateur de services
- il a accès à trois plateformes/tenants
- test/* : celle de test pour vendre
- prod/client : celle de son client qu'il est en train d'intégrer
- prod/lui-même : celle qu'il utilise pour gérer ses projets
- ses accès sont respectivement :
- administrateur : il doit pouvoir faire ce qu'il veut
- manager : il doit pouvoir modifier le tenant de son client
- utilisateur : il est simple utilisateur de son propre tenant
Pourtant c'est le même utilisateur faisant parti des mêmes groupes
Group/Role mapping
- Pour connaître les droits d'un utilisateur il faut déterminer ces rôles à partir de ses groupes
- C'est le rôle du dictionnaire groupe/rôle qui à chaque groupe associée des rôles
- Ce dictionnaire peut être spécifique à chaque tenant
tenant
group/role
groups
roles
requête
utilisateur
Le problème de l'initalisation
- global/pas de tenant => il faut qu'un administrateur initialise le groupRoleMapping général pour l'administrateur => 💀
=> il faut un compte initial dans la config
supprimé par la suite
- un tenant est créé => le groupRoleMapping de ce tenant est vide => le manager n'a pas accès et ne peut pas mettre le mapping à jour => 💀
=> l'administrateur doit ajouter un groupe pour le manager, ensuite le manager peut gérer le mapping de son tenant

Attention aux droits
💀
le manager ne doit pas pouvoir ajouter le rôle administrateur dans le mapping de son tenant
sinon il peut augmenter ses propres droits
Basic auth
username + password
- ne contient pas d'authentification intrinsèque
=> il faut authentifier l'utilisateur avec son identifiant et son mot de passe - ne contient pas de payload
=> il faut recherche les groupes associés à l'utilisateur
=> gérer une liste interne contenant les utilisateurs autorisés et définir pour chaque utilisateur la liste des groupes dont il fait parti (ou faire appel à un service tiers)
Utile pour
- les tests
- l'initialisation (temporairement)
JWT
Token self content avec authentification & payload
- on sait que l'utilisateur a été authentifié par l'émetteur du token
-
self content peut donc contenir toute l'information nécessaire
- groupes par tenant
- id de l'utilisateur
Droits positif/négatif
-
droit positif
tout le monde a le droit sauf ... - droit négatif
personne n'a le droit sauf ...

Toujours utiliser un droit de même type
Ne jamais mixer les deux types sur une même ressource
Webhooks
Webhooks
- ce sont les messages du service
- permettent chaîner les services
- pas de norme, mais des standards et des bonnes pratiques apparaissent
Exemple
A la création d'une tâche on veut
- faire des statistiques sur la tâche
- envoyer un sms à la personne responsable
Exemple
référentiel tâches
POST tâche
POST sms
data wharehouse
POST tâche
Numéro de téléphone !?
envoi de sms
Exemple
référentiel tâches
POST tâche
formatage sms
POST tâche
data wharehouse
POST tâche
envoi de sms
POST sms
référentiel tiers
Webhook
définit par
- un déclencheur
- une opération
- création, mise à jour, suppression
-
une cible
- une ressource ou un type de ressources
- une opération
-
une action : l'appel d'un service
- opération : GET, POST,...
- une url
-
un corps
- brut, filtré, reformaté,...
Création d'un webhook
un webhook est défini
- au niveau du service ou du tenant
- statiquement ou dynamiquement
- dans la configuration
- par un appel à une API
- avec ou sans durée de vie
Exemple de configuration
module tiers MGDIS
"webhooks": [
{
"topic": "POST+*/tiers",
"callback": "/document-collect/stnazaire/root/tiers?cmisaction=createFolder&propertyId[0]=cmis:name&propertyValue[0]={reference}&propertyId[1]=cmis:objectTypeId&propertyValue[1]=cmis:folder&succinct=true",
"method": "POST",
"options": {
"withoutBody": true
}
},
{
"topic": "POST+*/tiers",
"callback": "/request/api/stnazaire/collections/tiers/{reference}",
"method": "PUT",
"headers": {
"Authorization": "Basic YWRtaW46QzdOYVdWMzlwM1M4R0hFd2RTTjNIZ1lwVzFXMGVtS1E="
}
},
{
"topic": "POST+*/tiers",
"callback": "https://wwx2.mairie-saintnazaire.fr/BlueAccess/application/referentiel_association_TEST/modules/webhook/index.php?reftiers={reference}",
"method": "PUT"
},
]Conseils d'implémentation
- Limiter les données
- Gérer la quantité
- Gérer les erreurs
- Sécuriser les requêtes
Serveur
- Répondre rapidement
- Répondre correctement
- Sécuriser les requêtes
Client
Limiter les données
- Les données transmises ne doivent pas être trop volumineuses
- Si trop grosse (une vidéo par exemple) fournir l'url d'accès à la ressource au lieu de la ressource elle même
Serveur
Gérer la quantité
- Si beaucoup d'appels à chaque seconde
- Limiter le nombre d'appels par seconde
- Regrouper les événements par lots
Serveur
Gérer les erreurs
- Mettre un timeout pour arrêter un appel durant trop longtemps
- Réessayer si pas de réponse ou une erreur
- Mettre en place une stratégie de pause exponentielle entre les tentatives
- Si pas de réponse, mettre en blacklist
- Si un événement pas délivré le réorienter en lettre morte (dead letter queue)
- Être capable de rejouer des événements
Serveur
Sécuriser les requêtes
- Signer les requêtes avec un secret
- Identifier les requêtes de manière unique
- Permettre l'utilisation d'authentification
(Authorization JWT) - Pouvoir faire les requêtes en https
Serveur
Sécuriser les requêtes
- Vérifier la signature si les données sont signées
- Faire une whitelist pour les adresses ip des appelants
- Mettre une authentification robuste
(Authorization JWT) - Pouvoir faire les requêtes en https
Client
Répondre rapidement
- Si traitement long
- Accuser réception avec un ack
- Différer le traitement en asynchrone (via une queue par exemple)
Client
Répondre correctement
- Répondre avec 2xx
- Si l'événement est reçu plusieurs fois le traitement doit être idempotent
Client
Ressources/objets
Les schémas
Ils sont obligatoires pour :
-
la validation de l'API
- définition (OpenAPI/swagger)
- requête
- réponse
- la gestion du format de la persistance
Persistance
Information importante
- L'objet manipulé par
- l'ihm (reçu par le navigateur via l'API)
- le serveur (pour préparer sa réponse)
- la base de données (pour les stocker)
NE SONT PAS (forcément/souvent) LES MÊMES
Deux façons de faire
-
Snapshot
-
Incrémentale
Snapshot
On ne garde que le dernier état de la ressource
- simple
- la ressource est accessible immédiatement
- pas d'historique
- permet la recherche par champs
Incrémentale
On stocke toutes les modifications réalisées sur la ressource
- complet : qui, quoi, quand
- besoin de reconstituer la ressource
- permet de retracer l'historique
- ne permet pas la recherche
On peut combiner
- La sauvegarde incrémentale sert de référence
garanti d'exaustivité - Les snapshot sert de cache
garanti d'accès rapide
Référentiel
Un référentiel doit gérer l'historique des ressources qu'il gère
=>
Utilisation de la sauvegarde incrémentale obligatoire
Fonctions & orchestre
Fonctions
- Simples (pas d'état)
- intermédiateurs
- Complexes (avec état)
- fonctionnalités métier
- orchestration
Simples
Intermédiateurs
- pas de stockage d'information
- fonction pure
- idempotence
- donc service simplifié
- facilement remplaçable
- authentification simplifiée (voir inutile)
- utilisation d'EIP => Apache Camel
- container obligatoire
Complexes
Métier ou orchestrateur
- éventuellement du stockage d'information
- pas fonction pure
- pas d'idempotence
- donc service plus classique
- authentification complète
(mais rôles souvent moins nombreux) - pour les orchestrateur => EIP / BPM
(Apache Camel / Bonita) - pour les autres => comme un service référentiel
- authentification complète
Apache Camel
Basé sur les Entreprise Integration Pattern
(C'est à l'intégration ce que sont les Design Patterns à la POO)


Migration
Du monolithe
aux services
en trois étapes
- factoriser/modulariser
- créer des api
- faire des services
Découpage
première étape
- factoriser/modulariser le code existant
- limiter les dépendances
API
deuxième étape
- créer des api
- faire des tests unitaires dessus
- utiliser les API
Tests
Migration
troisième étape
- faire des services
- extraire le code
Tests
D'une base à une autre
- dissocier les bases de données en trois étapes
- la troisième vous étonnera
Dissocier lecture et écriture
première étape
- utiliser l'api pour l'écriture
Dissocier les données
deuxième étape
- récrire le service
- utiliser une autre base
Environnement
Déploiement
Containers rules the world
-
pour les containers
- Docker s'impose
- pour la composition de containers
- Docker Compose
- pour le cluster
- Docker Swarm ↘
- Kubernetes (k8s) ↗


Atelier logiciel
- Automatiser du développement au déploiement
- Utiliser les outils nécessaires
- organisation : redmine, jira, trello,...
- automatisation : jenkins
- qualité : sonarqube, linters,...
- tests unitaires
- tests d'intégration
- bug tracker : mantis, redmine, jira,...


Log
Monitorer
- Sans log impossible de suivre le fonctionnement, l'état de santé des nombreux containers
- Outiller les logs : ELK (ElasticSearch Logstash Kibana)
Exemple
Cas d'école
- Des tiers
- Des documents
- Des tâches
Cas d'école
- Des tiers
- physique ou moraux
- format adullact (administrations publiques)
- Des documents
- existe déjà
- la norme CMIS (Alfresco, MS Sharepoint, IBM FileNet,...)
- Des tâches
- format VCalendar/VTODO
Conclusion
Prendre la solution adaptée


ESIR 2020 MicroServices
By Benoît Chanclou
ESIR 2020 MicroServices
Cours ESIR 2020
- 683