Les applications web sont désormais omniprésentes, et parmi tous les protocoles de transport, HTTP en occupe une grande partie. En explorant les subtilités du développement d'applications web, la plupart des gens accordent trÚs peu d'attention au systÚme d'exploitation sur lequel ces applications s'exécutent réellement. La séparation entre le développement (Dev) et l'exploitation (Ops) n'a fait qu'aggraver la situation. Cependant, avec la montée de la culture DevOps, les développeurs commencent à assumer la responsabilité de la mise en route de leurs applications dans le cloud. Il est donc trÚs utile pour eux de se familiariser en profondeur avec le backend du systÚme d'exploitation. Cela est particuliÚrement bénéfique si vous essayez de déployer un systÚme pour des milliers ou des dizaines de milliers de connexions simultanées.
Les restrictions dans les services web ressemblent beaucoup à celles rencontrées dans d'autres applications. Que ce soit les équilibreurs de charge ou les serveurs de bases de données, toutes ces applications présentent des problÚmes similaires dans un environnement hautes performances. Comprendre ces limitations fondamentales et les moyens de les surmonter permettra d'évaluer la performance et la scalabilité de vos applications web.
J'écris cette série d'articles en réponse aux questions de jeunes développeurs qui souhaitent devenir des architectes systÚmes bien informés. Il est impossible de comprendre clairement les méthodes d'optimisation des applications Linux sans plonger dans leurs fondements et leur fonctionnement au niveau du systÚme d'exploitation. Bien qu'il existe de nombreux types d'applications, dans ce cycle, je souhaite explorer les applications réseau plutÎt que les applications de bureau comme les navigateurs ou les éditeurs de texte. Ce matériel s'adresse aux développeurs et architectes qui souhaitent comprendre comment fonctionnent les programmes Linux ou Unix et comment les structurer pour des performances élevées.
Linux est un systĂšme d'exploitation serveur, et la plupart du temps, vos applications fonctionnent sur ce systĂšme d'exploitation. Bien que je dise « Linux », vous pouvez souvent supposer avec confiance que cela fait rĂ©fĂ©rence Ă toutes les systĂšmes d'exploitation de type Unix au sens large. Cependant, je n'ai pas testĂ© le code d'accompagnement sur d'autres systĂšmes. Donc, si vous ĂȘtes intĂ©ressĂ© par FreeBSD ou OpenBSD, les rĂ©sultats peuvent varier. Lorsque j'essaie quelque chose de spĂ©cifique Ă Linux, je l'indique.
Bien que vous puissiez utiliser les connaissances acquises pour crĂ©er une application depuis zĂ©ro, qui sera parfaitement optimisĂ©e, il est prĂ©fĂ©rable de ne pas le faire. Si vous Ă©crivez un nouveau serveur web en C ou C++ pour l'application commerciale de votre organisation, cela pourrait ĂȘtre votre dernier jour de travail. Cependant, connaĂźtre la structure de ces applications vous aidera Ă choisir parmi les programmes existants. Vous pourrez comparer les systĂšmes basĂ©s sur les processus avec ceux basĂ©s sur les threads, ainsi que sur les Ă©vĂ©nements. Vous comprendrez et apprĂ©cierez pourquoi Nginx fonctionne mieux qu'Apache httpd, et pourquoi une application Python basĂ©e sur Tornado peut servir plus d'utilisateurs qu'une application Python basĂ©e sur Django.
ZeroHTTPd : outil d'apprentissage
 â un serveur web que j'ai Ă©crit depuis zĂ©ro en C en tant qu'outil pĂ©dagogique. Il n'a aucune dĂ©pendance externe, y compris l'accĂšs Ă Redis. Nous exĂ©cutons nos propres procĂ©dures Redis. Pour plus de dĂ©tails, voir ci-dessous.
Bien que nous puissions discuter longuement de la thĂ©orie, rien ne vaut le fait d'Ă©crire du code, de l'exĂ©cuter et de comparer toutes les architectures de serveurs. C'est la mĂ©thode la plus illustrative. Par consĂ©quent, nous allons Ă©crire le simple serveur web ZeroHTTPd, en appliquant chaque modĂšle : basĂ© sur des processus, des threads et des Ă©vĂ©nements. Nous vĂ©rifierons chacun de ces serveurs et verrons comment ils fonctionnent les uns par rapport aux autres. ZeroHTTPd est implĂ©mentĂ© dans un seul fichier C. Le serveur basĂ© sur les Ă©vĂ©nements comprend , une excellente implĂ©mentation de table de hachage qui est fournie dans un seul fichier d'en-tĂȘte. Dans les autres cas, il n'y a aucune dĂ©pendance afin de ne pas compliquer le projet.
Le code contient de nombreux commentaires pour aider Ă la comprĂ©hension. Ătant un simple serveur web en quelques lignes de code, ZeroHTTPd sert Ă©galement de cadre minimal pour le dĂ©veloppement web. Il a une fonctionnalitĂ© limitĂ©e, mais il est capable de servir des fichiers statiques et des pages 'dynamiques' trĂšs simples. Je dois dire que ZeroHTTPd est bien adaptĂ© pour apprendre Ă crĂ©er des applications Linux haute performance. En principe, la plupart des services web attendent des requĂȘtes, les vĂ©rifient et les traitent. C'est exactement ce que fera ZeroHTTPd. C'est un outil d'apprentissage, pas un outil de production. Il n'est pas fort en gestion d'erreurs et n'a probablement pas les meilleures pratiques de sĂ©curitĂ© (oh oui, j'ai utilisĂ© strcpy) ou des tours de langage en C. Mais j'espĂšre qu'il s'en sortira bien avec sa tĂąche.

Page d'accueil de ZeroHTTPd. Il peut fournir différents types de fichiers, y compris des images.
Application de livre d'or
Les applications web modernes ne se limitent gĂ©nĂ©ralement pas aux fichiers statiques. Elles ont des interactions complexes avec diverses bases de donnĂ©es, caches, etc. Nous allons donc crĂ©er une simple application web appelĂ©e « Livre d'or », oĂč les visiteurs laissent des messages sous leurs noms. Le livre d'or conserve les messages laissĂ©s auparavant. Il y a aussi un compteur de visiteurs en bas de la page.

Application web « Livre d'or » ZeroHTTPd
Le compteur de visiteurs et les messages du livre d'or sont stockĂ©s dans Redis. Des procĂ©dures personnalisĂ©es ont Ă©tĂ© mises en place pour communiquer avec Redis, indĂ©pendamment des bibliothĂšques externes. Je ne suis pas un grand fan de dĂ©velopper un code maison alors qu'il existe des solutions publiques et bien testĂ©es. Mais l'objectif de ZeroHTTPd est d'explorer la performance de Linux et l'accĂšs aux services externes, tandis que le traitement des requĂȘtes HTTP a un impact significatif sur la performance. Nous devons contrĂŽler complĂštement les communications avec Redis dans chacune de nos architectures serveur. Dans une architecture, nous utilisons des appels bloquants, tandis que dans d'autres, nous utilisons des procĂ©dures basĂ©es sur les Ă©vĂ©nements. L'utilisation d'une bibliothĂšque cliente Redis externe ne fournirait pas un tel contrĂŽle. De plus, notre petit client Redis exĂ©cute seulement quelques fonctions (obtenir, configurer et incrĂ©menter une clĂ© ; obtenir et ajouter Ă un tableau). De plus, le protocole Redis est d'une Ă©lĂ©gance et d'une simplicitĂ© exceptionnelles. On n'a mĂȘme pas besoin d'apprendre spĂ©cifiquement Ă l'utiliser. Le fait que tout le travail du protocole soit rĂ©alisĂ© en environ cent lignes de code montre Ă quel point il est bien conçu.
La figure suivante montre les actions de l'application lorsque le client (navigateur) fait une demande. /guestbookURL.

Mécanisme de fonctionnement de l'application livre d'or
Lorsqu'il est nĂ©cessaire de dĂ©livrer une page du livre d'or, un appel est effectuĂ© au systĂšme de fichiers pour lire le modĂšle en mĂ©moire et trois appels rĂ©seau Ă Redis. Le fichier modĂšle contient la majeure partie du contenu HTML de la page visible sur la capture d'Ă©cran ci-dessus. Il y a Ă©galement des espaces rĂ©servĂ©s spĂ©ciaux pour la partie dynamique du contenu : les entrĂ©es et le compteur de visiteurs. Nous les rĂ©cupĂ©rons depuis Redis, les insĂ©rons sur la page et dĂ©livrons un contenu complĂštement formĂ© au client. Le troisiĂšme appel Ă Redis peut ĂȘtre Ă©vitĂ© car Redis renvoie une nouvelle valeur de la clĂ© lorsqu'elle est incrĂ©mentĂ©e. Cependant, pour notre serveur avec une architecture asynchrone basĂ©e sur des Ă©vĂ©nements, de nombreux appels rĂ©seau constituent une bonne Ă©preuve Ă des fins Ă©ducatives. Ainsi, nous dĂ©daignons la valeur renvoyĂ©e par Redis concernant le nombre de visiteurs et la demandons dans un appel sĂ©parĂ©.
Architectures serveurs ZeroHTTPd
Nous construisons sept versions de ZeroHTTPd avec des fonctionnalités identiques, mais avec des architectures différentes :
- Itérative
- Serveur fork (un processus fils par requĂȘte)
- Serveur pré-fork (forking de processus à l'avance)
- Serveur avec des threads d'exĂ©cution (un thread par requĂȘte)
- Serveur avec threads pré-créés
- Architecture basée sur
poll() - Architecture basée sur
epoll
Nous mesurons la performance de chaque architecture en chargeant le serveur avec des requĂȘtes HTTP. Mais lors de la comparaison des architectures avec un haut degrĂ© de parallĂ©lisme, le nombre de requĂȘtes augmente. Nous effectuons trois tests et calculons la moyenne.
Méthodologie de test

Configuration pour le test de charge de ZeroHTTPd
Il est important que, lors de l'exécution des tests, tous les composants ne fonctionnent pas sur une seule machine. Dans ce cas, le systÚme d'exploitation entraßne des frais généraux supplémentaires en raison de la planification, car les composants rivalisent pour le CPU. Mesurer les frais généraux du systÚme d'exploitation avec chacune des architectures serveur choisies est l'un des objectifs les plus importants de cet exercice. L'ajout de variables supplémentaires serait préjudiciable au processus. Par conséquent, la configuration illustrée ci-dessus fonctionne le mieux.
Que fait chacun de ces serveurs
- load.unixism.net : ici nous exécutons
ab, l'outil Apache Benchmark. Il gĂ©nĂšre la charge nĂ©cessaire pour tester nos architectures serveurs. - nginx.unixism.net : parfois, nous voulons exĂ©cuter plusieurs instances d'un programme serveur. Pour cela, le serveur Nginx, avec les configurations appropriĂ©es, fonctionne comme un rĂ©partiteur de charge recevant des requĂȘtes de ab nos processus serveur.
- zerohttpd.unixism.net : ici, nous exécutons nos programmes serveur sur sept architectures différentes, un à la fois.
- redis.unixism.net : sur ce serveur, le dĂ©mon Redis fonctionne, oĂč les enregistrements du livre d'or et le compteur de visiteurs sont stockĂ©s.
Tous les serveurs fonctionnent sur un seul cĆur de processeur. L'idĂ©e est d'Ă©valuer la performance maximale de chacune des architectures. Comme tous les programmes serveur sont testĂ©s sur le mĂȘme matĂ©riel, cela constitue une base pour leur comparaison. Mon installation de test se compose de serveurs virtuels louĂ©s chez Digital Ocean.
Qu'est-ce que nous mesurons ?
DiffĂ©rents indicateurs peuvent ĂȘtre mesurĂ©s. Nous Ă©valuons la performance de chaque architecture dans cette configuration, en chargeant les serveurs avec des requĂȘtes Ă diffĂ©rents niveaux de parallĂ©lisme : la charge augmente de 20 Ă 15 000 utilisateurs simultanĂ©s.
Résultats des tests
Le graphique suivant montre la performance des serveurs sur diffĂ©rentes architectures Ă divers niveaux de parallĂ©lisme. Sur l'axe y, le nombre de requĂȘtes par seconde, sur l'axe x, les connexions parallĂšles.



Ci-dessous, un tableau avec les résultats.
requĂȘtes par seconde
parallélisme
itératif
fork
pré-fork
threadé
pré-threadé
poll
epoll
20
7
112
2100
1800
2250
1900
2050
50
7
190
2200
1700
2200
2000
2000
100
7
245
2200
1700
2200
2150
2100
200
7
330
2300
1750
2300
2200
2100
300
â
380
2200
1800
2400
2250
2150
400
â
410
2200
1750
2600
2000
2000
500
â
440
2300
1850
2700
1900
2212
600
â
460
2400
1800
2500
1700
2519
700
â
460
2400
1600
2490
1550
2607
800
â
460
2400
1600
2540
1400
2553
900
â
460
2300
1600
2472
1200
2567
1000
â
475
2300
1700
2485
1150
2439
1500
â
490
2400
1550
2620
900
2479
2000
â
350
2400
1400
2396
550
2200
2500
â
280
2100
1300
2453
490
2262
3000
â
280
1900
1250
2502
large variation
2138
5000
â
large variation
1600
1100
2519
â
2235
8000
â
â
1200
large variation
2451
â
2100
10Â 000
â
â
large variation
â
2200
â
2200
11Â 000
â
â
â
â
2200
â
2122
12Â 000
â
â
â
â
970
â
1958
13Â 000
â
â
â
â
730
â
1897
14Â 000
â
â
â
â
590
â
1466
15Â 000
â
â
â
â
532
â
1281
D'aprĂšs le graphique et le tableau, on peut voir qu'au-delĂ de 8000 requĂȘtes simultanĂ©es, il ne reste que deux options : prĂ©-fork et epoll. Avec l'augmentation de la charge, le serveur basĂ© sur poll performe moins bien que le threadĂ©. L'architecture avec crĂ©ation anticipĂ©e de threads constitue une sĂ©rieuse concurrence pour epoll : cela tĂ©moigne de l'efficacitĂ© avec laquelle le noyau Linux gĂšre un grand nombre de threads.
Code source de ZeroHTTPd
Code source de ZeroHTTPd . Un répertoire distinct pour chaque architecture.
ZeroHTTPd
â
âââ 01_iterative
â âââ main.c
âââ 02_forking
â âââ main.c
âââ 03_preforking
â âââ main.c
âââ 04_threading
â âââ main.c
âââ 05_prethreading
â âââ main.c
âââ 06_poll
â âââ main.c
âââ 07_epoll
â âââ main.c
âââ Makefile
âââ public
â âââ index.html
â âââ tux.png
âââ templates
âââ guestbook
âââ index.htmlEn plus des sept rĂ©pertoires pour toutes les architectures, il y a deux autres dans le rĂ©pertoire racine : public et templates. Le premier contient le fichier index.html et l'image du premier Ă©cran. D'autres fichiers et dossiers peuvent y ĂȘtre placĂ©s, et ZeroHTTPd doit ĂȘtre capable de servir ces fichiers statiques sans problĂšme. Si le chemin dans le navigateur correspond au chemin dans le dossier public, ZeroHTTPd recherche le fichier index.html dans ce rĂ©pertoire. Le contenu du livre d'or est gĂ©nĂ©rĂ© dynamiquement. Il n'a qu'une seule page principale, dont le contenu est basĂ© sur le fichier 'templates/guestbook/index.html'. ZeroHTTPd permet d'ajouter facilement des pages dynamiques pour s'Ă©tendre. L'idĂ©e est que les utilisateurs peuvent ajouter des modĂšles dans ce rĂ©pertoire et Ă©tendre ZeroHTTPd au besoin.
Pour compiler les sept serveurs, exĂ©cutez make all depuis le rĂ©pertoire racine â et tous les builds apparaĂźtront dans ce rĂ©pertoire. Les fichiers exĂ©cutables recherchent les rĂ©pertoires public et templates dans le rĂ©pertoire depuis lequel ils sont lancĂ©s.
API Linux
Pour comprendre les informations dans ce cycle d'articles, il n'est pas nécessaire de bien connaßtre l'API Linux. Cependant, je recommande de lire davantage sur le sujet, il existe de nombreuses ressources de référence en ligne. Bien que nous abordions plusieurs catégories de l'API Linux, notre attention se concentrera principalement sur les processus, les threads, les événements et la pile réseau. En plus des livres et articles sur l'API Linux, je recommande également de lire les manuels pour les appels systÚme et les fonctions de bibliothÚque utilisées.
Performance et évolutivité
Une remarque sur la performance et l'Ă©volutivitĂ©. ThĂ©oriquement, il n'y a aucun lien entre les deux. Vous pouvez avoir un service web qui fonctionne trĂšs bien, avec un temps de rĂ©ponse de quelques millisecondes, mais qui n'est pas Ă©volutif du tout. De mĂȘme, une application web peu performante peut prendre plusieurs secondes pour rĂ©pondre, mais elle peut Ă©voluer pour gĂ©rer des dizaines de milliers d'utilisateurs simultanĂ©s. NĂ©anmoins, la combinaison d'une haute performance et d'une Ă©volutivitĂ© est une trĂšs puissante. Les applications hautes performances utilisent gĂ©nĂ©ralement les ressources de maniĂšre Ă©conomique et par consĂ©quent, gĂšrent efficacement un plus grand nombre d'utilisateurs simultanĂ©s sur le serveur, rĂ©duisant ainsi les coĂ»ts.
TĂąches CPU et I/O
Enfin, il existe toujours deux types possibles de tĂąches dans les calculs : celles liĂ©es Ă l'I/O et celles liĂ©es au CPU. La rĂ©ception de requĂȘtes via Internet (entrĂ©e/sortie rĂ©seau), la gestion de fichiers (entrĂ©e/sortie rĂ©seau et disque), les communications avec la base de donnĂ©es (entrĂ©e/sortie rĂ©seau et disque) - tout cela constitue des actions I/O. Certaines requĂȘtes Ă la base de donnĂ©es peuvent lĂ©gĂšrement solliciter le CPU (tri, calcul de la moyenne d'un million de rĂ©sultats, etc.). La plupart des applications web sont limitĂ©es par un I/O maximal, tandis que le processeur est rarement utilisĂ© Ă pleine capacitĂ©. Lorsque vous constatez qu'une tĂąche d'entrĂ©e/sortie utilise beaucoup de CPU, c'est probablement un signe d'une mauvaise architecture d'application. Cela peut signifier que les ressources CPU sont dĂ©pensĂ©es pour la gestion des processus et le changement de contexte - ce qui n'est pas particuliĂšrement utile. Si vous faites quelque chose comme le traitement d'images, la conversion de fichiers audio ou de l'apprentissage automatique, alors l'application nĂ©cessite une puissance CPU Ă©levĂ©e. Mais pour la plupart des applications, ce n'est pas le cas.
Plus de détails sur les architectures serveur
Source : habr.com
