Performances des applications réseau Linux. Introduction

Les applications Web sont désormais utilisées partout, et parmi tous les protocoles de transport, HTTP occupe la part du lion. Lorsqu’ils étudient les nuances 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 du développement (Dev) et des opérations (Ops) n’a fait qu’empirer la situation. Mais avec la montée de la culture DevOps, les développeurs deviennent responsables de l’exécution de leurs applications dans le cloud. Il est donc très utile pour eux de se familiariser parfaitement avec le backend du système d’exploitation. Ceci est particulièrement utile si vous essayez de déployer un système pour des milliers ou des dizaines de milliers de connexions simultanées.

Les limitations des services Web sont très similaires à celles des autres applications. Qu'il s'agisse d'équilibreurs de charge ou de serveurs de bases de données, toutes ces applications rencontrent des problèmes similaires dans un environnement hautes performances. Comprendre ces limitations fondamentales et comment les surmonter en général vous aidera à évaluer les performances et l'évolutivité 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ème avertis. Il est impossible de comprendre clairement les techniques d'optimisation des applications Linux sans plonger dans les bases de leur fonctionnement au niveau du système d'exploitation. Bien qu'il existe de nombreux types d'applications, dans cette série, je souhaite explorer les applications Web plutôt que les applications de bureau telles qu'un navigateur ou un éditeur de texte. Ce matériel est destiné aux développeurs et aux architectes qui souhaitent comprendre comment fonctionnent les programmes Linux ou Unix et comment les structurer pour des performances élevées.

Linux est salle des serveurs système d'exploitation, et le plus souvent vos applications s'exécutent sur ce système d'exploitation. Même si je dis "Linux", vous pouvez la plupart du temps supposer que je parle de tous les systèmes d'exploitation de type Unix en général. Cependant, je n'ai pas testé le code qui l'accompagne sur d'autres systèmes. Donc, si vous êtes intéressé par FreeBSD ou OpenBSD, vos résultats peuvent varier. Lorsque j'essaie quelque chose de spécifique à Linux, je le signale.

Même si vous pouvez utiliser ces connaissances pour créer une application à partir de zéro et qu'elle 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 métier de votre organisation, cela pourrait être votre dernier jour de travail. Cependant, connaître la structure de ces candidatures aidera à choisir les programmes existants. Vous serez en mesure de comparer les systèmes basés sur des processus avec des systèmes basés sur des threads ainsi qu'avec des systèmes basés sur des événements. Vous comprendrez et apprécierez pourquoi Nginx fonctionne mieux qu'Apache httpd, pourquoi une application Python basée sur Tornado peut servir plus d'utilisateurs par rapport à une application Python basée sur Django.

ZeroHTTPd : outil d'apprentissage

ZéroHTTPd est un serveur Web que j'ai écrit de toutes pièces en C comme outil pédagogique. Il n'a aucune dépendance externe, y compris l'accès à Redis. Nous exécutons nos propres procédures Redis. Voir ci-dessous pour plus de détails.

Même si nous pourrions aborder longuement la théorie, il n’y a rien de mieux que d’écrire du code, de l’exécuter et de comparer toutes les architectures de serveur entre elles. C'est la méthode la plus évidente. Par conséquent, nous allons écrire un simple serveur Web ZeroHTTPd en utilisant chaque modèle : basé sur les processus, basé sur les threads et basé sur les événements. Examinons chacun de ces serveurs et voyons 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 outhash, une excellente implémentation de table de hachage fournie dans un seul fichier d'en-tête. Dans d'autres cas, il n'y a pas de dépendances, afin de ne pas compliquer le projet.

Il y a beaucoup de commentaires dans le code pour vous aider à comprendre. Étant un simple serveur web en quelques lignes de code, ZeroHTTPd est également un framework minimal de développement web. Il a des fonctionnalités limitées, mais est capable de servir des fichiers statiques et des pages « dynamiques » très simples. Je dois dire que ZeroHTTPd est idéal pour apprendre à créer des applications Linux hautes performances. De manière générale, la plupart des services Web attendent les demandes, les vérifient et les traitent. C'est exactement ce que fera ZeroHTTPd. Il s’agit d’un outil d’apprentissage et non de production. Il n'est pas doué pour la gestion des erreurs et il est peu probable qu'il se vante des meilleures pratiques de sécurité (oh ouais, j'ai utilisé strcpy) ou les astuces astucieuses du langage C. Mais j'espère qu'il fait bien son travail.

Performances des applications réseau Linux. Introduction
Page d'accueil de ZeroHTTPd. Il peut produire différents types de fichiers, y compris des images

Demande de livre d'or

Les applications Web modernes ne se limitent généralement pas aux fichiers statiques. Ils ont des interactions complexes avec diverses bases de données, caches, etc. Nous allons donc créer une application Web simple appelée « Livre d'or » dans laquelle les visiteurs laissent des entrées sous leur nom. Le livre d'or stocke les entrées laissées plus tôt. Il y a également un compteur de visiteurs en bas de page.

Performances des applications réseau Linux. Introduction
Application web "Livre d'Or" ZeroHTTPd

Le compteur de visiteurs et les entrées du livre d'or sont stockés dans Redis. Pour les communications avec Redis, des procédures propres sont implémentées ; elles ne dépendent pas de la bibliothèque externe. Je ne suis pas un grand fan du déploiement de code homebrew alors qu'il existe des solutions accessibles au public et bien testées. Mais le but de ZeroHTTPd est d'étudier les performances de Linux et l'accès aux services externes, tandis que le traitement des requêtes HTTP a un impact sérieux sur les performances. Nous devons contrôler entièrement les communications avec Redis dans chacune de nos architectures de serveurs. Dans certaines architectures, nous utilisons des appels bloquants, dans d'autres, nous utilisons des procédures basées sur les événements. L'utilisation d'une bibliothèque client Redis externe ne fournira pas ce contrôle. De plus, notre petit client Redis n'exécute que quelques fonctions (obtenir, définir et incrémenter une clé ; obtenir et ajouter à un tableau). De plus, le protocole Redis est extrêmement élégant et simple. Vous n’avez même pas besoin de l’enseigner spécialement. Le fait même que le protocole fasse tout le travail en une centaine de lignes de code montre à quel point il est bien pensé.

La figure suivante montre ce que fait l'application lorsque le client (navigateur) demande /guestbookURL.

Performances des applications réseau Linux. Introduction
Comment fonctionne l'application de livre d'or

Lorsqu'une page de livre d'or doit être émise, il y a un appel au système de fichiers pour lire le modèle en mémoire et trois appels réseau vers Redis. Le fichier modèle contient la plupart du contenu HTML de la page dans la capture d'écran ci-dessus. Il existe également des espaces réservés spéciaux pour la partie dynamique du contenu : publications et compteur de visiteurs. Nous les recevons de Redis, les insérons dans la page et fournissons au client un contenu entièrement formé. Le troisième appel à Redis peut être évité car Redis renvoie la nouvelle valeur de clé lorsqu'elle est incrémentée. Cependant, pour notre serveur, qui possède une architecture asynchrone basée sur les événements, de nombreux appels réseau constituent un bon test à des fins d'apprentissage. Nous supprimons donc la valeur de retour Redis du nombre de visiteurs et l'interrogeons avec un appel séparé.

Architectures de serveur ZeroHTTPd

Nous construisons sept versions de ZeroHTTPd avec les mêmes fonctionnalités mais des architectures différentes :

  • Itératif
  • Serveur Fork (un processus enfant par requête)
  • Serveur pré-fork (pré-fork des processus)
  • Serveur avec threads d'exécution (un thread par requête)
  • Serveur avec création de pré-thread
  • Basé sur l'architecture poll()
  • Basé sur l'architecture epoll

Nous mesurons les performances de chaque architecture en chargeant le serveur avec des requêtes HTTP. Mais lorsque l’on compare des architectures hautement parallèles, le nombre de requêtes augmente. Nous testons trois fois et calculons la moyenne.

Méthodologie de test

Performances des applications réseau Linux. Introduction
Configuration des tests de charge ZeroHTTPd

Il est important que lors de l’exécution de tests, tous les composants ne s’exécutent pas sur la même machine. Dans ce cas, le système d'exploitation entraîne une surcharge de planification supplémentaire, car les composants sont en concurrence pour le processeur. Mesurer la surcharge du système d'exploitation de chacune des architectures de serveur sélectionnées est l'un des objectifs les plus importants de cet exercice. L'ajout de variables supplémentaires deviendra préjudiciable au processus. Par conséquent, le paramètre de l’image ci-dessus fonctionne mieux.

Que fait chacun de ces serveurs ?

  • load.unixism.net : C'est ici que nous exécutons ab, utilitaire Apache Benchmark. Il génère la charge nécessaire pour tester nos architectures de serveurs.
  • nginx.unixism.net : Parfois, nous souhaitons exécuter plusieurs instances d'un programme serveur. Pour ce faire, le serveur Nginx avec les paramètres appropriés fonctionne comme un équilibreur de charge provenant de ab à nos processus de serveur.
  • zerohttpd.unixism.net : Ici, nous exécutons nos programmes serveur sur sept architectures différentes, une à la fois.
  • redis.unixism.net : ce serveur exécute le démon Redis, où les entrées du livre d'or et les compteurs de visiteurs sont stockés.

Tous les serveurs fonctionnent sur le même cœur de processeur. L'idée est d'évaluer les performances maximales de chaque architecture. Étant donné que tous les programmes serveur sont testés sur le même matériel, il s’agit d’une base de comparaison. Ma configuration de test se compose de serveurs virtuels loués auprès de Digital Ocean.

Que mesure-t-on ?

Vous pouvez mesurer différents indicateurs. Nous évaluons les performances de chaque architecture dans une configuration donnée en chargeant les serveurs avec des requêtes à différents niveaux de parallélisme : la charge passe de 20 à 15 000 utilisateurs simultanés.

Résultats de test

Le graphique suivant montre les performances des serveurs sur différentes architectures à différents niveaux de parallélisme. L'axe des y représente le nombre de requêtes par seconde, l'axe des x représente les connexions parallèles.

Performances des applications réseau Linux. Introduction

Performances des applications réseau Linux. Introduction

Performances des applications réseau Linux. Introduction

Vous trouverez ci-dessous un tableau avec les résultats.

requêtes par seconde

concurrence
itératif
fourchette
pré-fourche
diffusion
pré-diffusion
po
époll

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
grande diffusion
2138

5000
-
grande diffusion
1600
1100
2519
-
2235

8000
-
-
1200
grande diffusion
2451
-
2100

10 000
-
-
grande diffusion
-
2200
-
2200

11 000
-
-
-
-
2200
-
2122

12 000
-
-
-
-
970
-
1958

13 000
-
-
-
-
730
-
1897

14 000
-
-
-
-
590
-
1466

15 000
-
-
-
-
532
-
1281

Le graphique et le tableau montrent qu'au-dessus de 8000 XNUMX requêtes simultanées, il ne nous reste plus que deux joueurs : pre-fork et epoll. À mesure que la charge augmente, un serveur basé sur des sondages est moins performant qu'un serveur de streaming. L'architecture de pré-création de threads est un digne concurrent d'epoll, ce qui témoigne de la façon dont le noyau Linux planifie un grand nombre de threads.

Code source de ZeroHTTPd

Code source de ZeroHTTPd ici. Il existe un répertoire distinct pour chaque architecture.

ZeroHTTPd │ ├── 01_iterative │ ├── main.c ├── 02_forking │ ├── main.c ├── 03_preforking │ ├── main.c ├── 04_thread ing │ ├── main.c ├── 05_prethreading │ ├── main.c ├── 06_poll │ ├── main.c ├── 07_epoll │ └── main.c ├── Makefile ├── public │ ├ ── index.html │ └── smoking . png └── modèles └── livre d'or └── index.html

En plus des sept répertoires pour toutes les architectures, il y en a deux autres dans le répertoire de niveau supérieur : public et templates. Le premier contient le fichier index.html et l'image de la première capture d'écran. Vous pouvez y placer d'autres fichiers et dossiers, et ZeroHTTPd devrait servir ces fichiers statiques sans aucun problème. Si le chemin dans le navigateur correspond au chemin dans le dossier public, alors 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 page d'accueil et son contenu est basé sur le fichier 'templates/guestbook/index.html'. ZeroHTTPd ajoute facilement des pages dynamiques pour l'extension. L'idée est que les utilisateurs peuvent ajouter des modèles à ce répertoire et étendre ZeroHTTPd selon leurs besoins.

Pour créer les sept serveurs, exécutez make all à partir du répertoire de niveau supérieur - et toutes les versions apparaîtront dans ce répertoire. Les fichiers exécutables recherchent les répertoires public et templates dans le répertoire à partir duquel ils sont lancés.

API Linux

Vous n'avez pas besoin de bien connaître l'API Linux pour comprendre les informations contenues dans cette série d'articles. Cependant, je recommande de lire davantage sur ce sujet : il existe de nombreuses ressources de référence sur Internet. Bien que nous aborderons plusieurs catégories d'API Linux, nous nous concentrerons 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 le mana pour les appels système et les fonctions de bibliothèque utilisées.

Performances et évolutivité

Une remarque sur les performances et l’évolutivité. Théoriquement, il n’y a aucun lien entre eux. Vous pouvez avoir un service web qui fonctionne très bien, avec un temps de réponse de quelques millisecondes, mais il n'est pas du tout évolutif. De même, il peut y avoir une application Web peu performante qui met quelques secondes à répondre, mais qui évolue par dizaines pour gérer des dizaines de milliers d'utilisateurs simultanés. Cependant, la combinaison de hautes performances et d’évolutivité constitue une combinaison très puissante. Les applications hautes performances utilisent généralement les ressources avec parcimonie et servent ainsi efficacement davantage d'utilisateurs simultanés sur le serveur, réduisant ainsi les coûts.

Tâches CPU et E/S

Enfin, en informatique, il existe toujours deux types de tâches possibles : pour les E/S et le CPU. Recevoir des requêtes sur Internet (E/S réseau), servir des fichiers (E/S réseau et disque), communiquer avec la base de données (E/S réseau et disque) sont toutes des activités d'E/S. Certaines requêtes de base de données peuvent être un peu gourmandes en CPU (tri, moyenne d'un million de résultats, etc.). La plupart des applications Web sont limitées par le nombre maximal d'E/S possibles et le processeur est rarement utilisé à pleine capacité. Lorsque vous constatez qu’une tâche d’E/S utilise beaucoup de CPU, c’est probablement le signe d’une mauvaise architecture d’application. Cela peut signifier que les ressources du processeur sont gaspillées pour la gestion des processus et le changement de contexte - et cela n'est pas entièrement utile. Si vous effectuez quelque chose comme le traitement d'images, la conversion de fichiers audio ou l'apprentissage automatique, l'application nécessite de puissantes ressources CPU. Mais pour la plupart des applications, ce n’est pas le cas.

En savoir plus sur les architectures de serveur

  1. Partie I : Architecture itérative
  2. Deuxieme PARTIE. Serveurs fork
  3. Partie III. Serveurs pré-fork
  4. Partie IV. Serveurs avec threads d'exécution
  5. Partie V. Serveurs pré-threadés
  6. Partie VI. Architecture basée sur Pol
  7. Partie VII. architecture basée sur epoll

Source: habr.com

Ajouter un commentaire