Server-Lastausgleichsarchitekturen, Teil 1: Lastausgleich auf Transportebene

Serverfarmen erreichen eine hohe Skalierbarkeit und hohe Verfügbarkeit durch Serverlastenausgleich, eine Technik, mit der die Serverfarm für Clients als einzelner Server angezeigt wird. In diesem zweiteiligen Artikel untersucht Gregor Roth Architekturen für den Lastausgleich von Servern, wobei der Schwerpunkt auf Open Source-Lösungen liegt. Teil 1 behandelt die Grundlagen des Server-Lastausgleichs und erläutert die Vor- und Nachteile des Server-Lastausgleichs auf Transportebene. Teil 2 behandelt Server-Lastausgleichsarchitekturen auf Anwendungsebene, die einige der Einschränkungen der in Teil 1 beschriebenen Architekturen behandeln.

Die Eintrittsbarriere für viele Internetunternehmen ist gering. Jeder, der eine gute Idee hat, kann eine kleine Anwendung entwickeln, einen Domainnamen erwerben und einige PC-basierte Server einrichten, um eingehenden Datenverkehr zu verarbeiten. Die Anfangsinvestition ist gering, so dass das Anlaufrisiko minimal ist. Eine erfolgreiche kostengünstige Infrastruktur kann jedoch schnell zu einem ernsthaften Problem werden. Ein einzelner Server, der alle eingehenden Anforderungen verarbeitet, ist möglicherweise nicht in der Lage, hohe Verkehrsmengen zu verarbeiten, sobald das Unternehmen populär wird. In solchen Situationen beginnen Unternehmen häufig mit der Skalierung : Sie aktualisieren die vorhandene Infrastruktur, indem sie eine größere Box mit mehr Prozessoren kaufen oder mehr Speicher hinzufügen, um die Anwendungen auszuführen.

Eine Skalierung ist jedoch nur eine kurzfristige Lösung. Dies ist ein begrenzter Ansatz, da die Kosten für ein Upgrade im Verhältnis zu den Verbesserungen der Serverfähigkeit unverhältnismäßig hoch sind. Aus diesen Gründen verfolgen die meisten erfolgreichen Internetunternehmen einen Scale-out- Ansatz. Anwendungskomponenten werden in Serverfarmen, die auf kostengünstiger Hardware und Betriebssystemen basieren, als mehrere Instanzen verarbeitet. Mit zunehmendem Datenverkehr werden Server hinzugefügt.

Der Server-Farm-Ansatz hat seine eigenen Anforderungen. Auf der Softwareseite müssen Sie Anwendungen so entwerfen, dass sie als mehrere Instanzen auf verschiedenen Servern ausgeführt werden können. Dazu teilen Sie die Anwendung in kleinere Komponenten auf, die unabhängig voneinander bereitgestellt werden können. Dies ist trivial, wenn die Anwendungskomponenten zustandslos sind. Da die Komponenten keinen Transaktionsstatus beibehalten, kann jede von ihnen dieselben Anforderungen gleichermaßen verarbeiten. Wenn mehr Rechenleistung erforderlich ist, fügen Sie einfach weitere Server hinzu und installieren die Anwendungskomponenten.

Ein schwierigeres Problem tritt auf, wenn die Anwendungskomponenten zustandsbehaftet sind. Wenn die Anwendungskomponente beispielsweise Warenkorbedaten enthält, muss eine eingehende Anforderung an eine Anwendungskomponenteninstanz weitergeleitet werden, die die Warenkorbdaten dieses Anforderers enthält. Später in diesem Artikel werde ich erläutern, wie solche Anwendungssitzungsdaten in einer verteilten Umgebung behandelt werden. Um die Komplexität zu verringern, versuchen die meisten erfolgreichen internetbasierten Anwendungssysteme jedoch, wenn immer möglich, statusbehaftete Anwendungskomponenten zu vermeiden.

Auf der Infrastrukturseite muss die Verarbeitungslast auf die Servergruppe verteilt werden. Dies wird als Server-Lastausgleich bezeichnet. Lastausgleichstechnologien beziehen sich auch auf andere Domänen, z. B. die Verteilung der Arbeit auf Komponenten wie Netzwerkverbindungen, CPUs oder Festplatten. Dieser Artikel konzentriert sich auf den Serverlastenausgleich.

Verfügbarkeit und Skalierbarkeit

Der Serverlastenausgleich verteilt Dienstanforderungen auf eine Gruppe realer Server und lässt diese Server für die Clients wie einen einzelnen großen Server aussehen. Oft befinden sich Dutzende realer Server hinter einer URL, die einen einzelnen virtuellen Dienst implementiert.

Wie funktioniert das? In einer weit verbreiteten Server-Load-Balancing-Architektur wird die eingehende Anforderung an einen dedizierten Server-Load-Balancer geleitet, der für den Client transparent ist. Basierend auf Parametern wie Verfügbarkeit oder aktueller Serverlast entscheidet der Load Balancer, welcher Server die Anforderung verarbeiten soll, und leitet sie an den ausgewählten Server weiter. Um dem Lastausgleichsalgorithmus die erforderlichen Eingabedaten bereitzustellen, ruft der Lastausgleich auch Informationen über den Zustand und die Last der Server ab, um zu überprüfen, ob sie auf Datenverkehr reagieren können. Abbildung 1 zeigt diese klassische Load-Balancer-Architektur.

Die in Abbildung 1 dargestellte Load-Dispatcher-Architektur ist nur einer von mehreren Ansätzen. Um zu entscheiden, welche Lastausgleichslösung für Ihre Infrastruktur am besten geeignet ist, müssen Sie Verfügbarkeit und Skalierbarkeit berücksichtigen .

Die Verfügbarkeit wird durch definierte Verfügbarkeit - die Zeit zwischen Ausfällen. (Ausfallzeit ist die Zeit, um den Fehler zu erkennen, zu reparieren, die erforderliche Wiederherstellung durchzuführen und Aufgaben neu zu starten.) Während der Betriebszeit muss das System auf jede Anforderung innerhalb einer festgelegten, genau definierten Zeit reagieren. Wenn diese Zeit überschritten wird, sieht der Client dies als Serverstörung an. Hochverfügbarkeit ist im Grunde genommen Redundanz im System: Wenn ein Server ausfällt, übernehmen die anderen die Last des ausgefallenen Servers transparent. Der Ausfall eines einzelnen Servers ist für den Client nicht sichtbar.

Skalierbarkeit bedeutet, dass das System einen einzelnen Client sowie Tausende von Clients gleichzeitig bedienen kann, indem es die Anforderungen an die Servicequalität wie die Antwortzeit erfüllt. Unter einer erhöhten Last kann ein hoch skalierbares System den Durchsatz im Verhältnis zur Leistung der hinzugefügten Hardwareressourcen nahezu linear erhöhen.

In dem Szenario in Abbildung 1 wird eine hohe Skalierbarkeit erreicht, indem die eingehende Anforderung auf die Server verteilt wird. Wenn die Last steigt, können zusätzliche Server hinzugefügt werden, solange der Load Balancer nicht zum Engpass wird. Um eine hohe Verfügbarkeit zu erreichen, muss der Load Balancer die Server überwachen, um zu vermeiden, dass Anforderungen an überlastete oder tote Server weitergeleitet werden. Darüber hinaus muss auch der Load Balancer selbst redundant sein. Ich werde diesen Punkt später in diesem Artikel diskutieren.

Techniken zum Server-Lastausgleich

Im Allgemeinen gibt es zwei Haupttypen von Server-Lastausgleichslösungen:

  • Der Lastausgleich auf Transportebene - wie der DNS-basierte Ansatz oder der Lastausgleich auf TCP / IP-Ebene - erfolgt unabhängig von der Nutzlast der Anwendung.
  • Der Lastausgleich auf Anwendungsebene verwendet die Anwendungsnutzlast, um Entscheidungen zum Lastausgleich zu treffen.

Lastausgleichslösungen können weiter in softwarebasierte Lastausgleicher und hardwarebasierte Lastausgleicher unterteilt werden. Hardwarebasierte Load Balancer sind spezielle Hardware-Boxen, die anwendungsspezifische integrierte Schaltkreise (ASICs) enthalten, die für eine bestimmte Verwendung angepasst sind. ASICs ermöglichen die Hochgeschwindigkeitsweiterleitung des Netzwerkverkehrs ohne den Aufwand eines Allzweckbetriebssystems. Hardwarebasierte Lastausgleicher werden häufig für den Lastausgleich auf Transportebene verwendet. Im Allgemeinen sind hardwarebasierte Load Balancer schneller als softwarebasierte Lösungen. Ihr Nachteil sind ihre Kosten.

Im Gegensatz zu Hardware-Load-Balancern werden softwarebasierte Load-Balancer auf Standardbetriebssystemen und Standard-Hardwarekomponenten wie PCs ausgeführt. Softwarebasierte Lösungen werden entweder innerhalb eines dedizierten Load Balancer-Hardwareknotens wie in Abbildung 1 oder direkt in der Anwendung ausgeführt.

DNS-basierter Lastausgleich

Der DNS-basierte Lastausgleich ist einer der frühen Server-Lastausgleichsansätze. Das Domain Name System (DNS) des Internets verknüpft IP-Adressen mit einem Hostnamen. Wenn Sie einen Hostnamen (als Teil der URL) in Ihren Browser eingeben, fordert der Browser den DNS-Server auf, den Hostnamen in eine IP-Adresse aufzulösen.

Der DNS-basierte Ansatz basiert auf der Tatsache, dass mit DNS einem Hostnamen mehrere IP-Adressen (echte Server) zugewiesen werden können, wie im DNS-Suchbeispiel in Listing 1 gezeigt.

Listing 1. Beispiel für eine DNS-Suche

>nslookup amazon.com Server: ns.box Address: 192.168.1.1 Name: amazon.com Addresses: 72.21.203.1, 72.21.210.11, 72.21.206.5

Wenn der DNS-Server einen Round-Robin-Ansatz implementiert, ändert sich die Reihenfolge der IP-Adressen für einen bestimmten Host nach jeder DNS-Antwort. Normalerweise versuchen Clients wie Browser, eine Verbindung zu der ersten Adresse herzustellen, die von einer DNS-Abfrage zurückgegeben wurde. Das Ergebnis ist, dass Antworten auf mehrere Clients auf die Server verteilt werden. Im Gegensatz zur Server-Lastausgleichsarchitektur in Abbildung 1 ist kein Hardware-Knoten für den Zwischenlastausgleich erforderlich.

DNS ist eine effiziente Lösung für den globalen Server-Lastausgleich, bei der die Last auf Rechenzentren an verschiedenen Standorten verteilt werden muss. Häufig wird der DNS-basierte globale Server-Lastausgleich mit anderen Server-Lastausgleichslösungen kombiniert, um die Last in einem dedizierten Rechenzentrum zu verteilen.

Obwohl der DNS-Ansatz einfach zu implementieren ist, weist er schwerwiegende Nachteile auf. Um DNS-Abfragen zu reduzieren, werden die DNS-Abfragen vom Client zwischengespeichert. Wenn ein Server nicht mehr verfügbar ist, enthalten der Client-Cache sowie der DNS-Server weiterhin eine tote Serveradresse. Aus diesem Grund trägt der DNS-Ansatz wenig zur Implementierung einer hohen Verfügbarkeit bei.

Lastausgleich für TCP / IP-Server

TCP / IP-Server-Load-Balancer arbeiten mit Low-Level-Layer-Switching. Ein beliebter softwarebasierter Low-Level-Server-Load-Balancer ist der Linux Virtual Server (LVS). Die realen Server erscheinen der Außenwelt als ein einziger "virtueller" Server. Die eingehenden Anforderungen auf einer TCP-Verbindung werden vom Load Balancer an die realen Server weitergeleitet, auf dem ein Linux-Kernel ausgeführt wird, der mit IPVS-Code (IP Virtual Server) gepatcht ist.

Um eine hohe Verfügbarkeit sicherzustellen, werden in den meisten Fällen zwei Load-Balancer-Knoten eingerichtet, wobei sich ein Load-Balancer-Knoten im passiven Modus befindet. Wenn ein Load Balancer ausfällt, aktiviert das Heartbeat-Programm, das auf beiden Load Balancern ausgeführt wird, den passiven Load Balancer-Knoten und initiiert die Übernahme der virtuellen IP-Adresse (VIP). Während der Heartbeat für die Verwaltung des Failovers zwischen den Load Balancern verantwortlich ist, werden einfache Sende- / Erwartungsskripts verwendet, um den Zustand der realen Server zu überwachen.

Die Transparenz für den Client wird durch die Verwendung eines VIP erreicht, der dem Load Balancer zugewiesen ist. Wenn der Client eine Anfrage stellt, wird zuerst der angeforderte Hostname in den VIP übersetzt. Wenn das Anforderungspaket empfangen wird, entscheidet der Load Balancer, welcher reale Server das Anforderungspaket verarbeiten soll. Die Ziel-IP-Adresse des Anforderungspakets wird in die reale IP (RIP) des realen Servers umgeschrieben. LVS unterstützt mehrere Planungsalgorithmen zum Verteilen von Anforderungen an die realen Server. Es wird häufig für die Verwendung der Round-Robin-Planung eingerichtet, ähnlich wie beim DNS-basierten Lastausgleich. Bei LVS wird die Lastausgleichsentscheidung auf TCP-Ebene (Schicht 4 des OSI-Referenzmodells) getroffen.

Nach dem Empfang des Anforderungspakets verarbeitet der reale Server es und gibt das Antwortpaket zurück. Um die Rückgabe des Antwortpakets über den Load Balancer zu erzwingen, verwendet der reale Server den VIP als Standardantwortroute. Wenn der Load Balancer das Antwortpaket empfängt, wird die Quell-IP des Antwortpakets mit dem VIP (OSI Model Layer 3) neu geschrieben. Dieser LVS-Routing-Modus wird als NAT-Routing (Network Address Translation) bezeichnet. Abbildung 2 zeigt eine LVS-Implementierung, die NAT-Routing verwendet.

LVS unterstützt auch andere Routing-Modi wie Direct Server Return. In diesem Fall wird das Antwortpaket vom realen Server direkt an den Client gesendet. Dazu muss der VIP auch allen realen Servern zugewiesen werden. Es ist wichtig, dass der VIP des Servers für das Netzwerk nicht auflösbar ist. Andernfalls ist der Load Balancer nicht mehr erreichbar. Wenn der Load Balancer ein Anforderungspaket empfängt, wird die MAC-Adresse (OSI Model Layer 2) der Anforderung anstelle der IP-Adresse neu geschrieben. Der reale Server empfängt das Anforderungspaket und verarbeitet es. Basierend auf der Quell-IP-Adresse wird das Antwortpaket unter Umgehung des Load Balancers direkt an den Client gesendet. Für den Webverkehr kann dieser Ansatz die Arbeitslast des Balancers drastisch reduzieren. In der Regel werden viel mehr Antwortpakete übertragen als Anforderungspakete. Wenn Sie beispielsweise eine Webseite anfordern, wird häufig nur ein IP-Paket gesendet. Wenn eine größere Webseite angefordert wird,Zum Übertragen der angeforderten Seite sind mehrere Antwort-IP-Pakete erforderlich.

Caching

Low-Level-Server-Load-Balancer-Lösungen wie LVS stoßen an ihre Grenzen, wenn Caching auf Anwendungsebene oder Unterstützung für Anwendungssitzungen erforderlich sind. Caching ist ein wichtiges Skalierbarkeitsprinzip, um teure Vorgänge zu vermeiden, bei denen dieselben Daten wiederholt abgerufen werden. Ein Cache ist ein temporärer Speicher, der redundante Daten enthält, die aus einer vorherigen Datenabrufoperation resultieren. Der Wert eines Caches hängt von den Kosten für das Abrufen der Daten im Verhältnis zur Trefferquote und der erforderlichen Cache-Größe ab.

Basierend auf dem Load Balancer-Planungsalgorithmus werden die Anforderungen einer Benutzersitzung von verschiedenen Servern verarbeitet. Wenn auf der Serverseite ein Cache verwendet wird, werden streunende Anforderungen zu einem Problem. Ein Ansatz, um dies zu handhaben, besteht darin, den Cache in einem globalen Raum zu platzieren. memcached ist eine beliebte verteilte Cache-Lösung, die einen großen Cache auf mehreren Computern bereitstellt. Es handelt sich um einen partitionierten, verteilten Cache, der mithilfe von konsistentem Hashing den Cache-Server (Daemon) für einen bestimmten Cache-Eintrag ermittelt. Basierend auf dem Hash-Code des Cache-Schlüssels ordnet die Client-Bibliothek immer denselben Hash-Code derselben Cache-Server-Adresse zu. Diese Adresse wird dann zum Speichern des Cache-Eintrags verwendet. Abbildung 3 veranschaulicht diesen Caching-Ansatz.

Listing 2 verwendet spymemcachedeinen memcachedin Java geschriebenen Client, um HttpResponseNachrichten auf mehreren Computern zwischenzuspeichern. Die spymemcachedBibliothek implementiert die erforderliche Client-Logik, die ich gerade beschrieben habe.

Listing 2. Memcached-basierter HttpResponse-Cache