Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung

Webanwendungen sind heutzutage weit verbreitet, und unter allen Transportprotokollen hat HTTP den grĂ¶ĂŸten Anteil. Bei der Entwicklung von Webanwendungen schenken die meisten der zugrunde liegenden Betriebssystemumgebung wenig Beachtung. Die Trennung zwischen Entwicklung (Dev) und Betrieb (Ops) hat die Situation zusĂ€tzlich erschwert. Mit der Verbreitung der DevOps-Kultur ĂŒbernehmen Entwickler jedoch zunehmend Verantwortung fĂŒr das Betreiben ihrer Anwendungen in der Cloud, weshalb ein vertieftes VerstĂ€ndnis der Backend-Umgebung des Betriebssystems Ă€ußerst vorteilhaft ist. Dies ist besonders wichtig, wenn Sie ein System fĂŒr tausende oder sogar zehntausende gleichzeitige Verbindungen bereitstellen möchten.

Die EinschrĂ€nkungen in Webdiensten Ă€hneln stark denen anderer Anwendungen. Ob Lastenausgleich oder Datenbankserver, diese Anwendungen haben in leistungsstarken Umgebungen Ă€hnliche Herausforderungen. Das VerstĂ€ndnis dieser grundlegenden EinschrĂ€nkungen und der Möglichkeiten zu ihrer Überwindung ermöglicht es insgesamt, die Leistung und Skalierbarkeit Ihrer Webanwendungen besser zu bewerten.

Ich schreibe diese Artikelreihe als Antwort auf die Fragen junger Entwickler, die gut informierte Systemarchitekten werden möchten. Man kann die Methoden zur Optimierung von Linux-Anwendungen nicht klar verstehen, ohne in die Grundlagen einzutauchen und zu verstehen, wie sie auf Betriebssystemebene funktionieren. Obwohl es viele Arten von Anwendungen gibt, möchte ich in diesem Zyklus Netzwerk-Anwendungen untersuchen und nicht Desktop-Anwendungen wie Browser oder Texteditoren. Dieses Material richtet sich an Entwickler und Architekten, die verstehen möchten, wie Programme unter Linux oder Unix funktionieren und wie man sie fĂŒr höchste Leistung strukturiert.

Linux ist ein Server- Betriebssystem, und am hĂ€ufigsten laufen Ihre Anwendungen genau auf diesem OS. Obwohl ich „Linux“ sage, können Sie die meiste Zeit mit Sicherheit annehmen, dass alle Unix-Ă€hnlichen Betriebssysteme im Allgemeinen gemeint sind. Ich habe den begleitenden Code allerdings nicht auf anderen Systemen getestet. Wenn Sie also an FreeBSD oder OpenBSD interessiert sind, können die Ergebnisse abweichen. Wenn ich etwas spezifisch fĂŒr Linux ausprobiere, mache ich darauf aufmerksam.

Obwohl Sie das Wissen nutzen können, um eine Anwendung von Grund auf neu zu erstellen, und diese hervorragend optimiert sein wird, ist es besser, dies zu vermeiden. Wenn Sie einen neuen Webserver in C oder C++ fĂŒr die GeschĂ€ftsapplication Ihrer Organisation schreiben, könnte dies Ihr letzter Arbeitstag sein. Allerdings wird Ihnen das VerstĂ€ndnis der Struktur dieser Anwendungen bei der Auswahl bereits existierender Software helfen. Sie können Systeme basierend auf Prozessen mit solchen auf Basis von Threads sowie Event-basierten Systemen vergleichen. Sie werden verstehen und nachvollziehen können, warum Nginx besser funktioniert als Apache httpd und warum eine Python-Anwendung auf Basis von Tornado mehr Benutzer bedienen kann als eine Python-Anwendung, die auf Django basiert.

ZeroHTTPd: Lernwerkzeug

ZeroHTTPd — ein Webserver, den ich von Grund auf in C als Lernwerkzeug geschrieben habe. Er hat keine externen AbhĂ€ngigkeiten, einschließlich des Zugriffs auf Redis. Wir fĂŒhren unsere eigenen Redis-Prozeduren aus. Weitere Informationen s. unten.

Obwohl wir lange ĂŒber die Theorie diskutieren könnten, gibt es nichts Besseres, als Code zu schreiben, ihn auszufĂŒhren und die verschiedenen Serverarchitekturen miteinander zu vergleichen. Das ist die anschaulichste Methode. Daher werden wir einen einfachen Webserver namens ZeroHTTPd erstellen, indem wir jedes Modell anwenden: auf der Basis von Prozessen, Threads und Ereignissen. Wir ĂŒberprĂŒfen jeden dieser Server und sehen, wie sie im Vergleich zueinander funktionieren. ZeroHTTPd ist in einer einzigen C-Datei implementiert. Der ereignisbasierte Server umfasst uthash, eine hervorragende Implementierung einer Hash-Tabelle, die in einer einzigen Header-Datei bereitgestellt wird. Ansonsten gibt es keine AbhĂ€ngigkeiten, um das Projekt nicht zu komplizieren.

Der Code enthĂ€lt zahlreiche Kommentare, die beim VerstĂ€ndnis helfen. ZeroHTTPd, als einfacher Webserver und minimaler Rahmen fĂŒr Webentwicklung, bietet grundsĂ€tzlich eine eingeschrĂ€nkte FunktionalitĂ€t, kann jedoch statische Dateien sowie sehr einfache 'dynamische' Seiten ausgeben. Ich muss sagen, dass ZeroHTTPd sich gut fĂŒr das Lernen eignet, wie man leistungsstarke Linux-Anwendungen erstellt. Im Grunde genommen warten die meisten Webdienste auf Anfragen, ĂŒberprĂŒfen diese und verarbeiten sie. Genau das wird ZeroHTTPd tun. Es ist ein Lernwerkzeug und kein Produktivsystem. Es ist nicht besonders gut im Fehlermanagement und kann kaum mit den besten Sicherheitspraktiken aufwarten (oh ja, ich habe strcpy verwendet) oder mit ausgeklĂŒgelten Tricks der Programmiersprache C. Aber ich hoffe, dass es seinen Zweck gut erfĂŒllt. strcpy) oder mit ausgeklĂŒgelten Tricks der Programmiersprache C. Aber ich hoffe, dass es seinen Zweck gut erfĂŒllt.

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung
Startseite von ZeroHTTPd. Es kann verschiedene Dateitypen ausgeben, einschließlich Bilder.

GĂ€stebuch-Anwendung

Moderne Webanwendungen beschrĂ€nken sich in der Regel nicht auf statische Dateien. Sie umfassen komplexe Interaktionen mit verschiedenen Datenbanken, Caches usw. Daher erstellen wir eine einfache Webanwendung mit dem Namen „GĂ€stebuch“, in dem Besucher EintrĂ€ge unter ihrem Namen hinterlassen können. Im GĂ€stebuch werden die zuvor hinterlassenen EintrĂ€ge gespeichert. Außerdem gibt es einen BesucherzĂ€hler am unteren Rand der Seite.

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung
Webanwendung „GĂ€stebuch“ ZeroHTTPd

Der BesucherzĂ€hler und das GĂ€stebuch werden in Redis gespeichert. FĂŒr die Kommunikation mit Redis haben wir eigene Verfahren implementiert, die unabhĂ€ngig von externen Bibliotheken sind. Ich bin kein großer Fan davon, selbstentwickelten Code einzufĂŒhren, wenn es öffentliche und gut getestete Lösungen gibt. Aber das Ziel von ZeroHTTPd ist, die Leistung von Linux und den Zugriff auf externe Dienste zu untersuchen, wĂ€hrend die Bearbeitung von HTTP-Anfragen die Leistung erheblich beeinflusst. Wir mĂŒssen die Kommunikation mit Redis in jeder unserer Serverarchitekturen vollstĂ€ndig kontrollieren. In einer Architektur verwenden wir blockierende Aufrufe, in anderen ereignisbasierte Prozeduren. Die Verwendung einer externen Redis-Clientbibliothek wĂŒrde uns nicht diesen Kontrollgrad bieten. Außerdem fĂŒhrt unser kleiner Redis-Client nur eine Handvoll Funktionen aus (Abrufen, Setzen und Erhöhen eines SchlĂŒssels; Abrufen und HinzufĂŒgen zu einem Array). Zudem ist das Redis-Protokoll außergewöhnlich elegant und einfach. Man muss es nicht einmal speziell lernen. Die Tatsache, dass das gesamte Protokoll in etwa einhundert Zeilen Code implementiert ist, zeigt, wie durchdacht es ist.

Im nÀchsten Bild sind die VorgÀnge der Anwendung dargestellt, wenn ein Kunde (Browser) eine Anfrage stellt. /guestbookURL.

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung
Funktionsweise der GĂ€stebuch-Anwendung

Wenn die GĂ€stebuch-Seite ausgegeben werden soll, erfolgt ein Aufruf an das Dateisystem, um die Vorlage in den Speicher zu laden, sowie drei Netzwerkaufrufe an Redis. Die Vorlagendatei enthĂ€lt den Großteil des HTML-Inhalts fĂŒr die Seite im obigen Screenshot. Es gibt auch spezielle Platzhalter fĂŒr den dynamischen Teil des Inhalts: EintrĂ€ge und die BesuchszĂ€hler. Wir holen diese von Redis, fĂŒgen sie auf der Seite ein und liefern dem Kunden den vollstĂ€ndig formatierten Inhalt. Der dritte Aufruf an Redis kann vermieden werden, da Redis beim Inkrementieren einen neuen Wert des SchlĂŒssels zurĂŒckgibt. Allerdings stellt eine Vielzahl von Netzwerkaufrufen fĂŒr unseren auf Ereignissen basierenden asynchronen Server eine gute Herausforderung zu Lernzwecken dar. Daher lassen wir den zurĂŒckgegebenen Wert von Redis ĂŒber die Anzahl der Besucher weg und fordern ihn in einem separaten Aufruf an.

Serverarchitekturen von ZeroHTTPd

Wir erstellen sieben Versionen von ZeroHTTPd mit identischer FunktionalitÀt, jedoch unterschiedlichen Architekturen:

  • Iterativ
  • Fork-Server (ein Kindprozess pro Anfrage)
  • Pre-Fork-Server (vorbereitendes Forking der Prozesse)
  • Server mit AusfĂŒhrungsströmen (ein Thread pro Anfrage)
  • Server mit vorab erstellten Strömen
  • Architektur basierend auf poll()
  • Architektur basierend auf epoll

Wir messen die Leistung jeder Architektur, indem wir den Server mit HTTP-Anfragen belasten. Bei den Vergleichen von Architekturen mit hohem Parallelismus steigt die Anzahl der Anfragen. Wir testen dreimal und berechnen den Durchschnitt.

Testmethodologie

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung
Einrichtung fĂŒr Lasttests von ZeroHTTPd

Es ist wichtig, dass bei der DurchfĂŒhrung der Tests nicht alle Komponenten auf einer einzigen Maschine laufen. In diesem Fall ergeben sich zusĂ€tzliche Betriebssystemkosten durch das Scheduling, da die Komponenten um die CPU konkurrieren. Die Messung der Betriebssystemkosten mit jeder der ausgewĂ€hlten Serverarchitekturen ist eines der Hauptziele dieser Übung. Das HinzufĂŒgen weiterer Variablen kann den Prozess beeintrĂ€chtigen. Folglich funktioniert die oben gezeigte Konfiguration am besten.

Was jeder dieser Server tut

  • load.unixism.net: hier starten wir ab, das Tool Apache Benchmark. Es erzeugt die notwendige Last, um unsere Serverarchitekturen zu testen.
  • nginx.unixism.net: Manchmal möchten wir mehr als eine Instanz des Serverprogramms betreiben. Dazu fungiert der Nginx-Server mit entsprechenden Einstellungen als Lastverteiler fĂŒr die ankommenden Anfragen ab an unsere Serverprozesse.
  • zerohttpd.unixism.net: Hier betreiben wir unsere Serverprogramme auf sieben verschiedenen Architekturen, allerdings jeweils nur eine zur selben Zeit.
  • redis.unixism.net: Auf diesem Server lĂ€uft der Redis-Daemon, in dem die EintrĂ€ge des GĂ€stebuchs sowie der BesucherzĂ€hler gespeichert werden.

Alle Server arbeiten auf einem einzelnen Prozessorkern. Die Idee dahinter ist, die maximale Leistung jeder Architektur zu bewerten. Da alle Serverprogramme auf derselben Hardware getestet werden, ergibt sich hier ein Grundniveau fĂŒr deren Vergleich. Mein Testaufbau besteht aus virtuellen Servern, die ich bei Digital Ocean angemietet habe.

Was messen wir?

Es können verschiedene Metriken gemessen werden. Wir bewerten die Leistung jeder Architektur in dieser Konfiguration, indem wir die Server mit Anfragen bei unterschiedlichen ParallelitÀtsstufen belasten: die Last steigt von 20 bis zu 15.000 gleichzeitigen Benutzern.

Testergebnisse

Das folgende Diagramm zeigt die Leistung von Servern auf verschiedenen Architekturen bei unterschiedlichen ParallelitĂ€tsstufen. Auf der y-Achse – Anfragen pro Sekunde, auf der x-Achse – parallele Verbindungen.

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung

Leistung von Netzwerkapplikationen unter Linux. EinfĂŒhrung

Nachfolgend eine Tabelle mit den Ergebnissen.

Anfragen pro Sekunde

ParallelitÀt
iterativ
Fork
Pre-Fork
Threading
Pre-Threading
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
große Streuung
2138

5000
–
große Streuung
1600
1100
2519
–
2235

8000
–
–
1200
große Streuung
2451
–
2100

10 000
–
–
große Streuung
–
2200
–
2200

11 000
–
–
–
–
2200
–
2122

12 000
–
–
–
–
970
–
1958

13 000
–
–
–
–
730
–
1897

14 000
–
–
–
–
590
–
1466

15 000
–
–
–
–
532
–
1281

Aus dem Diagramm und der Tabelle geht hervor, dass bei mehr als 8000 gleichzeitigen Anfragen nur zwei Architekturen konkurrenzfĂ€hig bleiben: Pre-Fork und Epoll. Mit zunehmender Last schneidet der Poll-Server schlechter ab als der Threading-Server. Die Architektur mit vorab erstellten Threads konkurriert auf hohem Niveau mit Epoll: Das belegt, wie gut der Linux-Kernel eine große Anzahl an Threads verwalten kann.

Der Quellcode von ZeroHTTPd

Der Quellcode von ZeroHTTPd hier. FĂŒr jede Architektur gibt es ein eigenes Verzeichnis.

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.html

Neben den sieben Verzeichnissen fĂŒr alle Architekturen gibt es im Hauptverzeichnis noch zwei weitere: public und templates. Im ersten liegt die Datei index.html sowie ein Bild vom ersten Screenshot. Dort können weitere Dateien und Ordner platziert werden, und ZeroHTTPd sollte diese statischen Dateien problemlos bereitstellen. Wenn der Pfad im Browser mit dem Pfad im public-Ordner ĂŒbereinstimmt, sucht ZeroHTTPd in diesem Verzeichnis nach der Datei index.html. Der Inhalt fĂŒr das GĂ€stebuch wird dynamisch generiert. Es gibt nur die Hauptseite, deren Inhalt auf der Datei ‘templates/guestbook/index.html’ basiert. Dynamische Seiten lassen sich in ZeroHTTPd problemlos hinzufĂŒgen, sodass Benutzer in diesem Verzeichnis Templates hinzufĂŒgen und ZeroHTTPd bei Bedarf erweitern können.

Um alle sieben Server zu erstellen, starten Sie make all aus dem Hauptverzeichnis – und alle Builds erscheinen in diesem Verzeichnis. Die ausfĂŒhrbaren Dateien suchen die Verzeichnisse public und templates in dem Verzeichnis, aus dem sie gestartet werden.

Linux API

Um die Informationen in diesem Artikelzyklus zu verstehen, ist es nicht notwendig, sich gut im Linux API auszukennen. Ich empfehle jedoch, mehr zu diesem Thema zu lesen, da es viele Ressourcen im Internet gibt. Obwohl wir einige Kategorien des Linux API ansprechen werden, liegt unser Fokus hauptsĂ€chlich auf Prozessen, Threads, Ereignissen und dem Netzwerk-Stack. Neben BĂŒchern und Artikeln ĂŒber das Linux API empfehle ich auch, die Man-Pages fĂŒr Systemaufrufe und verwendete Bibliotheksfunktionen zu lesen.

Leistung und Skalierbarkeit

Eine Anmerkung zur Performance und Skalierbarkeit. Theoretisch gibt es keinen direkten Zusammenhang zwischen den beiden. Sie können einen Webdienst haben, der sehr gut funktioniert, mit Reaktionszeiten von wenigen Millisekunden, aber nicht skalierbar ist. genauso kann es eine schlecht funktionierende Webanwendung geben, die mehrere Sekunden fĂŒr eine Antwort benötigt, aber in der Lage ist, auf Hunderte zu skalieren, um Zehntausende von gleichzeitigen Benutzern zu bedienen. Dennoch ist die Kombination aus hoher Performance und Skalierbarkeit eine sehr starke Kombination. Hochleistungsanwendungen nutzen im Allgemeinen Ressourcen effizient, was bedeutet, dass sie mehr gleichzeitige Benutzer auf einem Server bedienen können und so die Kosten senken.

CPU- und I/O-Aufgaben

Bei Berechnungen gibt es zwei grundlegende Arten von Aufgaben: I/O und CPU. Anfragen ĂŒber das Internet (Netzwerk-I/O), Dateiverwaltung (Netzwerk- und Festplattendatenverarbeitung) sowie Datenbankkommunikation (Netzwerk- und Festplattendatenverarbeitung) zĂ€hlen zu den I/O-AktivitĂ€ten. Einige Datenbankanfragen können die CPU geringfĂŒgig belasten (zum Beispiel Sortierung, Berechnung des Durchschnitts von Millionen von Ergebnissen usw.). Die meisten Webanwendungen sind in Bezug auf das maximal mögliche I/O eingeschrĂ€nkt, wĂ€hrend die CPU selten voll ausgelastet wird. Wenn Sie bei einer I/O-Aufgabe feststellen, dass viel CPU verwendet wird, deutet das oft auf eine ineffiziente Architektur der Anwendung hin. Dies kann darauf hindeuten, dass CPU-Ressourcen fĂŒr Prozessmanagement und Kontextwechsel verwendet werden – was nicht besonders vorteilhaft ist. Wenn Sie jedoch etwas wie Bildbearbeitung, Audioverarbeitung oder maschinelles Lernen durchfĂŒhren, benötigt die Anwendung leistungsstarke CPU-Ressourcen. Aber fĂŒr die meisten Anwendungen ist das nicht der Fall.

Weitere Informationen zu Serverarchitekturen

  1. Teil I. Iterative Architektur
  2. Teil II. Fork-Server
  3. Teil III. Pre-Fork-Server
  4. Teil IV. Server mit AusfĂŒhrungsströmen
  5. Teil V. Server mit vorab erstellten Strömen
  6. Teil VI. Architektur basierend auf Poll
  7. Teil VII. Architektur basierend auf Epoll

Quelle: habr.com

Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Servern đŸ”„ Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Servern | ProHoster