Comment Netflix Microservices gère les données Pub-Sub

La traduction de l'article a été préparée spécialement pour les étudiants du cours «High Load Architect» .





Présentation


Dans l'architecture de microservice Netflix, le transfert d'ensembles de données d'un à plusieurs points de terminaison peut être extrêmement difficile. Ces ensembles de données peuvent contenir tout, d'une configuration de service aux résultats du traitement par lots. Pour optimiser l'accès, une base de données résidente est souvent nécessaire et les modifications doivent être envoyées immédiatement après la mise à jour des données.

Un exemple qui reflète le besoin de distribution distribuée d'un ensemble de données ressemble à ceci: à tout moment, Netflix effectue un grand nombre de tests A / B. Ces tests couvrent plusieurs services et commandes, et les opérateurs de test devraient pouvoir se reconfigurer à la volée. Cela nécessite également la capacité de détecter les nœuds qui n'ont pas pu obtenir la dernière configuration de test et la possibilité de revenir aux anciennes versions en cas de problème.

Un autre exemple d'un ensemble de données qui doit être distribué est la séquence de sortie d'un modèle d'apprentissage automatique: les résultats de son travail peuvent être utilisés par plusieurs équipes, mais les équipes ML ne sont pas nécessairement intéressées à soutenir des services d'accès ininterrompus dans une situation critique. Au lieu de la situation où chaque équipe doit créer des sauvegardes afin de pouvoir revenir en arrière de manière succincte, une attention particulière est accordée pour garantir que plusieurs équipes peuvent utiliser les résultats d'une seule équipe.

Sans assistance au niveau de l'infrastructure, chaque équipe essaie finalement de mettre en œuvre sa propre solution, mais cela se fait avec différentes équipes avec un succès variable. Les ensembles de données eux-mêmes sont de tailles différentes, de quelques octets à quelques gigaoctets. Il est important de créer la capacité de surveiller les performances des processus et de détecter les dysfonctionnements à l'aide d'outils spéciaux afin que les opérateurs puissent rapidement apporter des modifications sans avoir à créer leur propre solution.


Diffusion des données

Chez Netflix, nous utilisons un système de données pub / sub interne appelé Gutenberg. Gutenberg vous permet de distribuer des ensembles de données avec gestion des versions - les destinataires s'abonnent aux données et reçoivent leurs dernières versions lors de leur publication. Chaque version de l'ensemble de données reste inchangée et contient une représentation complète des données, c'est-à-dire qu'il n'y a aucune dépendance par rapport aux versions précédentes. Gutenberg vous permet d'afficher d'anciennes versions de données au cas où vous auriez besoin, par exemple, de déboguer, de résoudre rapidement un problème de données ou de recycler un modèle d'apprentissage automatique. Dans cet article, nous parlerons de l'architecture de haut niveau de Gutenberg.

Modèle de données



1 sujet -> plusieurs versions

Le design de haut niveau de Gutenberg est le thème. L'éditeur publie des données dans le sujet et les destinataires en extraient. La publication dans le sujet est ajoutée en tant que version distincte. Celles-ci sont caractérisées par une politique de stockage spécifique qui détermine le nombre de versions, selon le cas d'utilisation. Par exemple, vous pouvez configurer un thème pour stocker 10 versions ou les versions des 10 derniers jours.

Chaque version contient des métadonnées (clés et valeurs) et un pointeur de données. Le pointeur de données peut être considéré comme des métadonnées spéciales indiquant où les données publiées sont réellement stockées. Aujourd'hui, Gutenberg prend en charge les pointeurs de données directs (si la charge utile est écrite dans la valeur du pointeur de données lui-même) et les pointeurs de données S3 (si la charge utile est stockée dans S3). Les pointeurs de données directs sont généralement utilisés lorsque les données sont petites (moins de 1 Mo), et S3 est utilisé comme stockage de sauvegarde au cas où le volume de données est important.


1 sujet -> de nombreux sets publiés

Gutenberg offre la possibilité d'envoyer une publication à un ensemble spécifique d'utilisateurs destinataires - par exemple, un ensemble peut être groupé par région, application ou cluster spécifique. Cela peut être utilisé pour contrôler la qualité des modifications de données ou pour limiter l'ensemble de données afin qu'un sous-ensemble d'applications puisse s'y abonner. Les éditeurs déterminent la zone de publication d'une version particulière des données et peuvent ajouter des zones aux données précédemment publiées. Veuillez noter que cela signifie que le concept de la dernière version des données dépend d'un domaine spécifique - les deux applications peuvent recevoir les dernières versions différentes des données en fonction de la zone de publication définie par l'éditeur. Le service Gutenberg mappe les applications destinataires aux zones de publication avant de décider quoi envoyer comme dernière version.

Cas d'utilisation


Le cas d'utilisation le plus courant pour Gutenberg est de distribuer des données de différentes tailles d'un éditeur à plusieurs destinataires. Souvent, les données sont stockées dans la mémoire du destinataire et utilisées comme «cache partagé», où elles restent toujours disponibles pendant l'exécution du code du destinataire et sont remplacées atomiquement sous le capot si nécessaire. Un grand nombre de ces cas d'utilisation peuvent être regroupés en «configurations», telles que la configuration du cache Open Connect Appliance , les ID de type d'appareil pris en charge, les métadonnées de méthode de paiement prises en charge et les configurations de test A / B. Gutenberg fournit une abstraction entre la publication et la réception de ces données, permettant aux éditeurs de parcourir librement leur application sans affecter les destinataires en aval. Dans certains cas, la publication se fait à l'aide d'une interface utilisateur gérée par Gutenberg, et les équipes n'ont pas du tout besoin de toucher leur propre application de publication.

Une autre utilisation du système Gutenberg est un référentiel de données versionnées. Ceci est utile pour les applications d'apprentissage automatique où les équipes construisent et forment des modèles basés sur des données historiques, voient comment elles changent au fil du temps, puis modifient certains paramètres et réexécutent l'application. Le plus souvent dans les calculs par lots, Gutenberg est utilisé pour stocker et distribuer les résultats de ces calculs sous différentes versions d'ensembles de données. Les cas d'utilisation en ligne s'abonnent à des rubriques pour fournir des données en temps réel à partir des derniers ensembles de versions, tandis que les systèmes autonomes peuvent utiliser des données historiques des mêmes rubriques, par exemple, pour enseigner un modèle d'apprentissage automatique.

Il est important de noter que Gutenberg n'est pas conçu comme un système d'événements, il est uniquement destiné au contrôle de version et à la distribution de données. En particulier, des publications fréquentes ne signifient pas que l'abonné est tenu de recevoir chaque version. Lorsqu'il demande une mise à jour, il recevra la dernière version, même si pour le moment sa version actuelle est loin derrière la version actuelle. Les systèmes de pub-sub ou d'événement traditionnels conviennent mieux aux petits messages qui sont envoyés séquentiellement. Autrement dit, les destinataires peuvent créer une idée de l'ensemble des données en consommant l'intégralité (compressée) du flux d'événements. Cependant, Gutenberg est destiné à publier et à utiliser une représentation complète et immuable d'un ensemble de données.

Développement et architecture


Gutenberg se compose d'un service gRPC et d'une API REST, ainsi que d'une bibliothèque client Java qui utilise l'API gRPC.


Architecture de haut niveau

Client


La bibliothèque cliente Gutenberg gère des tâches telles que la gestion d'un abonnement, le chargement / déchargement S3, les métriques Atlas et les paramètres qui peuvent être configurés à l'aide des propriétés Archaius . Elle interagit avec le service Gutenberg via gRPC, en utilisant Eureka pour découvrir les services.

Publication


Les éditeurs utilisent généralement des API de haut niveau pour publier des chaînes, des fichiers et des tableaux d'octets. Selon la taille des données, elles peuvent être publiées en tant que pointeur direct sur les données ou téléchargées sur S3, puis publiées en tant que pointeur de données S3. Le client peut télécharger la charge utile vers S3 au nom de l'éditeur ou publier uniquement les métadonnées de charge utile déjà présentes dans S3.

Les pointeurs de données directs sont automatiquement répliqués globalement. Les données publiées dans S3 sont, par défaut, téléchargées par l'éditeur dans plusieurs domaines, bien que cela puisse également être personnalisé.

Gestion des abonnements


La bibliothèque cliente fournit la gestion des abonnements des destinataires. Cela permet aux utilisateurs de créer des abonnements pour certains sujets à partir desquels la bibliothèque extrait des données (par exemple, de S3) afin de les transférer vers le destinataire défini par l'utilisateur. Les abonnements fonctionnent selon le modèle d'enquête - ils demandent une nouvelle mise à jour au service toutes les 30 secondes, en envoyant la version qu'ils ont reçue en dernier. Les clients abonnés n'utiliseront pas une version plus ancienne des données que celle dont ils disposent actuellement si elle n'est pas corrigée (voir «tolérance aux pannes» ci-dessous). La logique de demande répétée est câblée et configurable. Par exemple, les utilisateurs peuvent configurer Gutenberg pour utiliser des versions plus anciennes des données si le processus de téléchargement est interrompu ou pour traiter la dernière version des données au démarrage, le plus souvent afin de travailler avec des modifications de données incompatibles avec les commentaires. Gutenberg fournit également un abonnement préconfiguré qui stocke les dernières données et sous le capot les met à jour atomiquement lorsque les changements arrivent. Cela répond à la plupart des cas d'utilisation d'abonnement où les abonnés ne se soucient que de la valeur actuelle à un moment donné, ce qui permet aux utilisateurs de spécifier une valeur par défaut, par exemple, pour un sujet qui n'a jamais été publié auparavant (par exemple, si le thème est utilisé pour la configuration), ou s'il y a une erreur selon le sujet (pour éviter de bloquer le lancement du service quand il y a une valeur par défaut valide).

API du destinataire


Gutenberg fournit également des API clientes de haut niveau, qui sous le capot ont des API gRPC de bas niveau et offrent des fonctionnalités supplémentaires et la transparence de l'exécution des requêtes. Un exemple est le téléchargement de données pour un thème et une version spécifiques, qui sont largement utilisés par les composants connectés à Netflix Hollow . Un autre exemple est la réception de la dernière version d'un sujet à un certain moment - un cas d'utilisation courant pour le débogage ou l'enseignement de modèles d'apprentissage automatique.

Durabilité et "transparence" du client


Gutenberg a été conçu dans le but de permettre aux services destinataires de démarrer avec succès, plutôt que de garantir qu'ils commencent avec les données les plus récentes. Pour cette raison, la bibliothèque cliente a été construite avec une logique de sauvegarde pour gérer les états lorsqu'elle ne peut pas interagir avec le service Gutenberg. Si les requêtes HTTP échouent, le client charge le cache de métadonnées de sauvegarde de la rubrique publiée à partir de S3 et travaille avec lui. Ce cache contient toutes les informations permettant de décider d'appliquer ou non la mise à jour et de récupérer les données (à partir des métadonnées de publication elles-mêmes ou de S3). Cela permet aux clients de récupérer des données (qui sont potentiellement obsolètes, selon l'état actuel du cache de sauvegarde) sans utiliser le service.

L'un des avantages de fournir une bibliothèque cliente est la possibilité d'obtenir des métriques qui peuvent être utilisées pour signaler des problèmes d'infrastructure en général et des erreurs dans des applications spécifiques. Aujourd'hui, ces mesures sont utilisées par l'équipe de Gutenberg pour surveiller notre distribution SLI des publications et des alertes en cas de problèmes typiques. Certains clients utilisent également ces mesures pour signaler des erreurs spécifiques à l'application, par exemple, des échecs de publication individuels ou un refus de sujet particulier.

Serveur


Gutenberg est une application Governator / Tomcat qui fournit des points de terminaison gRPC et REST. Il utilise le cluster Cassandra répliqué à l'échelle mondiale pour stocker et distribuer les métadonnées de publication dans chaque région. Les instances qui traitent les demandes des destinataires sont mises à l'échelle séparément des instances qui traitent les demandes de publication. Il y a environ 1 000 fois plus de demandes de publication que de demandes de publication. De plus, cela vous permet de supprimer la dépendance du fait de la publication à la réception, de sorte qu'une augmentation soudaine des publications n'affectera pas la réception, et vice versa.

Chaque instance du cluster de demandes de destinataires traite son propre cache en mémoire des publications récentes, en le retirant de Cassandra toutes les quelques secondes. Cela est nécessaire pour traiter un grand nombre de demandes de réception provenant de clients signés sans transférer de trafic vers le cluster Cassandra. De plus, les caches avec un petit pool de requêtes ttl protègent contre les pics de requête qui pourraient potentiellement ralentir Cassandra à un point tel qu'il affecte toute la région. Nous avons eu des situations où des erreurs soudaines coïncidant avec la redistribution de grands clusters ont provoqué des interruptions du service Gutenberg. De plus, nous utilisons le limiteur de concurrence adaptatif trouvé dans l'application d'origine pour supprimer les applications avec un comportement incorrect sans affecter les autres.

Dans les cas où les données sont publiées dans S3 dans plusieurs régions, le serveur décide quel segment renvoyer au client pour téléchargement, en fonction de l'emplacement du client. Il permet également au service de fournir au client un segment dans la région «la plus proche» ou de forcer le client à se déplacer vers une autre région si la région actuelle est déconnectée pour une raison ou une autre.

Avant de renvoyer les données d'abonnement aux destinataires, Gutenberg vérifie d'abord la cohérence des données. Si la vérification échoue et que l'abonné a déjà reçu des données, le service ne renvoie rien, ce qui signifie en fait que la mise à jour n'est pas disponible. Si le client abonné n'a pas encore reçu de données (cela signifie généralement qu'il vient de démarrer), le service demande l'historique du sujet et renvoie la dernière valeur qui réussit le contrôle de cohérence. Cela est dû au fait que nous observons des retards épisodiques dans la réplication au niveau de Cassandra, où au moment où les abonnés demandent de nouvelles données, les métadonnées associées à la dernière version publiée n'étaient que partiellement répliquées. Cela peut amener le client à recevoir des données incomplètes, ce qui entraînera alors des erreurs de demande de données ou des erreurs dans la logique métier. La réalisation de ces vérifications de cohérence sur le serveur protège les destinataires des alertes de cohérence possibles qui accompagnent le choix d'un service d'entrepôt de données.

La capacité de surveiller les publications de sujets et de sites qui utilisent ces sujets est une fonction importante pour l'audit et la collecte d'informations sur l'utilisation. Pour collecter ces données, le service intercepte les demandes des éditeurs et des destinataires (les deux demandes de mise à jour des données des abonnés et des autres) et les indexe dans Elasticsearch à l'aide du pipeline de données Keystone . Nous avons donc la possibilité d'obtenir des données pour le suivi des sujets qui sont utilisés et qui ne sont plus là. Nous publions des liens détaillés vers le tableau de bord Kibana à partir de l'interface utilisateur interne afin que les propriétaires de thèmes puissent gérer indépendamment leurs abonnés.

Outre les clusters qui gèrent les demandes des éditeurs et des destinataires, le service Gutenberg lance un autre cluster qui traite les demandes périodiques. En particulier, il résout deux problèmes:

  1. Toutes les quelques minutes, toutes les dernières publications et métadonnées sont collectées et envoyées à S3. Cela lance le démarrage du cache de sauvegarde, qui est utilisé par le client, comme décrit ci-dessus.
  2. Le garbage collector supprime les versions des rubriques qui ne répondent pas à leurs politiques de rétention. Il supprime également les données qui lui sont associées (par exemple, les objets S3) et contribue à garantir un cycle de vie des données bien défini.

Tolérance aux pannes


Snap


Les déploiements infructueux se produisent dans le monde du développement d'applications, et les restaurations aux versions antérieures sont une stratégie courante pour résoudre de tels problèmes. L'architecture pilotée par les données complique la situation, car le comportement est déterminé par des données qui évoluent avec le temps.

Les données distribuées par Gutenberg influencent et dans de nombreux cas contrôlent le comportement du système. Cela signifie qu'en cas de problème, vous avez besoin d'un moyen de revenir à une bonne version éprouvée des données. Pour atténuer la situation, Gutenberg permet de "lier" le thème à une version spécifique. Les broches remplacent la dernière version des données et forcent le client à mettre à niveau vers cette version, ce qui vous permet de résoudre rapidement une situation critique, plutôt que d'essayer de comprendre comment publier la dernière version de travail. Vous pouvez même appliquer une liaison à la zone de publication afin que seuls les destinataires de cette zone puissent utiliser les données. Les broches remplacent également les données publiées lors de la liaison active, mais lorsque la broche est supprimée, les clients recevront la dernière version, qui peut être la dernière version épinglée ou une nouvelle version publiée alors que l'ancienne était épinglée.

Déploiement séquentiel


Lors du déploiement d'un nouveau code, il est souvent recommandé de créer de nouveaux assemblys avec un sous-ensemble de trafic, de les déployer progressivement ou de réduire d'une autre manière les risques de déploiement en le ralentissant. , , .

, Gutenberg, — Spinnaker . , . , . , , , , , . , AWS- .


Gutenberg Netflix . Gutenberg , 6 . – , 1-2 , 12 .

24- , , . , 200, 7. - , , Hollow. , , , – 60, – 4.


, Gutenberg:

  • : Gutenberg Java-, Node.JS Python-. , REST API Gutenberg . , Node.JS Python.
  • : Gutenberg . Gutenberg.
  • : , . , .
  • : , Gutenberg, Gutenberg . , .
  • : , , . , Elasticsearch.
  • : Netflix – . , Gutenberg , .

C’est tout. .

Source: https://habr.com/ru/post/fr479572/


All Articles