Kubernetes : accélérez vos services en supprimant les limites du processeur

En 2016, nous chez Buffer je suis passé à Kubernetes, et maintenant environ 60 nœuds (sur AWS) et 1500 8 conteneurs travaillent sur notre cluster kXNUMXs géré par puisque. Cependant, nous sommes passés aux microservices par essais et erreurs, et même après plusieurs années de travail avec les k8, nous sommes toujours confrontés à de nouveaux problèmes. Dans cet article, nous parlerons de limitations du processeur: pourquoi nous pensions qu'ils étaient de bonnes pratiques et pourquoi ils n'étaient finalement pas si bons.

Limitations et limitation du processeur

Comme beaucoup d'autres utilisateurs de Kubernetes, Google recommande fortement de définir des limites de processeur. Sans un tel paramètre, les conteneurs d'un nœud peuvent utiliser toute la puissance du processeur, ce qui entraîne d'importants processus Kubernetes (par exemple kubelet) cessera de répondre aux demandes. Ainsi, définir des limites de CPU est un bon moyen de protéger vos nœuds.

Les limites du processeur définissent un conteneur sur le temps CPU maximum qu'il peut utiliser pendant une période spécifique (la valeur par défaut est 100 ms), et le conteneur ne dépassera jamais cette limite. Dans Kubernetes pour étranglement conteneur et l'empêcher de dépasser la limite, un outil spécial est utilisé Quota du CSA, mais ces limites artificielles du processeur finissent par nuire aux performances et augmenter le temps de réponse de vos conteneurs.

Que peut-il se passer si nous ne fixons pas de limites en matière de processeur ?

Malheureusement, nous avons dû nous-mêmes faire face à ce problème. Chaque nœud dispose d'un processus responsable de la gestion des conteneurs kubelet, et il a cessé de répondre aux demandes. Le nœud, lorsque cela se produit, entrera dans l'état NotReady, et les conteneurs de celui-ci seront redirigés ailleurs et créeront les mêmes problèmes sur les nouveaux nœuds. Ce n’est pas un scénario idéal, c’est le moins qu’on puisse dire.

Manifestation du problème de limitation et de réponse

La mesure clé pour le suivi des conteneurs est trottling, il indique combien de fois votre conteneur a été limité. Nous avons remarqué avec intérêt la présence de throttling dans certains conteneurs, que la charge du processeur soit extrême ou non. À titre d'exemple, jetons un œil à l'une de nos principales API :

Kubernetes : accélérez vos services en supprimant les limites du processeur

Comme vous pouvez le voir ci-dessous, nous avons fixé la limite à 800m (0.8 ou 80 % de noyau) et valeurs maximales à la meilleure portée 200m (20 % de base). Il semblerait qu'avant de limiter le service, nous disposions encore de beaucoup de puissance de processeur, cependant...

Kubernetes : accélérez vos services en supprimant les limites du processeur
Vous avez peut-être remarqué que même lorsque la charge du processeur est inférieure aux limites spécifiées - nettement inférieures - une limitation se produit toujours.

Face à cela, nous avons rapidement découvert plusieurs ressources (problème sur github, présentation sur zadano, poster sur omio) sur la baisse des performances et du temps de réponse des services due à la limitation.

Pourquoi constatons-nous une limitation lorsque la charge du processeur est faible ? La version courte est la suivante : « il y a un bug dans le noyau Linux qui provoque une limitation inutile des conteneurs avec des limites de processeur spécifiées ». Si vous êtes intéressé par la nature du problème, vous pouvez lire la présentation (vidéo и textuel options) par Dave Chiluk.

Suppression des restrictions du processeur (avec une extrême prudence)

Après de longues discussions, nous avons décidé de supprimer les restrictions de processeur de tous les services qui affectaient directement ou indirectement les fonctionnalités critiques de nos utilisateurs.

La décision n’a pas été facile car nous accordons une grande importance à la stabilité de notre cluster. Dans le passé, nous avons déjà expérimenté l'instabilité de notre cluster, puis les services consommaient trop de ressources et ralentissaient le travail de l'ensemble de leur nœud. Maintenant, tout était quelque peu différent : nous avions une compréhension claire de ce que nous attendions de nos clusters, ainsi qu'une bonne stratégie pour mettre en œuvre les changements prévus.

Kubernetes : accélérez vos services en supprimant les limites du processeur
Correspondance commerciale sur une question urgente.

Comment protéger vos nœuds lorsque les restrictions sont levées ?

Isolement des services « sans restriction » :

Dans le passé, nous avons déjà vu certains nœuds entrer dans un état notReady, principalement en raison de services consommant trop de ressources.

Nous avons décidé de placer ces services dans des nœuds séparés (« étiquetés ») afin qu'ils n'interfèrent pas avec les services « associés ». En conséquence, en marquant certains nœuds et en ajoutant le paramètre de tolérance aux services « non liés », nous avons obtenu un meilleur contrôle sur le cluster et il nous est devenu plus facile d'identifier les problèmes avec les nœuds. Pour réaliser vous-même des démarches similaires, vous pouvez vous familiariser avec Documentation.

Kubernetes : accélérez vos services en supprimant les limites du processeur

Attribution d'un processeur et d'une demande de mémoire corrects :

Notre plus grande crainte était que le processus consomme trop de ressources et que le nœud cesse de répondre aux demandes. Puisque désormais (grâce à Datadog) nous pouvions clairement surveiller tous les services de notre cluster, j'ai analysé plusieurs mois de fonctionnement de ceux que nous prévoyions de désigner comme « non liés ». J'ai simplement défini l'utilisation maximale du processeur avec une marge de 20 %, et j'ai donc alloué de l'espace dans le nœud au cas où k8s tenterait d'attribuer d'autres services au nœud.

Kubernetes : accélérez vos services en supprimant les limites du processeur

Comme vous pouvez le voir sur le graphique, la charge maximale sur le processeur a atteint 242m Cœurs de processeur (0.242 cœurs de processeur). Pour une requête processeur, il suffit de prendre un nombre légèrement supérieur à cette valeur. Veuillez noter que les services étant centrés sur l'utilisateur, les valeurs de charge de pointe coïncident avec le trafic.

Faites de même avec l'utilisation de la mémoire et les requêtes, et voilà : vous êtes prêt ! Pour plus de sécurité, vous pouvez ajouter une mise à l'échelle automatique des pods horizontaux. Ainsi, chaque fois que la charge des ressources est élevée, l'autoscaling créera de nouveaux pods et Kubernetes les distribuera aux nœuds disposant d'espace libre. S'il n'y a plus d'espace dans le cluster lui-même, vous pouvez vous définir une alerte ou configurer l'ajout de nouveaux nœuds via leur mise à l'échelle automatique.

Parmi les inconvénients, il convient de noter que nous avons perdu en "densité du conteneur", c'est à dire. nombre de conteneurs exécutés sur un nœud. Nous pouvons également avoir beaucoup de «relaxations» à faible densité de trafic, et il est également possible que vous atteigniez une charge de processeur élevée, mais les nœuds de mise à l'échelle automatique devraient vous aider dans ce dernier cas.

résultats

Je suis heureux de publier ces excellents résultats issus des expériences menées au cours des dernières semaines ; nous avons déjà constaté des améliorations significatives de la réponse dans tous les services modifiés :

Kubernetes : accélérez vos services en supprimant les limites du processeur

Nous avons obtenu les meilleurs résultats sur notre page d'accueil (buffer.com), là le service s'est accéléré en vingt-deux fois !

Kubernetes : accélérez vos services en supprimant les limites du processeur

Le bug du noyau Linux est-il corrigé ?

Oui, Le bug a déjà été corrigé et le correctif a été ajouté au noyau distributions version 4.19 et supérieures.

Cependant, à la lecture problèmes de Kubernetes sur github pour le 2020 septembre XNUMX nous rencontrons encore des mentions de certains projets Linux avec un bug similaire. Je pense que certaines distributions Linux ont toujours ce bug et travaillent simplement à le corriger.

Si la version de votre distribution est inférieure à 4.19, je vous recommande de mettre à jour vers la dernière version, mais dans tous les cas, vous devriez essayer de supprimer les restrictions du processeur et voir si la limitation persiste. Ci-dessous, vous pouvez voir une liste partielle des services de gestion Kubernetes et des distributions Linux :

  • Debian : correctif intégré à la dernière version de la distribution, buster, et a l'air assez frais (Août 2020 ans). Certaines versions précédentes peuvent également être corrigées.
  • Ubuntu : correctif intégré à la dernière version Ubuntu Focal Fossa 20.04
  • EKS a encore un correctif en décembre 2019 de l'année. Si votre version est inférieure à celle-ci, vous devez mettre à jour l'AMI.
  • copines : À partir de juin 2020 у kops 1.18+ L'image hôte principale sera Ubuntu 20.04. Si votre version de kops est plus ancienne, vous devrez peut-être attendre un correctif. Nous attendons nous-mêmes maintenant.
  • GKE (Google Cloud) : correctif intégré en janvier 2020, cependant il y a des problèmes avec la limitation sont toujours observés.

Que faire si le correctif résout le problème de limitation ?

Je ne suis pas sûr que le problème soit complètement résolu. Lorsque nous arriverons à la version du noyau avec le correctif, je testerai le cluster et mettrai à jour la publication. Si quelqu'un a déjà mis à jour, je serais intéressé de lire vos résultats.

Conclusion

  • Si vous travaillez avec des conteneurs Docker sous Linux (peu importe Kubernetes, Mesos, Swarm ou autres), vos conteneurs peuvent perdre en performances en raison de la limitation ;
  • Essayez de mettre à jour vers la dernière version de votre distribution en espérant que le bug a déjà été corrigé ;
  • La suppression des limites du processeur résoudra le problème, mais il s'agit d'une technique dangereuse qui doit être utilisée avec une extrême prudence (il est préférable de d'abord mettre à jour le noyau et de comparer les résultats) ;
  • Si vous avez supprimé les limites du processeur, surveillez attentivement l'utilisation de votre processeur et de votre mémoire et assurez-vous que vos ressources CPU dépassent votre consommation ;
  • Une option sûre consisterait à mettre à l'échelle automatiquement les pods pour créer de nouveaux pods en cas de charge matérielle élevée, afin que Kubernetes les attribue à des nœuds libres.

J'espère que cet article vous aidera à améliorer les performances de vos systèmes de conteneurs.

PS il est l'auteur correspond avec des lecteurs et des commentateurs (en anglais).


Source: habr.com

Ajouter un commentaire