Retour d'expérience sur la conception d'un système distribué en start-up

Les API et micro-services ne sont pas que des termes à la mode. Ce sont des techniques et des architectures très utiles pour construire des produits vraiment performants.

Nous partageons avec vous notre retour d'expérience sur ce type d'architecture.

Un système distribué est une architecture technique privilégiant la mise en place de plusieurs petits services plutôt qu'un service dit monolithique. Cette approche apporte plusieurs avantages comme l'augmentation des performances et de la scalabilité technique tout en favorisant une diminution de la dette technique.. Cependant le coût de coordination entre les différentes briques technologiques peut rapidement augmenter si on y prend pas garde.

Les différents noeuds et services du système peuvent, par leur conception, permettre une concurrence native. Chaque composant est indépendant et donc nativement résistant face aux pannes. Ceci facilite la mise à l'échelle.

Première leçon: ne pas trop cacher le fonctionnement interne des composants

Ne pas camoufler la nature distribuée des composants derrière une abstraction logique nous semble une bonne pratique sur le long terme. Sur certaines parties du code nous avions fait le choix d'implémenter une logique "neutre" sur la base d'interfaces écrites en Golang.

Ceci permettait de ne pas embarquer certaines contraintes techniques propres à l'implémentation de différentes logiques. Pour faire simple, les composants logiciels discutaient entres eux sans connaitre totalement le fonctionnement d'autres composants. Ceci peut paraitre constructif au premier abord, pouvant faciliter la maintenance et l'interopérabilité générale du système mais malheureusement cette pratique impose avec le temps un gymnastique qui pousse les développeurs à s'occuper de problèmes non métier qui n'importent pas de valeur business. Par exemple, lorsqu'un composant expose un fonctionnement asynchrone (ou synchrone), même s'il possède plusieurs implémentations il ne faut pas cacher ceci aux autres composants. Notamment dans l'appels de méthodes.

Des services et riens que des services

Les éléments qui composent le système distribué doivent être considérés comme des services. Ils doivent exposer un "contrat d'utilisation" clair. Ils doivent être documentés, posséder un lead-developper clairement impliqué et un cycle de vie qui leur est propre. Il doit s'agir de véritable sous-projets.

Concevoir ce genre de service nécessite de raisonner avec un prise de hauteur sur la valeur business apporté et non sur les détails techniques d'implémentation. On se retrouve alors avec moins de lignes de code à gérer. Ils deviennent plus facile à comprendre. Chaque service est indépendant par nature des autres. Ils sont plus facilement mockables lors de l'écriture des tests. Concevoir de cette façon permet à l'équipe technique d'identifier plus facilement les parties défaillantes d'un système.

Communication asynchrone

Il faut faire en sorte que les services fonctionnent de manière non bloquante. Chaque service doit avoir sa propre queue de message. Même si les traitements sont très rapides, il faut privilégier les messages asynchrones. A moins que l'approche synchrone apporte une valeur business notable, notamment en terme de performance.

L'avantage de cette approche asynchrone permet de rendre scalable des services et des points noirs de l'architecture. En général, il suffit de multiplier le nombre d'instances pour augmenter les performances. Chaque noeuds est concrètement isolé, sa file de messages aussi. En cas de blocage, les messages sont conservés pour traitement. Pour gérer ceci il est souvent nécessaire d'ajouter un peu de logique sur la priorité des messages et leurs échéances. Mais une fois clarifié et maitrisé ceci ne présente pas de gros soucis.

Pour faire communiquer les messages les technologies comme rabbitmq, redis et AWS/SQS facilitent la mise en oeuvre.

Toute l'information des messages échangés doit être présente dans les messages. Autrement dit un service ne doit pas savoir à qui il envoie des messages et un service ne doit pas avoir besoin de savoir quoique ce soit sur la nature d'un expéditeur. La communication par message entre différents composants du système permet de faciliter la monté en charge et de repartir les requêtes en fonction de l'état des services.

Supervision

La supervision est une pratique fondamentale dans la conception de systèmes distribués.

Chaque service doit pousser régulièrement sont lot de métriques dans un système de supervision. Les points d'étranglement et incohérences logiques permettent de prioriser les évolutions logicielle ainsi que la maintenance sur la roadmap du produit.

Pour s'assurer de la cohérence de fonctionnement de service il est possible d'envoyer directement en production des messages particuliers et régulièrement afin de vérifier l'intégrité des réponses puis de vérifier qu'ils retournent les informations attendues. Centraliser les logs aide à faire des diagnostics efficaces.

LittleBlueFox.io est la cyber-solution qui a un impact considérable sur la sécurité de toutes les activités: e-commerce, santé, immobilier, grands comptes, etc.

Sécurisez gratuitement