Serveur minecraft

Alibaba Container Platform Infrastructure – une approche Kubernetes – Monter un serveur MineCraft

Le 29 octobre 2019 - 39 minutes de lecture

Transcription

Guo: Quand on parle d'Alibaba, beaucoup de gens savent peut-être qu'il y a des événements Double 11, ce qui est essentiellement une spéciale chaque année, le 11 décembre. Alibaba organisera une promotion spéciale pour tous les fournisseurs, à l'instar du Black Friday aux États-Unis. En 2018, pour un jour, le total des ventes en ligne était d'environ 13 milliards de dollars. À titre de comparaison, la vente de Thanksgiving en Amérique du Nord en 2018 s'élevait à environ 3,7 milliards de dollars. En gros, cela représente environ neuf fois le revenu d’une entreprise et en une journée.

Beaucoup de gens pensent que c'est un miracle, y compris moi, et je pense que c'est probablement la plus grande collaboration commerciale et technologique au monde. Pour prendre en charge cet événement, l'infrastructure Alibaba multiplie par dix la capacité normale d'un ordinateur, atteignant environ 10 millions de capacités principales, et le sous-système de stockage est conçu pour prendre en charge environ un million d'opérations IOPS parallèles. Notre équipe infra doit gérer plus d'un million de conteneurs pour exécuter plus de 10 000 applications. En d'autres termes, cet événement Double 11 est bien une campagne pour les équipes d'infrastructure.

Je m'appelle Fei Guo, je suis un ingénieur en chef de Alibaba Cloud. Je travaille sur l'équipe de la plate-forme de conteneur cloud, qui est l'équipe principale qui a pris en charge les événements Double 11 que j'ai mentionnés. Mon travail actuel porte sur l'évolutivité et la construction d'une solution de service utilisant Kubernetes. Je dirige également plusieurs projets open-source sur l'automatisation de la charge de travail et la multi-location dans Kubernetes.

Voici les grandes lignes de la conversation d'aujourd'hui. Je vais d'abord parler de la façon dont Alibaba se dirige vers Kubernetes et de l'innovation en matière d'architecture. Avant de parler des détails, je vais énumérer plusieurs défis auxquels nous avons été confrontés au cours de l’intégration, et quelques solutions pour les surmonter, y compris des contrôleurs – en passant, ils sont tous à source ouverte -, un interne. planificateur, pourquoi nous l’avons construit et comment nous l’avons construit, et un système spécial de colocation, qui est essentiellement un système qui peut nous permettre de mélanger les travaux en ligne et les travaux hors connexion afin d’obtenir une utilisation coûteuse des ressources. Après avoir évoqué certaines des contributions apportées en amont lors de l'intégration, je terminerai mon travail par quelques leçons que j'ai apprises au cours du processus.

Des principes

Avant de parler de l'architecture de la plate-forme de conteneur Alibaba, je voudrais revenir un peu en arrière pour discuter de certains principes de conception d'infrastructure de concepteur. Je pense que beaucoup de personnes présentes dans cette salle sont des experts en infrastructure. Vous pouvez venir ici de startups, d'entreprises de taille Web telles que Google ou Facebook, ou de fournisseurs de cloud, tels qu'AWS. Voyons si nous pouvons arriver à des accords sur ce sujet. À mon avis, l'infrastructure peut se concentrer sur quatre domaines, en fonction de vos besoins. Le premier est l'utilisation, puis la stabilité, la standardisation et le DevOps.

Pour les startups, car elles fonctionnent très rapidement et l'application itère très rapidement, il est très important que l'infrastructure puisse fournir des flux de travail pratiques pour DevOps, ainsi que pour les entreprises à l'échelle Web qui sont vos propres centres de données. Étant donné que le coût de la maintenance d'un tel pool de ressources est si élevé, l'utilisation des ressources peut être la principale préoccupation. Pour les fournisseurs de cloud, il y a une légère différence, car les fournisseurs de cloud doivent fournir un contrat de niveau de service aux utilisateurs, et le non-respect de celui-ci peut parfois être catastrophique. Ensuite, la stabilité peut être la chose la plus importante. Pour certains utilisateurs de l'entreprise, si vous ne pouvez pas investir trop de ressources humaines dans l'infrastructure, la normalisation est essentielle pour limiter les coûts de maintenance de votre infrastructure.

C'est vraiment intéressant. Alibaba passe presque toutes les quatre étapes. C'était une start-up, puis une entreprise à taille humaine hébergeant de nombreuses applications à grande échelle. Récemment, nous avons lancé le processus de transfert de la totalité de la plateforme de conteneur Alibaba vers Alicloud, et nous devons fournir un contrat de niveau de service à nos utilisateurs. Sur la carte, de plus en plus de BU d'Alibaba souhaitent utiliser notre plate-forme de conteneur pour gérer leur activité, bien qu'elles nous demandent de fournir les interfaces standard. En fin de compte, l'infrastructure d'Alibaba doit prendre en compte les quatre facteurs.

Le chemin de Kubernetes

Cela étant dit, les exigences de notre équipe remontent en réalité à 2010, où nous avions simplement attribué un pool dédié de différentes unités opérationnelles. Ils ont géré leur propre charge de travail, leurs entreprises ont connu une croissance très rapide, mais à des rythmes différents, et ils ont mis en place leurs propres ordonnanceurs. Peu de temps après, nous avons constaté que le fait d’avoir plusieurs petites piscines constituait un gaspillage important pour la ressource à mesure que l’échelle augmentait. En 2012, nous avons commencé à utiliser un cluster centralisé, appelé Sigma. nous utilisons le nom de code Sigma pour combiner toutes les petites grappes en une grande, en utilisant un planificateur unifié. L'objectif principal est que vous utilisiez un seul système pour mélanger tous les travaux en ligne et hors ligne afin d'améliorer l'utilisation du cluster.

Il semblait bien fonctionner jusqu'en 2018, car nous avions trouvé qu'il était si difficile d'étendre l'ancien système, car il ne supportait pas les interfaces standard. Lorsque nous avons commencé à penser à utiliser une solution à source ouverte, et que Kubernetes est devenu un choix, le danger était grand, car son écosystème était très vaste. Il prend en charge les API standard et l'architecture complète est très extensible, ce qui peut nous aider à réaliser la stabilité et les exigences d'utilisation de notre système. Nous avons déjà quelques clusters Kubernetes à grande échelle en production.

Dans cette figure, je vous donne un aperçu de haut niveau de notre architecture de plate-forme de conteneur, en utilisant l'approche basée sur Kubernetes. Dans la ligne pointillée rouge, ce sont les composants Kubernetes que nous avons construits. Vous verrez des termes qui vous semblent familiers, tels que serveur API, logiciel de gestionnaire de contrôleur. Tous les blocs en dehors des lignes pointillées rouges sont tous des services internes d’Alibaba avec lesquels nous devons collaborer pour cette transition, et c’est tout à fait acceptable si vous ne les connaissez pas. Je vais expliquer. Nous devons convertir notre couche PaaS pour changer l'API afin qu'elle utilise directement l'API Kubernetes. Nous devons créer un ensemble de contrôleurs pour interagir avec les services de stockage et de mise en réseau de chaque nœud. Nous devons connecter le système existant qui utilise déjà l'API Kubernetes au nouveau système et apporter quelques modifications aux noeuds. Fondamentalement, nous modifions légèrement les cales de Kubelet et CRI. J'expliquerai plus tard pourquoi nous devons faire cela.

Nous devons créer notre propre plug-in CRI dans le plug-in CNI. Nous devons travailler avec un autre système de l’Est, le système qui exécute tous les travaux par lots d’Alibaba. Je viens de le nommer MaxCompute Master. Nous devons nous assurer que ces deux systèmes fonctionnent ensemble. C'est la raison pour laquelle nous avons introduit notre serveur API de colocation, que j'expliquerai également plus tard. Enfin, un moteur de placement hors connexion doit fonctionner avec le planificateur unifié, utilisé lors de la création d'un site pour les événements de promotion, comme les événements Double 11 déjà mentionnés.

Défis

Globalement, je voulais simplement vous mettre en évidence: la mise à niveau de l’infrastructure est en effet une tâche très compliquée. Cela peut être difficile à bien des égards. Pour nous, je pense qu'il y avait trois défis majeurs quand nous avons fait cette innovation d'infrastructure. Je me souviens de quelques gars qui ont levé la main, alors vous avez également procédé à la mise à niveau de l’infrastructure vers Kubernetes. Je parie que vous avez peut-être eu un problème similaire à celui que je mentionne maintenant. Le premier est l'évolutivité. Notre cluster a généralement 10 000 nœuds et exécute plus de 100 000 conteneurs. Presque personne ne gère Kubernetes à cette échelle. Par conséquent, nous avons peut-être rencontré un problème que personne n’a jamais rencontré auparavant.

Notre ancien système possède des fonctionnalités très critiques, mais ces fonctionnalités n'existent pas dans Kubernetes. Dans un nouveau système, nous devons fournir une parité de fonctionnalité, sinon nous ne sommes même pas autorisés à mettre à niveau l'infrastructure. La troisième partie est l'opération. Les Kubernetes ne disposent pas des outils d’exploitation standard. En pratique, de nombreuses personnes doivent donc mettre en œuvre leurs propres opérateurs pour assurer la maintenance du système. Parfois, cela peut être risqué, car le problème de la mise à niveau du système peut, dans la pratique, facilement distraire beaucoup de ressources pour résoudre tous ces problèmes.

Pour ces défis, nous avons en fait proposé quelques stratégies d'intégration pour les surmonter. Notre objectif principal est de fournir une norme pour la prise en charge de l’API de pod Kubernetes. C’est l’essentiel que nous ne pouvons pas compromettre. Sinon, la mise à niveau complète de l’infrastructure n’a aucun sens. En termes de parité des fonctionnalités, nous voulons d’abord nous assurer que lors de la mise à niveau vers le nouveau système, nous ne sacrifions pas l’utilisation, ce qui signifie que notre nouveau système doit fonctionner avec le système de colocation existant pour garantir le bon fonctionnement des travaux en ligne et hors connexion. ensemble. Nous avons tiré parti du contrôleur Kubernetes CRD standard et du plug-in de planification pour implémenter toutes les fonctionnalités que nous souhaitions implémenter afin de les étendre à Kubernetes en amont. Lorsque nous avons conçu ces nouveaux contrôleurs, les nouveaux CRD, nous avons mis l’évolutivité comme première constante de la construction des nouveaux composants.

En termes de fonctionnement, nous avons construit certains outils Internet en utilisant les données collectées auprès de Prometheus, et nous avons mis en place un système d’inspection permettant de détecter toutes sortes de problèmes ou d’erreurs se produisant dans le cluster. Enfin, nous avons essayé de rendre notre base de code native en amont, ce qui signifie que nous ne modifions aucun code de serveur API principal. Pour le Kubelet, nous apportons un minimum de changements. Le but de cette opération est que si nous souhaitons mettre à niveau la version de Kubernetes, ce processus de mise à niveau sera aussi simple que possible. C’est la stratégie que nous suivons lors de l’intégration.

Solutions

Ensuite, je vais parler des solutions que nous avons élaborées pour surmonter ces défis. Commençons par les contrôleurs. Dans notre application, la plupart de nos applications de magasinage en ligne sont des applications avec état, par conséquent, les ensembles avec état sont largement utilisés dans notre infrastructure. Le statefulset en amont a quelques problèmes. Le premier problème est que si vous souhaitez mettre à niveau l'image du pod de l'étatfulset, le contrôleur en recréera un nouveau. Si vous souhaitez mettre à niveau l'intégralité de l'étatfulset, le contrôleur procédera à la mise à niveau séquentielle du passé dans l'ordre inverse de l'index du pod. Le problème avec ce processus est qu’il peut être lent si votre ensemble avec état comporte de nombreuses pièces, ce qui peut poser problème, car dans nos déploiements, nos ensembles d’état peuvent comporter des milliers de pods, ce qui prend beaucoup de temps pour effectuer une mise à niveau. .

Nous avons amélioré les services en amont sous deux aspects. nous appelons l’un le nouveau contrôleur, nous appelons l’autre statefulsets. La première chose à faire est d’introduire ce qu’on appelle une «mise à niveau sur place», ce qui signifie que si le seul composant des images de conteneur est mis à niveau dans une spécification, le contrôleur ne recréera pas un nouveau pod. Au lieu de cela, le Kubelet ne fera que redémarrer le pod avec la nouvelle image, et le pod sera conservé. L'avantage de cette fonctionnalité est que de cette manière, les états des pods sont préservés; les états des pods, y compris l’adresse IP et toute la configuration PV, ils restent tous identiques lors de la mise à niveau et vous évitez beaucoup de replanification inutile, car vous devez toujours appeler le planificateur et consulter tous les pods de planification si vous le souhaitez. vouloir démarrer un nouveau pod. Si vous effectuez la mise à niveau sur place, vous pouvez simplement éliminer ceux-ci.

Une autre chose que nous avons trouvée, du moins dans notre cas d'utilisation, est que l'ordre de mise à niveau n'a pas d'importance. L'ordre de mise à niveau est en réalité quelque chose sur lequel l'étatful en amont insiste. Cela n'a pas d'importance pour nous. À cet égard, nous introduisons une nouvelle fonctionnalité appelée MaxUnavailable. Ce que fait cette fonctionnalité est que cet indicateur spécifie simplement quel est le nombre maximal de modules que vous pouvez effectuer lors d’une mise à niveau simultanée. Prenons, par exemple, dans ce cas, si vous dites que MaxUnavailable est égal à trois, le contrôleur mettra à niveau les trois pods en même temps. Cela peut accélérer la mise à niveau complète des pods, si l'ordre de mise à niveau n'est pas une préoccupation majeure pour les charges de travail.

Ensuite, nous utilisons des conteneurs Sidecar dans presque tous nos modules de production, mais l’amont ne fournit pas de contrôleur standard pour gérer toutes les Sidecar. Pour cette raison, nous avons construit un nouveau contrôleur appelé SidecarSet. Fondamentalement, il injecte des contrôleurs de side-car pour tous les pods basés sur le sélecteur de pods au moment de la création du pod, en utilisant le hook d'admission Web Mutate standard. Le contrôleur sidecar gérera les conteneurs sidecar à l’aide de la mise à niveau sur place. Par conséquent, si vous souhaitez mettre à niveau le sidecar [inaudible 00:15:12] image, vous n'avez pas à recréer les pods. Il sera simplement géré à l'aide des mises à niveau sur place. La gestion du cycle de vie de sidecar est indépendante de la gestion du cycle de vie de votre conteneur principal. Enfin, voyez comment il est supprimé. tous les conteneurs injectés par le side-car en seront retirés. Je pense que ce conteneur sidecar est très important pour nous aussi pour une autre fonctionnalité, dont je parlerai plus tard, qui consiste à se débarrasser du conteneur riche.

Il y a un ou deux jours, à l'occasion de la KubeCon Shanghai, nous avons officiellement annoncé la publication du projet OpenKruise, qui est essentiellement une suite d'automatisation pour la gestion de la charge de travail dans Kubernetes. Lors de la première étape, nous avons ouvert trois sources de contrôleurs, y compris le jeu de données avancé et le sidecar que j'ai déjà mentionné. Le troisième contrôleur est le broadcastjob, qui est, vous pouvez l’imaginer, tout comme une combinaison d’un démon et d’un travail. Ceci est notre première étape. Notre objectif est d'essayer d'utiliser ce projet. Nous espérons que la communauté nous enverra les exigences et les cas d'utilisation et qu'elle contribuera même dans ce domaine à compléter les Kubernetes en amont. N'hésitez pas à essayer, et s'il vous plaît nous donner quelques commentaires. J'espère que je pourrai également travailler avec vous sur ce projet.

Ensuite, je vais parler du planificateur. Notre planificateur s'exécute dans un module séparé, ce qui permet d'utiliser un mode plug-in de planificateur. Il maintient son propre cache de cluster et dispose d'une file d'attente pour mettre en file d'attente tous les modules en attente. Nous avons créé cette architecture pour plusieurs raisons. Le premier est lorsque nous avons démarré un projet, le planificateur en amont n'était pas du tout évolutif. Ça va mieux maintenant, mais à cette époque, ce n'était pas évolutif. Nous avons décidé de créer notre propre planificateur pour résoudre tous les problèmes d'évolutivité, et nous avons dû implémenter une parité de fonctionnalités fournie par notre ancien système. En utilisant des modules distincts et un plugin de planificateur, vous pouvez découpler le cycle de publication afin que la version de notre nouveau planificateur puisse être découplée de la version du serveur d'API. Enfin, si nous introduisons un bogue dans le planificateur, nous voulons au moins nous assurer que le serveur d’API ne va pas tomber en panne à cause du bogue. C'est la raison pour laquelle nous avons introduit un nouvel ordonnanceur en tant que plugin dans cet effort.

Par rapport au planificateur en amont, la plus grande différence réside dans le fait que notre planificateur est sensible à la topologie du processeur. Cela signifie que notre ancien ordonnanceur peut placer les modules sur un noyau spécifique du noeud. Ils le font parce qu'ils veulent une isolation des performances très forte, car bon nombre des charges de travail, nos charges de travail de magasinage en ligne, ont des exigences très strictes en matière de latence. Ils veulent avoir l'isolation de performance la plus élevée possible. Il s'agit d'une exigence que nous ne pouvons pas nier. Notre nouveau système doit donc offrir la même capacité. Ce que nous faisons est que nous conservons les détails sur les nœuds de notre topologie dans notre cache de planificateur. Supposons que si un pod dit simplement que je veux un noyau, et notre ordonnanceur utilisera le cache en disant que ce pod est placé dans un socket est égal à zéro avec un core. Si un autre pod a besoin de deux cœurs, le planificateur les placera dans un autre socket de ce nœud et marquera les deux cœurs occupés. Ceci est juste du côté du planificateur.

Afin de respecter la décision du planificateur dans le nœud, le planificateur écrira la décision ou le repère binaire de la CPU définit les points que les pods veulent utiliser, l'écrivons dans l'annotation du pod et les Kubletes changent légèrement pour passer le test. Annotation du pod sur la cale CRI. Ce que fait CRI-SHIM, c'est qu'après avoir lancé le processus pour s'exécuter dans les conteneurs, il va simplement appeler le noyau système de la tâche standard pour lier le processus de lignes au jeu de processeurs spécifié par le planificateur. De cette manière, nous pouvons nous assurer que le contenu des pods que nous exécutons est spécifique aux cœurs des nœuds. L'ensemble du processus semble un peu compliqué, mais en réalité, les modifications apportées à Kubelet et à l'interface CRI pour prendre en charge cette fonctionnalité sont mineures.

Ensuite, je vais parler de certains changements d’algorithmes du côté du planificateur. Du point de vue du planificateur, du moins sous Kubernetes, le planificateur est à mon avis un travail simple. Pour un pod, il suffit de choisir le nœud le mieux placé dans un pod. Le flux de travail typique est quelque chose comme ça. Ils passent par un tas de vérifications de prédicats. Les contrôles de prédicat traversent tous les nœuds du cluster et trouvent une liste des nœuds possibles. Ensuite, ils trient la liste des nœuds réalisables en fonction des priorités du centre de la matrice et trouvent le meilleur nœud pour exécuter un pod. La vérification des prédicats serait celle qui prend le plus de temps. Dans le cas où vous avez un cluster avec un nœud 10K, l'ensemble du processus peut prendre beaucoup de temps.

Une optimisation très simple consiste à écrire le tableau de nœuds dans plusieurs régions et à démarrer plusieurs threads pour effectuer les contrôles parallèles pour chaque région, puis rechercher les nœuds réalisables via le contrôle de prédicat. En fait, même si vous faites cela, si votre cluster a plus de 10 000 nœuds, même si vous faites le parallèle – car au plus, vous pouvez démarrer, par exemple, 10 à 16 threads pour effectuer la vérification des parallèles – c'est toujours lent. Une autre façon de réduire le temps est d’introduire un drapeau qui indique les nœuds possibles à rechercher. Disons que le nombre est 100. Cela signifie que la recherche parallèle s'arrête réellement. Si vous trouvez un total de 100 nœuds possibles, vous arrêtez toute la recherche parallèle. En temps normal, cela réduit efficacement la complexité de l’algorithme de l’ordre de N à l’ordre de 1. [O(N)->O(1)].

Je pense qu’en août dernier, le planificateur amont a mis en œuvre à peu près la même idée, mais elle n’était pas là quand nous avons démarré le projet. Il y avait une différence entre notre ordonnanceur et Upstream à cet égard: Upstream utilisait la sélection de nœud alternée, mais notre ordonnanceur utilise une randomisation. Ce que je veux dire en termes de randomisation, c'est que, pour chaque module avant d'effectuer les vérifications de prédiction automatique, nous utilisons shuffle pour randomiser complètement le tableau de nœuds avant d'effectuer la vérification de prédicat. L'idée d'utiliser Shuffle est que nous essayons de répartir les pods de manière uniforme de la manière la plus uniforme possible, et je pense que les mêmes idées ont été utilisées dans le planificateur de boîtes. Mais dans certains cas, nous ne le faisons pas, car si le pod a des règles d’affinité ou un nœud spécifié, nous ne faisons pas cette randomisation car cela n’aide en rien.

La prochaine fonctionnalité que nous avons introduite s'appelle la planification de groupe. L'idée est que si les deux modules ont les mêmes spécifications, ils peuvent en fait partager les mêmes nœuds possibles. Nous utilisons le hachage des étiquettes, des annotations et des spécifications de pod pour former une clé. Nous utilisons une clé pour regrouper les modules en attente dans les groupes. Ensuite, pour les pods du même groupe, nous ne faisons que la vérification des prédicats pour le premier pod. Supposons que, dans cet exemple, nous vérifions les prédicats du pod A et trouvons que celui-ci est un hôte réalisable. Après avoir placé A dans l’un des nœuds du tableau, nous utiliserons exactement le même tableau de nœuds réalisables pour le module B. À moins de règles d'affinité pour le module A, il sera placé dans un autre nœud, en fonction de notre stratégie de propagation.

De cette manière, nous pouvons gagner du temps lors de la vérification des prédicats pour le pod B. Je pense qu'en pratique, cette optimisation est très utile, car si vous utilisez workload, un état de déploiement pour gérer votre charge de travail, la plupart de vos pods sont créés par le contrôleur. , donc ils partagent les mêmes spécifications. En fait, il existe assez peu de pods qui peuvent avoir les mêmes clés et vous pouvez gagner beaucoup de temps sur la recherche d’hôte réalisable. Globalement, notre planificateur peut atteindre un débit d’environ 150 pièces par seconde dans un cluster avec une échelle, plus de 10 000 nœuds et 100 000 modules en cours d’exécution dans le système.

Ensuite, je parlerai du système de colocation que j'ai déjà mentionné. C'est la technique que nous utilisons pour essayer d'exécuter à la fois les applications en ligne et les applications hors ligne dans les nœuds simples. Actuellement, toutes nos propres applications utilisent Kubernetes, mais tous nos travaux hors connexion, tels que les travaux par lots, utilisent un autre système de planificateur, que j'appelle simplement MassCompute Master. Afin de s'assurer que ces deux systèmes fonctionnent ensemble, nous devons résoudre le conflit de deux manières. Le premier est la couche d'ordonnanceur et le second se trouve dans le nœud de la couche d'exécution. Dans la couche de planification, nous introduisons un serveur d’API dit de colocation. Il s’agit en réalité d’un serveur d’API Kubernetes agrégé. Cela fournit une API à l'utilisateur pour spécifier la quantité de ressources dans les nœuds pouvant être affectées à différents types de travaux.

Le serveur d'API de colocation a une vue complète des deux systèmes, de l'allocation de ressources. Ils peuvent donc effectuer un contrôle d'admission pour s'assurer que chaque type de travail ne dépasse pas son quota. Du côté des nœuds, nous avons un agent de colocation, qui lit le quota du serveur d’API de colocation et ajuste la hiérarchie des groupes C du nœud en conséquence, afin de s’assurer que les performances des travaux en ligne et des travaux hors connexion sont isolées. Nous utilisons également certaines fonctionnalités du système d'exploitation; nous utilisons le partitionnement du cache matériel pour nous assurer que nos applications en ligne ne sont pas affectées par les applications hors connexion [inaudible 00:26:52] prévu. Je ne vais pas parler des détails dans le discours d'aujourd'hui.

Dans l’ensemble, lorsque nous combinons à la fois l’application en ligne et les applications hors connexion, l’utilisation de la CPU des nœuds peut atteindre environ 40%. Sans cela, pour notre seul cluster d'applications en ligne, l'utilisation du processeur n'est que d'environ 15%. Il s'agit donc d'un progrès important en termes d'utilisation, ce qui est essentiel pour nous. Comme vous pouvez le constater, cette solution n’est pas la solution idéale. Cela a introduit beaucoup de complexité. Ce serait beaucoup plus agréable si nous pouvions convertir directement en MaxCompute Master en utilisant Kubernetes, car à mon avis, ce serait beaucoup, beaucoup plus facile. Mais en fait, il est très courant dans les grandes organisations informatiques comme la nôtre qu'il faille du temps pour convaincre d'autres personnes de passer à une nouvelle infrastructure. Nous devons faire des compromis pour trouver une solution afin de progresser, car nous ne pouvons nous permettre aucune perte d’utilisation pendant cette transition.

Contributions

Tout au long du processus, nous avons trouvé certains problèmes et nous avons soumis la plupart des solutions en amont. La plupart des problèmes rencontrés lors de la finalisation de la zone d'évolutivité. Par exemple, nous avons constaté qu’etcd présentait des problèmes d’accès simultané, de verrouillage et d’algorithme, ainsi que dans le grand cluster, s’il existait plus de 10 000 nœuds, la quantité de [inaudible 00:28:36] qu'ils envoient à Kubelets, c'est beaucoup. Beaucoup de nos contrôleurs utilisent [inaudible 00:28:42] et nous constatons que dans les grands groupes, le nombre d’auditeurs et d’observateurs surveillés gérés par le meilleur serveur est énorme. Le planificateur est généralement acceptable car nous avons créé le nôtre. Nous retrouvons les problèmes dans les trois autres composantes majeures en termes d’évolutivité.

J'ai répertorié ici quelques relations publiques que nous avons envoyées pour résoudre ces problèmes. Pour etcd, nous avons soumis pour résoudre le problème de verrouillage. Je veux juste souligner un changement, qui est le changement d'algorithme dans le etcd. Cette modification peut améliorer les performances de l'etcd environ 24 fois dans le scénario de données à grande échelle. Dans le serveur d'API, nous avons ajouté l'indexation pour l'opération de liste de pod. Cette optimisation a amélioré le fonctionnement de la liste de pods environ 35 fois, et la solution sera disponible très bientôt. Nous avons également ajouté la création de signets à l’opération de montre. Les performances de l'observateur s'améliorent considérablement si le serveur d'API est redémarré. Nous avons également corrigé un problème de pulsation cardiaque de Kubelet. Il est intéressant de noter que le problème de pulsations cardiaques que j'ai mentionné précédemment a été résolu ultérieurement par l'amont. Ce que nous faisons, c'est que nous sélectionnons le correctif de notre construction. Dans l’ensemble, je pense que c’est une belle histoire de travailler avec la communauté open source. Fondamentalement, nous avons contribué ensemble et nous avons profité les uns aux autres.

Leçons apprises

Ensuite, je veux parler des leçons que nous avons apprises pendant tout le processus. La première est parfois que nous devons faire de bons compromis pour compromettre les systèmes plus anciens. Dans le cas que j'ai mentionné pour le système de colocation, il est si important de trouver une solution de compromis. Mais dans d'autres cas, nous devrons peut-être insister pour demander à l'ancien système de changer. Un exemple est que nous utilisions des conteneurs dits riches dans une grande partie de notre infrastructure Alibaba. En fait, il s’agit d’un système Java monolithique. Le conteneur commence par les systemds, et il a une application, et il a l'ordre [inaudible 00:31:01] autres services dans un grand conteneur géant. Les gens travaillent généralement avec des conteneurs riches de cette manière; ils se connectent SSH au conteneur et au script principal pour démarrer l’application. Et puis un script d'arrêt pour arrêter l'application. C'est la façon dont ils exploitent le conteneur riche.

Le problème avec les conteneurs riches est qu'ils ne suivent pas la [inaudible 00:31:27] modèle de fonctionnement. Le problème est maintenant que le cycle de vie de l'application est complètement différent du cycle de vie du pod. Cela nous cause beaucoup de difficultés pour maintenir ce conteneur riche comme celui-ci. Au cours du processus, nous avons conçu pour modifier la façon dont la couche supérieure organisait les applications. Nous avons utilisé un conteneur pour exécuter des applications, puis nous avons déployé un grand nombre de conteneurs Sidecar pour combiner tous les services dans les conteneurs Sidecar, puis en utilisant les sidecarsets mentionnés précédemment pour gérer tous les sidecarsets. Nous utilisons l'API de conteneur standard pour spécifier votre script LivenessProbe, ainsi que pour spécifier le script permettant de démarrer votre application et de l'arrêter. De cette manière, la gestion du cycle de vie des pods devient beaucoup, beaucoup plus propre.

Quelques soucis. Pendant le processus, je pense que l’évolutivité peut être un problème, mais ce n’est pas un problème difficile, car la communauté Intel essaie de résoudre les problèmes d’évolutivité. En fait, l'opération et la mise à niveau peuvent être plus risquées. Par conséquent, nous construisons de nombreux outils pour analyser et inspecter le cluster Intel. Nous avons mis à niveau notre base de code de Kubernetes 1.10 à 1.12 avec succès, mais le processus n’a pas été aussi simple. Certains de nos utilisateurs se plaignent toujours que leurs conteneurs redémarrent brusquement et ils ne savent pas pourquoi. «Je n'ai rien fait, pourquoi tous mes conteneurs commencent-ils?» Nous ne savons pas pourquoi. Après quelques analyses, nous avons découvert que c'était parce que nous étions en train de mettre à niveau le serveur d'API et que dans la nouvelle version, l'API de spécification du pod a été modifiée. Ensuite, la signature de la capsule est modifiée et Kubelets pense que les capsules doivent être recréées. Le problème est qu’il s’agit d’un comportement inattendu et que nos utilisateurs ne sont pas préparés au redémarrage du conteneur.

Globalement, je pense que Kubernetes est un gros projet. Je pense qu’il compte environ 1,3 million de lignes de code et même que nous sommes toujours en train d’apprendre. Mais au cours de ce processus d'apprentissage, certains comportements inattendus peuvent être risqués, du moins à mon avis. En résumé, je pense que passer à Kubernetes n’est pas aussi difficile qu’il en a l’air, bien que le travail soit combiné, car l’utilisation des contrôleurs CRD et du plug-in peut faciliter l’intégration et que Kubernetes est en mesure de gérer le grand cluster. Nos expériences réalisées en interne montrent que le dernier débit etcd peut atteindre environ 5000 QPS pour exécuter 100 clients, en parallèle, par rapport à un million de paires de KV aléatoires. Le débit du planificateur peut atteindre environ 150 pods par seconde dans un cluster à grande échelle avec plus de 10 000 nœuds et 100 000 conteneurs en cours d'exécution.

La dernière chose que je veux souligner est, essayez simplement de vous en tenir à l’amont, ce qui signifie que vous ne devez pas vous déplacer. Cela signifie que nous devons rendre le serveur API Kubernetes de base aussi intact que possible. Nous devrions respecter l’API déclarative et les modèles de contrôleur qui effectuent l’extension. Nous devons également honorer le Kubelet et le CRI pour l'exécution à exécuter dans les conteneurs. Bien sûr, si vous le faites en amont, vous devez payer tous les quelques mois le coût de la refonte de votre code en amont. Je pense que cela en vaut vraiment la peine car à la fin, toute une communauté soutiendra le système que vous utilisez. Cela dit, je termine mon exposé et je suis ravi de répondre à vos questions.

questions et réponses

Participant 1: Vous avez indiqué à votre planificateur que vous pouviez augmenter votre utilisation de 15% à 40%. Considérez-vous ces 40% comme une limite supérieure pour laquelle vous visez ou avez-vous des ambitions d'aller au-delà?

Guo: En fait, si vous regardez cela, tout d'abord, nous n'utilisons pas un Kubernetes unifié pour toutes les charges de travail. Ce sont deux systèmes. Un système exécute une charge de travail en ligne et un système exécutera des charges de travail par lots. Si vous pensez au modèle de charge de travail en ligne, les gens font leurs courses à midi ou le soir, mais ils sont complètement inactifs au milieu parce que les gens dorment. Les travaux hors ligne peuvent tirer parti de la fenêtre temporelle de cette zone pour effectuer leur travail. Nos travaux hors ligne peuvent tolérer les échecs, une durée d'exécution plus longue lorsque vous exécutez des travaux de traitement par lots, une fois le travail en ligne démarré. Une fois le travail en ligne démarré, les travaux hors ligne doivent être [inaudible 00:36:59]

Si vous examinez la situation à cet égard, les 40% sont plutôt limités par les emplois en ligne, car, comme je l’ai dit, ils ont une forte exigence en matière de ressources. Ils utilisent même le noyau dont nous avons besoin pour les affecter à un noyau spécifique et souhaitent occuper tout le noyau. Si, pour une raison quelconque, ils ne configurent pas correctement le numéro principal, cette utilisation ne peut pas être renvoyée à votre valeur la plus élevée. Nous avons donc beaucoup de contraintes. Si vous voulez augmenter l'utilisation, il faut plus que l'ordonnanceur, plus que l'infrastructure. Nous devons dire à quiconque utilise le système de définir une ressource de réservation que vous souhaitez. C’est un effort plus important que lors de la mise à niveau de l’infrastructure. C'est l'histoire et les 40%. Atteindre ces 40% est un travail vraiment difficile, en fait. Je pense que même l’utilisation de Google est d’environ 50%. C'est mon histoire. Si j'atteins 50%, je serais vraiment heureux.

Participant 2: Hier, Uber a présenté Peloton, une plate-forme d'orchestration comme la vôtre. Comment comparez-vous votre solution à Peloton?

Guo: Je pense que je dois en savoir plus sur le Peloton avant de répondre à votre question. Je voudrais discuter de cela avec vous en mode hors connexion.

Participant 3: Vous avez mentionné que vous colocalisez les conteneurs de lots avec des conteneurs sans état. Que faites-vous pour les conteneurs de lot pour l'isolation d'E / S de disque?

Guo: Je n'ai pas mentionné cela parce que certaines des solutions sont tellement spécifiques à Alibaba parce que nous avons nos propres équipes de systèmes d'exploitation; ils ont des fonctionnalités QS implémentées dans la couche de pile de stockage et je ne connais pas les détails. Mais c’est quelque chose que nous ne faisons pas dans la couche planifiée ni dans la couche Kubernetes; c'est entièrement dans la couche de système d'exploitation, car nous devons en quelque sorte interagir avec un système d'exploitation pour assurer l'isolation des performances. Du côté de la mémoire de la CPU, nous ne jouons généralement qu’avec les paramètres SQL, mais pour le réseau et le stockage, nous jouons du côté du pilote. Ils font des changements.

Participant 4: Mon autre question était: faites-vous un partage de ressources, un partage de ressources élastique dans votre planificateur? Que faites-vous pour la gestion des quotas?

Guo: For now, we don't do very sophisticated quota management, because we typically have big pools, and we typically honor your request as long as the pool has capacity. C'est ça. Because in general, for running a business like this, our infrastructures really tells the business guys we are out of the budget, we need more machines. We will just get more machines. But in fact, that's a very good question. Nowadays, because the cost is so high, we are thinking about your very careful quota assignment to the BUs that you can use, and sometimes if you want, you can provide solutions to third-party users, not BUs. For other customers, you have to enforce the quota. We do have our quota controllers inside, which I didn't mention today. This is a purely separate CRD, just for quota purposes. With resource quotas, you can do very fine-grain quota management. We can discuss this offline, if you like.

Participant 5: You mentioned that to maintain the feature parity, you actually introduced cost CPU topology-aware, and in your scheduler you maintain a cache of the CPU topology of all the nodes. My question is, how often do you update your cache? How do you deal with the cache inconsistency?

Guo: That's a very good question. The cache consistency is key because there are two things. First, you have to put the pod informer in the cache because every time the API server has some changes on the pod, you need to upgrade the cache accordingly. For now, at least, we completely rely on the stableness of the podwatch. If there is a network issue in which we're missing one pod, we probably will introduce the cache inconsistently in our cash. We need to periodically reconcile to make sure the caches are consistent. But the consistent requirement is not that strict, because in general, we are in good scenarios, and the network problem causing the missing one or two pods is rare, and we somehow can tolerate this kind of misinformation. As long as we have a mechanism to back up, to resync every 10 minutes, something like that, I think we are fine.

Participant 6: [inaudible 00:43:22]

Guo: Yes. This is a very common perception. The guy is asking about Double 11 – for such important events, if you have a problem with the scheduler then the pod cannot start, the service is done. C'est [inaudible 00:43:42] right? This is a very common perception. I asked the same question for the scheduler guys. “You guys don’t make a good job, how do you handle Double 11?” In fact, Double 11, think about it. Mostly, the pressure is in owner applications. They've already been launched, let's say 10 days ago, before the event. The actual pressure to the scheduler is the minimum to Double 11 events, where it will stress the rest of the system, but not the scheduler.

Partcipant 7: Actually, a lot of the talk here is about the group scheduler, and also the topology-aware of the scheduling. Actually, in the open-source community, the project has been driving. One is driving [inaudible 00:44:32] scheduler, and another one is driving by the signaled, where I am the tech lead. I really encourage you guys to upstream and contribute to those things because there's the mini proposal made by the community. The only reason that's not happening is just lack of the contributors. I think a lot of people attended the earlier keynote speech, and the talk about the leadership. In the open-source community, we lean on that leadership; someone stands up, says, “Oh, here it is, I want to supervise a certain project …” I just wanted to follow up.

Participant 8: You guys maintain quite a lot of clusters, right?

Guo: Yes.

Participant 8: How similar are all those clusters, and how do you schedule between them? How do you decide that a given workload's going to run on one cluster versus another?

Guo: We currently don't have the multi-cluster scheduler, like federation stuff. We don't do that at this moment. I react to a question like this because typically, our cluster is big. You rarely get a case where you want to deploy your application into two clusters. We solve this problem by just building big clusters to work around this, you need to spread things across clusters.

Participant 9: In your algorithm, you mentioned that you do a randomization on all the metrics, and then find the nodes. What do you do for the bigger containers? This will actually lead to a defragmented cluster, right? Because you would not be able to place the bigger containers, because once you're randomly choosing the nodes, you're actually defragmenting the cluster.

Guo: A few things. At least, currently our scheduler doesn't have this notion of a prerequisite move, reschedule, funny things. Here I need to solve two problems. The first problem is if the scheduler, if the cluster is empty, it's likely that the load is very low. I need to break the fast, and then I use randomization, because if the Intel cluster is kind of empty, this won't introduce too many fragmentation issues. Then, I have another optimization I didn't mention here. I constantly check the allocation rate of the cluster. If I find that the cluster allocation rate is kind of high, basically close to the full, the fragmentation can be an issue now. I just don't do the randomization. I'd probably stick back to the first come, first serve kind of feature to reduce the chance of having the exact problem that you mentioned. But I skipped the details in this talk. I have some thoughts about this, but this is a hard problem, the scheduler.

Voir plus de présentations avec transcriptions

Commentaires

Laisser un commentaire

Votre commentaire sera révisé par les administrateurs si besoin.