Vous collectez donc des métriques. Comme nous sommes. Nous collectons également des métriques. Bien sûr, nécessaire pour les affaires. Aujourd'hui, nous allons parler du tout premier maillon de notre système de surveillance - un serveur d'agrégation compatible statsd
De nos articles précédents (
Réclamation 1. Github, le développeur du projet, a cessé de le prendre en charge : en publiant des correctifs et des correctifs, en acceptant les nôtres et (pas seulement les nôtres) les relations publiques. Au cours des derniers mois (entre février et mars 2018), l'activité a repris, mais avant cela, il y a eu presque 2 ans de calme complet. De plus, le projet est en cours de développement
Réclamation 2. Précision des calculs. Brubeck collecte un total de 65536 30 valeurs pour l'agrégation. Dans notre cas, pour certaines métriques, pendant la période d'agrégation (1 secondes), beaucoup plus de valeurs peuvent arriver (527 392 XNUMX au pic). Suite à cet échantillonnage, les valeurs maximales et minimales apparaissent inutiles. Par exemple, comme ceci :
Comme c'était
Comment ça aurait dû être
Pour la même raison, les montants sont généralement mal calculés. Ajoutez ici un bug avec un débordement de float 32 bits, qui envoie généralement le serveur en erreur de segmentation lors de la réception d'une métrique apparemment innocente, et tout devient génial. Soit dit en passant, le bug n’a pas été corrigé.
Et, enfin, Réclamation X. Au moment de la rédaction de cet article, nous sommes prêts à le présenter aux 14 implémentations de statsd plus ou moins fonctionnelles que nous avons pu trouver. Imaginons qu'une infrastructure se soit tellement développée qu'accepter 4 millions de MPS ne suffit plus. Ou même s'il n'a pas encore augmenté, mais les indicateurs sont déjà si importants pour vous que même de courtes baisses de 2 à 3 minutes dans les graphiques peuvent déjà devenir critiques et provoquer des crises de dépression insurmontables parmi les managers. Le traitement de la dépression étant une tâche ingrate, des solutions techniques sont nécessaires.
Premièrement, la tolérance aux pannes, afin qu'un problème soudain sur le serveur ne provoque pas une apocalypse zombie psychiatrique au bureau. Deuxièmement, évoluer pour pouvoir accepter plus de 4 millions de MPS, sans creuser profondément dans la pile réseau Linux et sans augmenter calmement « en largeur » jusqu'à la taille requise.
Comme nous avions de la marge pour évoluer, nous avons décidé de commencer par la tolérance aux pannes. "À PROPOS DE! Tolérance aux pannes ! C'est simple, nous pouvons le faire », avons-nous pensé et lancé 2 serveurs, en élevant une copie de brubeck sur chacun. Pour ce faire, nous avons dû copier le trafic avec les métriques sur les deux serveurs et même écrire pour cela
Si vous réfléchissez un peu au problème et en même temps déterrez la neige avec une pelle, alors l'idée évidente suivante peut vous venir à l'esprit : vous avez besoin d'un statsd capable de fonctionner en mode distribué. C'est-à-dire celui qui implémente la synchronisation entre les nœuds dans le temps et les métriques. "Bien sûr, une telle solution existe probablement déjà", avons-nous dit en nous tournant vers Google…. Et ils n'ont rien trouvé. Après avoir parcouru la documentation des différentes statistiques (
Et puis nous nous sommes souvenus du "jouet" statsd - bioyino, qui a été écrit lors du hackathon Just for Fun (le nom du projet a été généré par le script avant le début du hackathon) et avons réalisé que nous avions un besoin urgent de nos propres statsd. Pour quoi?
- parce qu'il y a trop peu de clones statsd dans le monde,
- car il est possible de fournir la tolérance aux pannes et l'évolutivité souhaitées ou proches de celles souhaitées (y compris la synchronisation des métriques agrégées entre les serveurs et la résolution du problème des conflits d'envoi),
- parce qu'il est possible de calculer des métriques avec plus de précision que Brubeck,
- parce que vous pouvez collecter vous-même des statistiques plus détaillées, que Brubeck ne nous a pratiquement pas fournies,
- parce que j'ai eu la chance de programmer ma propre application de laboratoire à échelle distribuée hyperperformance, qui ne répétera pas complètement l'architecture d'une autre hyperfor similaire... eh bien, c'est tout.
Sur quoi écrire ? Bien sûr, à Rust. Pourquoi?
- car il existait déjà une solution prototype,
- parce que l'auteur de l'article connaissait déjà Rust à cette époque et était impatient d'y écrire quelque chose pour la production avec la possibilité de le mettre en open source,
- car les langages avec GC ne nous conviennent pas en raison de la nature du trafic reçu (presque en temps réel) et les pauses GC sont pratiquement inacceptables,
- parce que vous avez besoin de performances maximales comparables à C
- parce que Rust nous offre une concurrence intrépide, et si nous avions commencé à l'écrire en C/C++, nous aurions récolté encore plus de vulnérabilités, de débordements de tampon, de conditions de concurrence et d'autres mots effrayants que Brubeck.
Il y a également eu une dispute contre Rust. L'entreprise n'avait aucune expérience dans la création de projets dans Rust et nous ne prévoyons désormais pas non plus de l'utiliser dans le projet principal. On craignait donc sérieusement que rien ne marche, mais nous avons décidé de tenter notre chance et d’essayer.
Le temps passait...
Finalement, après plusieurs tentatives infructueuses, la première version fonctionnelle était prête. Ce qui s'est passé? C'est ce qui s'est passé.
Chaque nœud reçoit son propre ensemble de métriques et les accumule, et ne regroupe pas les métriques pour les types pour lesquels leur ensemble complet est requis pour l'agrégation finale. Les nœuds sont connectés les uns aux autres par une sorte de protocole de verrouillage distribué, qui vous permet de sélectionner parmi eux le seul (ici nous avons pleuré) qui est digne d'envoyer des métriques au Grand. Ce problème est actuellement résolu par
Les paquets UDP avec métriques sont déséquilibrés entre les nœuds des équipements réseau via un simple Round Robin. Bien entendu, le matériel réseau n’analyse pas le contenu des paquets et peut donc extraire bien plus de 4 millions de paquets par seconde, sans parler des métriques dont il ne sait rien du tout. Si nous tenons compte du fait que les métriques n'arrivent pas une par une dans chaque paquet, nous ne prévoyons aucun problème de performances à cet endroit. Si un serveur tombe en panne, le périphérique réseau détecte rapidement (en 1 à 2 secondes) ce fait et supprime le serveur en panne de la rotation. En conséquence, les nœuds passifs (c'est-à-dire non leaders) peuvent être activés et désactivés pratiquement sans remarquer de baisses sur les graphiques. Le maximum que nous perdons fait partie des métriques arrivées à la dernière seconde. Une perte/arrêt/commutation soudaine d'un leader créera toujours une anomalie mineure (l'intervalle de 30 secondes est toujours désynchronisé), mais s'il y a une communication entre les nœuds, ces problèmes peuvent être minimisés, par exemple, en envoyant des paquets de synchronisation. .
Un peu sur la structure interne. L'application est bien sûr multithread, mais l'architecture des threads est différente de celle utilisée à Brubeck. Les fils de discussion à Brubeck sont les mêmes - chacun d'eux est responsable à la fois de la collecte et de l'agrégation des informations. Dans bioyino, les travailleurs sont répartis en deux groupes : ceux responsables du réseau et ceux responsables de l'agrégation. Cette division vous permet de gérer l'application de manière plus flexible en fonction du type de métriques : là où une agrégation intensive est requise, vous pouvez ajouter des agrégateurs, là où il y a beaucoup de trafic réseau, vous pouvez ajouter le nombre de flux réseau. Actuellement, sur nos serveurs, nous travaillons en 8 flux réseau et 4 flux d'agrégation.
La partie comptage (responsable de l'agrégation) est assez ennuyeuse. Les tampons remplis par les flux réseau sont répartis entre les flux de comptage, où ils sont ensuite analysés et agrégés. Sur demande, des métriques sont fournies pour être envoyées à d'autres nœuds. Tout cela, y compris l'envoi de données entre les nœuds et le travail avec Consul, est effectué de manière asynchrone, en s'exécutant sur le framework.
Beaucoup plus de problèmes lors du développement ont été causés par la partie réseau chargée de recevoir les métriques. L'objectif principal de la séparation des flux de réseau en entités distinctes était la volonté de réduire le temps passé par un flux aucun pour lire les données du socket. Les options utilisant UDP asynchrone et recvmsg régulier ont rapidement disparu : la première consomme trop d'espace CPU pour le traitement des événements, la seconde nécessite trop de changements de contexte. C'est pourquoi il est maintenant utilisé
Noter
Dans les paramètres par défaut, la taille du tampon est assez grande. Si vous décidez soudainement d'essayer le serveur vous-même, vous risquez de constater qu'après l'envoi d'un petit nombre de métriques, elles n'arriveront pas dans Graphite et resteront dans le tampon du flux réseau. Pour travailler avec un petit nombre de métriques, vous devez définir bufsize et task-queue-size sur des valeurs plus petites dans la configuration.
Enfin, quelques graphiques pour les amateurs de graphiques.
Statistiques sur le nombre de métriques entrantes pour chaque serveur : plus de 2 millions de MPS.
Désactivation de l'un des nœuds et redistribution des métriques entrantes.
Statistiques sur les métriques sortantes : un seul nœud envoie toujours - le patron du raid.
Statistiques de fonctionnement de chaque nœud, prenant en compte les erreurs dans différents modules du système.
Détails des métriques entrantes (les noms des métriques sont masqués).
Que prévoyons-nous de faire de tout cela ensuite ? Bien sûr, écrivez du code, putain... ! Le projet était initialement prévu pour être open-source et le restera tout au long de sa vie. Nos plans immédiats incluent le passage à notre propre version de Raft, le remplacement du protocole homologue par un protocole plus portable, l'introduction de statistiques internes supplémentaires, de nouveaux types de métriques, des corrections de bugs et d'autres améliorations.
Bien entendu, tout le monde est invité à contribuer au développement du projet : créer des relations publiques, des problèmes, si possible nous y répondrons, nous améliorerons, etc.
Cela étant dit, c’est tout, achetez nos éléphants !
Source: habr.com