L'échec dans les systèmes distribués est normal. Les systèmes distribués ne peuvent fournir que deux des trois garanties de cohérence, de disponibilité et de tolérance au partitionnement. Selon Kevlin Henney, cela limite ce que vous pouvez savoir sur le comportement d'un système distribué. Il a donné une keynote intitulée Six Impossible Things à QCon London 2022 et à QCon Plus du 10 au 20 mai 2022.
Lorsque vous regardez un morceau de code, vous pouvez voir un flux de contrôle simple, tel qu'une séquence et un embranchement, reflété dans les constructions et l'indentation du code source. Ce qui n'est pas visible, c'est la façon dont le temps est perdu ou réorganisé dans le réseau ou le backend, a expliqué Kevlin Henney.
Parce que les pannes - routeurs, câblage, hôtes, middleware, etc. - sont normales, cela signifie que toute vision de l'état reposant sur la disponibilité permanente de tout est impossible. Kevlin Henney a donné un exemple de ce qui peut arriver :
Si un nœud tombe en panne et ne revient jamais, mais que vous devez attendre qu'il donne une réponse à l'utilisateur, l'utilisateur ne recevra jamais de réponse. L'architecte n'est pas en mesure de garantir que le nœud redeviendra disponible. Alternativement, vous donnez à l'utilisateur une réponse mise en cache, mais ce résultat peut être obsolète. Dans les deux cas, l'utilisateur ne reçoit jamais la vraie réponse.
Le théorème CAP est le principe d'incertitude de Heisenberg des systèmes distribués : cohérence, disponibilité et tolérance au partitionnement. Vous ne pouvez cependant pas avoir les trois propriétés à la fois, comme l'a expliqué Kevlin Henney :
Concernant la cohérence, les résultats renvoyés sont soit à jour et cohérents, soit une erreur est reçue. Pour la disponibilité, il n'y a pas de réponses d'erreur, mais il n'y a aucune garantie que le résultat soit à jour et cohérent. Pour la tolérance au partitionnement, cela fait référence à la capacité d'un système distribué à continuer à fonctionner en présence de parties du réseau devenant inaccessibles. Choisissez-en deux, vous ne pouvez pas tous les avoir - ou, en d'autres termes, vous ne pouvez pas tout savoir.
Les délais d'attente (timeouts) et la mise en cache jouent un rôle important dans le codage des systèmes distribués, non pas parce qu'ils sont des solutions de contournement et des ajustements d'optimisation, mais parce qu'ils sont fondamentalement nécessaires, a conclu Kevlin Henney.
InfoQ a interviewé Kevlin Henney à propos des systèmes distribués.
InfoQ : Pourquoi les gens supposent-ils que les systèmes distribués sont prévisibles ?
Kevlin Henney : les développeurs voient généralement le monde à travers leur IDE, du point de vue d'une seule machine. Par défaut, ils raisonnent sur un système à travers le prisme du code qui est immédiatement devant eux. Bien qu'ils soient consciemment conscients du réseau en tant que source d'échec, de concurrence, d'asynchronisme et de latence, leur vue à travers un hublot ne les amène pas nécessairement à prendre du recul et à apprécier ce qu'ils considèrent comme une situation - un problème dans ce cas – est en fait fondamental ; qu'elle découle de la nature du système.
Bien que les gestionnaires d'exceptions puissent reconnaître les échecs, ils ne reflètent pas leur normalité. J'ai vu plus d'une directive de codage stipuler que "les exceptions doivent être exceptionnelles". Ce conseil n'est guère plus qu'un jeu de mots - il n'est ni utile ni réaliste. Il n'y a rien d'exceptionnel dans les délais d'attente, les déconnexions et autres erreurs dans un environnement en réseau - ceci est "business as usual".
Ces "petits problèmes" ne sont pas non plus des moindres : ils façonnent - en fait, ils sont - le tissu à partir duquel un système distribué est fait.
InfoQ : Comment pouvons-nous gérer l'incertitude qui accompagne les systèmes distribués ?
Kevlin Henney : Tout d'abord, reconnaissez que l'incertitude existe. Deuxièmement, reconnaissez que l'échec et les informations incomplètes sont une situation normale et non exceptionnelle. Troisièmement, décidez quelle qualité de données est appropriée pour l'application.
Les limites de la certitude et de la connaissance signifient que les architectes doivent reconnaître que la cohérence des états est une décision fondamentale et non un détail de mise en œuvre. Que les données soient cohérentes à terme ou transactionnelles de manière synchrone façonnent le code, l'expérience utilisateur et de nombreuses autres qualités d'un système. Si un utilisateur effectue une modification, cette modification est-elle immédiatement et nécessairement visible pour les autres utilisateurs ? La réponse à cette question peut modifier l'architecture. Être trop strict sur la qualité des données va à l'encontre du théorème CAP ou aura des conséquences malheureuses sur les performances, comme le verrouillage distribué.
Ces contraintes de distribution expliquent pourquoi, par exemple, les mécanismes de récupération de mémoire distribués, tels que le RMI de Java, sont probabilistes dans leur détermination de savoir si un objet n'est plus nécessaire et peut donc être collecté. Dans un processus unique dans un langage managé, il est possible de déterminer si un objet est référencé ou non comme une déclaration de fait ; dans un système distribué, ce n'est pas le cas. Un mécanisme de location basé sur les délais d'attente est utilisé pour déterminer s'il est probable qu'un objet soit toujours référencé ou non par des processus distants. Mais cela ne garantit pas que la détermination est réellement correcte, juste probablement correcte.