Maison  >  Article  >  Applet WeChat  >  Vous apprendre comment libco prend en charge d'énormes quantités d'informations de données

Vous apprendre comment libco prend en charge d'énormes quantités d'informations de données

Y2J
Y2Joriginal
2017-05-11 11:53:362021parcourir

Ibco est une bibliothèque de coroutines c/c++ utilisée à grande échelle dans le backend WeChat. Elle fonctionne de manière stable sur des dizaines de milliers de machines dans le backend WeChat depuis 2013. Libco a été open source pour la première fois en 2013 en tant que l'un des six projets open source majeurs de Tencent. Nous avons récemment effectué une mise à jour majeure, qui est synchronisée sur github.com/tencent/libco. libco prend en charge le modèle de programmation de style de synchronisation agile backend tout en offrant des capacités de simultanéité élevées du système.

Fonctionnalités prises en charge par libco

Pas besoin d'envahir la logique métier, de transformer les services multi-processus et multi-thread en services coroutine, et la capacité de concurrence est améliorée cent fois ; 🎜> Prise en charge de CGI
Framework
, services Web faciles à créer (Nouveau) ; Prend en charge les bibliothèques tierces couramment utilisées telles que gethostbyname, mysqlclient, ssl (Nouveau) ; mode pile partagée, facile à autonome Accès à des dizaines de millions de connexions (Nouveau);

Programmation coroutine parfaite et concise
interface


- conception d'interface de type pthread, via des interfaces simples et claires telles que co_create et co_resume Compléter la création et la restauration de la coroutine ; – Coroutine privée variable de type thread, sémaphore de coroutine co_signal (Nouveau) pour la communication entre coroutines – Lambda de niveau non linguistique ; implémentation, combinée avec une coroutine sur place Écrire et exécuter des tâches asynchrones en arrière-plan (Nouveau) ; – Un framework réseau petit et léger basé sur epoll/kqueue, un minuteur hautes performances basé sur la roulette temporelle
timer
 ; > Généré par libco Contexte Au début du backend de WeChat, en raison des besoins commerciaux complexes et changeants et des exigences d'itération rapide des produits, la plupart des modules ont adopté un modèle semi-synchrone et semi-asynchrone
. La couche d'accès est un modèle asynchrone et la couche de logique métier est un modèle synchrone multi-processus ou multi-thread. La capacité de concurrence de la logique métier n'est que de quelques dizaines à plusieurs centaines. À mesure que l'activité de WeChat se développe, l'échelle du système devient de plus en plus grande et chaque module est facilement affecté par la gigue du service back-end/du réseau.

Le choix de la transformation asynchrone
Afin d'améliorer la capacité de concurrence du backend de WeChat, l'approche générale consiste à modifier tous les services du réseau existant vers un modèle asynchrone. Cette approche nécessite une énorme quantité de travail, du framework au code de logique métier, ce qui nécessite une transformation complète, chronophage, laborieuse et risquée. Nous avons donc commencé à réfléchir à l'utilisation de coroutines.
Cependant, l'utilisation de coroutines sera confrontée aux défis suivants :

L'industrie n'a aucune expérience dans l'application à grande échelle de coroutines dans un environnement c/c++

Comment contrôler la coroutine ; scheduling;

 Comment gérer les appels
API
de style synchronisé, tels que Socket, mysqlclient, etc.;

 Comment gérer l'utilisation de variables globales existantes et de variables privées de thread ;
En fin de compte, nous avons résolu tous les problèmes ci-dessus grâce à libco et réalisé une transformation asynchrone non intrusive de la logique métier. Nous avons utilisé libco pour transformer des centaines de modules backend WeChat en coroutines et transformations asynchrones. Au cours du processus de transformation, le code de la logique métier est resté fondamentalement inchangé. Jusqu'à présent, la plupart des services du backend WeChat sont des modèles de coroutine multi-processus ou multithread. Les capacités de concurrence ont été qualitativement améliorées par rapport à avant, et libco est devenue la pierre angulaire du framework backend WeChat.
 framework libco

Libco est divisé en trois couches dans le framework, à savoir la couche d'interface, la couche système
fonction
la couche Hook et l'
événement

pilote Couche.


Traitement des API de style synchrone

Pour les API de style synchrone, principalement des appels réseau synchrones, la tâche principale de libco est d'éliminer l'occupation des ressources par ces attentes et d'améliorer les performances de concurrence du système. Pour un service d'arrière-plan réseau régulier, nous pouvons passer par des étapes telles que la connexion, l'écriture, la lecture, etc. pour terminer une interaction réseau complète. Lors de l'appel de ces API de manière synchrone, l'ensemble du thread se bloquera en attendant une interaction réseau.

Bien que les performances de concurrence du style de programmation synchrone ne soient pas bonnes, il présente les avantages d'une logique de code claire, d'une écriture facile et peut prendre en charge une itération commerciale rapide et un développement agile. Afin de continuer à conserver les avantages de la programmation synchrone sans modifier le code logique métier existant en ligne, libco a repris de manière innovante l'interface d'appel réseau (Hook) et a enregistré la remise et la récupération de la coroutine en tant qu'événement dans les E/S réseau asynchrones avec rappels. . Lorsque le traitement métier rencontre une demande réseau synchrone, la couche libco enregistrera la demande réseau comme un événement asynchrone. Cette coroutine abandonnera l'occupation du processeur et le processeur sera remis à autres coroutines pour exécution. Libco reprendra automatiquement l'exécution de la coroutine lorsqu'un événement réseau se produit ou expire.

Nous avons repris la plupart des API de style de synchronisation via la méthode Hook, et libco planifiera la coroutine pour reprendre l'exécution au moment approprié.

Des dizaines de millions de coroutines prises en charge
Par défaut, libco permet à chaque coroutine d'avoir sa propre pile en cours d'exécution. Lorsque la coroutine est créée, une mémoire de taille fixe est allouée à partir de la mémoire du tas en tant que pile en cours d'exécution. pour la coroutine. Si nous utilisons une coroutine pour traiter une connexion d'accès sur le front-end, alors pour un service d'accès massif, la limite de concurrence de notre service sera facilement limitée par la mémoire. À cette fin, libco fournit également un mode de partage de coroutines sans pile, qui vous permet de configurer plusieurs coroutines pour partager la même pile en cours d'exécution. Lors du basculement entre des coroutines sous la même pile partagée, le contenu actuel de la pile en cours d'exécution doit être copié dans la mémoire privée de la coroutine. Afin de réduire le nombre de ces copies de mémoire, la copie de mémoire de la pile partagée ne se produit que lors du basculement entre différentes coroutines. Lorsque l'occupant de la pile partagée n'a pas changé, il n'est pas nécessaire de copier la pile en cours d'exécution.

Le mode pile de coroutines partagées de la coroutine libco permet à une seule machine d'accéder facilement à des dizaines de millions de connexions, simplement en créant suffisamment de coroutines. Nous créons 10 millions de coroutines (E5-2670 v3 à 2,30 GHz * 2, 128 Go de mémoire) via le mode pile partagée libco. Chaque 100 000 coroutines utilise 128 Ko de mémoire, et l'ensemble du service echo est stable. La consommation totale de mémoire. est d'environ 66G.
Variables privées de coroutine
Lorsqu'un programme multi-processus est transformé en programme multi-thread, nous pouvons utiliser le thread pour modifier rapidement les variables globales. Dans l'environnement coroutine, nous avons créé la variable coroutine ROUTINE_VAR, ce qui simplifie grandement la réduction. la charge de travail de transformation de coroutine.
Étant donné que les coroutines sont essentiellement exécutées en série au sein d'un thread, lorsque nous définissons une variable privée de thread, il peut y avoir des problèmes de réentrance. Par exemple, si nous définissons une variable privée de thread d'un thread, nous voulions à l'origine que chaque logique d'exécution ait un usage exclusif de cette variable. Mais lorsque notre environnement d'exécution est migré vers des coroutines, la même variable privée de thread peut être exploitée par plusieurs coroutines, ce qui conduit au problème d'intrusion de variables. Pour cette raison, lorsque nous effectuions la transformation asynchrone de libco, nous avons modifié la plupart des variables privées du thread en variables privées au niveau de la coroutine. Les variables privées de coroutine ont les caractéristiques suivantes : lorsque le code s'exécute dans un environnement multithread non coroutine, la variable est privée pour le thread ; lorsque le code s'exécute dans un environnement coroutine, cette variable est privée pour la coroutine. Les variables privées de la coroutine sous-jacente complèteront automatiquement le jugement de l'environnement d'exécution et renverront correctement la valeur requise.
Les variables privées de coroutine jouent un rôle décisif dans la transformation de l'environnement existant de la synchronisation à l'asynchronisation. En même temps, nous avons défini une méthode très simple et pratique pour définir les variables privées de coroutine, qui est aussi simple qu'une seule ligne de déclaration. code.
 Méthode Hook de gethostbyname
Pour les services réseau existants, il peut être nécessaire de interrogerDNS pour obtenir l'adresse réelle via l'interface API gethostbyname du système. Lors de la transformation de la coroutine, nous avons constaté que la fonction de la famille de sockets de notre hook n'est pas applicable à gethostbyname. Lorsqu'une coroutine appelle gethostbyname, elle attend le résultat de manière synchrone, ce qui retarde l'exécution des autres coroutines du même thread. Nous avons étudié le code source gethostbyname de la glibc et avons constaté que le hook ne prend pas effet principalement parce que la glibc définit une méthode d'interrogation pour attendre les événements au lieu d'une méthode d'interrogation générale. En même temps, la glibc définit également une variable privée de thread entre laquelle basculer ; différentes coroutines. La réentrance peut entraîner des données inexactes. Enfin, l'asynchronisation de la coroutine gethostbyname est résolue grâce à la méthode Hook poll et à la définition de variables privées de la coroutine.
Gethostbyname est une interface DNS de requête synchrone fournie par la glibc. Il existe de nombreuses excellentes solutions asynchrones pour gethostbyname dans l'industrie, mais ces implémentations nécessitent l'introduction d'une bibliothèque tierce et nécessitent que la couche sous-jacente fournisse un mécanisme de notification de rappel asynchrone. . Grâce à la méthode hook, libco réalise l'asynchronisation de gethostbyname sans modifier le code source de la glibc.
Sémaphore coroutine
Dans un environnement multi-thread, nous aurons besoin d'une synchronisation entre les threads. Par exemple, l'exécution d'un thread doit attendre le signal d'un autre thread. Pour ce besoin, nous utilisons généralement. pthread_signal pour le résoudre. Dans libco, nous définissons le sémaphore de coroutine co_signal pour gérer les exigences de concurrence entre les coroutines. Une coroutine peut décider de notifier une coroutine en attente ou de réveiller toutes les coroutines en attente via co_cond_signal et co_cond_broadcast.
Résumé
Libco est une bibliothèque de coroutines c/c++ efficace qui fournit une interface de programmation de coroutines complète, des Hooks de fonction de la famille Socket couramment utilisés, etc., permettant aux entreprises d'utiliser des modèles de programmation synchrones pour un développement itératif rapide. Avec un fonctionnement stable au cours des dernières années, libco a joué un rôle central en tant que pierre angulaire du framework backend de WeChat.

[Recommandations associées]

1. Téléchargement du code source de la plateforme de compte public WeChat

2 Téléchargement gratuit du code source du système de commande Alizi<.>

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn