Emily Reinhold, ingénieur chez Uber, décrit dans un récent billet de blog comment ils ont décomposé une API monolithique en une architecture modulaire et flexible de microservice. Elle met en évidence quelques choix stratégiques de conception et d'architecture qui ont été la clé de l'effort de migration de Uber.
Reinhold écrit que la migration vers les microservices avait pour objectif de parvenir à une meilleure évolutivité sur trois points différents : la gestion du trafic croissant, l'ajout facile de nouvelles fonctionnalités et l'adoption d'une architecture qui peut s'adapter facilement à la croissance de l'organisation.
Les ingénieurs Uber ont pris quelques décisions de conception générale visant à réduire le couplage entre les microservices :
- L'adoption de MVCS, une extension de l'approche bien connue Model-View-Controller qui inclut explicitement une couche de services, qui héberge la logique de l'application. Cela a permis à Uber de découpler la logique métier de la couche de persistance, ce qui rend donc plus facile de modifier celle-ci.
- Le remplacement de PostgreSQL par UDR, l'entrepôt de données d'Uber répliqué globalement pour permettre de servir des voyages simultanément depuis plusieurs centres de données.
De même, les ingénieurs d'Uber ont pris des décisions architecturales importantes visant à faire face aux conséquences d'avoir un nombre élevé de services :
- Réseau Asynchrone : pour gérer l'augmentation du nombre de demandes de services, les ingénieurs d'Uber se sont appuyés sur Tornado, une bibliothèque Python de réseau asynchrone basé sur les boucles d'événements, qui proclame être capable de gérer des dizaines de milliers de connexions ouvertes à la fois. L'un des avantages de l'utilisation Tornado a été sa capacité à bien intégrer le code Python existant de réseau d'Uber, qui a été structuré autour d'un paradigme synchrone.
- La découverte de service et la résilience : avec l'augmentation du nombre de services, une caractéristique essentielle est de découvrir ces services et d'identifier des points de défaillance. Cela comprend la collecte des statistiques telles que les taux d'échec et les violations de SLA, la détection des hôtes qui ne sont pas en bonne santé et la coupure de circuit pour prévenir les défaillances en cascade. Uber a géré ces préoccupations en utilisant TChannel sur Hyperbahn, un protocole RPC de multiplexage et de framing de réseau qu'ils ont développé et open-sourcé.
- La définition d'interfaces strictes : Uber a choisi Thrift pour définir des interfaces de service en utilisant un IDL et pour générer des fichiers source côté client pour une variété de langages. Thrift permet de détecter tout consommateur qui tente de passer un appel qui ne se conforme pas à la définition d'interface.
Reinhold explique enfin qu'Uber maintient un environnement de production en bonne santé en appliquant trois principes :
- L'exécution des tests de charge pour identifier les goulots d'étranglement et les points de rupture
- L'utilisation de conteneurs pour utiliser plus efficacement le matériel
- La simulation d'interruption de service pour assurer que le système est capable de récupérer et d'identifier ses vulnérabilités
Emily Reinhold a également abordé ces sujets à la dernière QCon New York.