Kapitel 1. Muster und Zusammenhänge

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Stell dir vor, du backst mit einem Freund oder einer Freundin einen Kuchen. Du hast das Rezept befolgt und alle Zutaten (Öl, Mehl, Eier und Zucker) gemischt, und der Kuchen sieht gut aus, aber wenn du ihn probierst, stimmt etwas nicht ganz. Um ein guter Bäcker oder eine gute Bäckerin zu sein, musst du alle Bestandteile eines Kuchens kennen (das Verhältnis von Mehl zu Fett usw.) und wissen, wie sie zusammenwirken, um die Qualität des fertigen Produkts (z. B. Geschmack und Konsistenz) zu beeinflussen. In Abbildung 1-1 haben unsere Bäcker/innen zum Beispiel nicht verstanden, dass Sesamöl für den Kuchen nicht geeignet ist.

Ersetze nun Bäcker durch Systemadministrator und ersetze die goldenen Verhältnisse der Zutaten eines Bäckers durch die miteinander verbundenen Komponenten deines Systems (z. B. Smartphones, eingebettete Geräte, große Server und Speicher-Arrays). Um ein guter Systemadministrator zu sein, musst du verstehen, wie die Komponenten in gemeinsamen Mustern zusammenhängen und sich auf die Qualität deines Systems auswirken (z. B. Zuverlässigkeit, Skalierbarkeit und Wartbarkeit).

In diesem Kapitel helfe ich dir, deine Systeme zu durchdenken, um die Muster und Zusammenhänge darin zu erkennen, damit du verstehst, welche Entscheidungen für das Design deines Systems getroffen wurden.

Figure 1-1
Abbildung 1-1. Modellierung des Verständnisses eines Systems (Bild von Tomomi Imura)

Wie man Dinge verbindet

Ingenieure wählen Architekturmuster, wiederverwendbare Lösungen für typische Arbeitslasten (z. B. Stapelverarbeitung, Webserver und Caching). Diese Muster sind Modelle, die "ein gemeinsames Verständnis des Systemdesigns" vermitteln.1

Von On-Premise- bis hin zu Cloud-Computing-Umgebungen entwickeln sich die wiederverwendbaren Lösungen weiter, um dekomponierte Sets kleinerer Dienste zu unterstützen.2 Diese Muster bestimmen die Zuverlässigkeit, Skalierbarkeit und Wartbarkeit von Systemen, indem sie die Komponenten des Systems und die Verbindung zwischen den Komponenten festlegen.

Untersuchen wir drei gängige Architekturmuster ( ), die beim Systemdesign verwendet werden, um zu sehen, wie ihre Verwendung die Entwicklung und die Eigenschaften des Systems (Zuverlässigkeit, Skalierbarkeit und Wartbarkeit) beeinflusst (und einschränkt):

Mehrschichtige Architektur

Das am weitesten verbreitete und bekannteste Muster ist die allgemeine Schichten- oder Ebenenarchitektur. Ingenieure verwenden dieses Muster häufig für Client-Server-Anwendungen wie Webserver, E-Mail und andere Geschäftsanwendungen.

Ingenieure gliedern die Komponenten in horizontale Schichten, wobei jede Schicht eine bestimmte Aufgabe erfüllt und die Belange der einzelnen Schichten von den anderen Schichten trennt. Die Schichten sind in der Regel eng miteinander gekoppelt und hängen von den Anfragen und Antworten der benachbarten Schichten ab. Daher kannst du Komponenten innerhalb jeder Schicht unabhängig von anderen Schichten aktualisieren und einsetzen.

Ein zweistufiges System besteht aus einem Client und einem Server. Ein dreischichtiges System besteht aus einem Client und zwei weiteren Serverschichten; die Präsentations-, Anwendungs- und Datenschichten sind in verschiedene Komponenten unterteilt. In einem N-Tier- oder Multitier-System kann jede Schicht in separate logische Schichten aufgeteilt sein. Je nach den Anforderungen des Systems (z. B. Ausfallsicherheit, Sicherheit und Skalierbarkeit) kann es mehr als drei Schichten geben. Mit jeder Schicht steigen die Skalierbarkeit und die Zuverlässigkeit, da die Schichten eine zusätzliche Trennung zwischen den Bereichen schaffen, die unabhängig voneinander eingesetzt und aktualisiert werden können.

Microservices-Architektur

Ein Microservice-System ist eine verteilte Architektur, die anstelle von Ebenen aus einer Sammlung von kleinen, voneinander entkoppelten Einheiten von Geschäftscode besteht. Microservices sind klein und eigenständig. Da jeder Dienst separat ist, kann der Code unabhängig entwickelt und eingesetzt werden. Darüber hinaus kann jeder Dienst die beste Sprache oder das beste Framework für seinen Anwendungsfall nutzen.

Microservices erhöhen die Skalierbarkeit und Zuverlässigkeit des Systems, da sie je nach Bedarf unabhängig voneinander eingesetzt werden können und von den Fehlerpunkten im System isoliert sind.

Die Zerlegung eines Dienstes in Microservices verringert die Wartungsfreundlichkeit, da die Systemadministratoren mehr Arbeit haben. Um dein System zu verstehen, musst du alle Details über jeden einzelnen Dienst kennen (d.h. Sprachen, Frameworks, Build- und Deployment-Pipelines und alle relevanten Umgebungen).

Ereignisgesteuerte Architektur

Eine ereignisgesteuerte Architektur ist ein verteiltes, asynchrones Muster, das eine lose Kopplung zwischen Anwendungen ermöglicht. Die verschiedenen Anwendungen kennen keine Details übereinander. Stattdessen kommunizieren sie indirekt, indem sie Ereignisse veröffentlichen und konsumieren.

Ereignisse sind etwas, das passiert, eine Tatsache, die nachverfolgt werden kann.3 Systeme erzeugen Ereignisse. In ereignisgesteuerten Systemen erzeugen Ereignisproduzenten Ereignisse, Broker nehmen Ereignisse auf, und Konsumenten hören zu und verarbeiten sie.

Es gibt zwei Hauptmodelle für ereignisgesteuerte Systeme: Messaging (oder Pub/Sub) und Streaming.

Die Ereignisproduzenten oder -verleger veröffentlichen Ereignisse an einen Broker in einem Ereignis-Nachrichtensystem. Der Broker sendet alle veröffentlichten Ereignisse an Ereignisverbraucher oder Abonnenten. Der Nachrichtenbroker empfängt die veröffentlichten Ereignisse von den Verlagen, hält die Reihenfolge der empfangenen Nachrichten ein, stellt sie den Abonnenten zur Verfügung und löscht die Ereignisse, nachdem sie konsumiert wurden.

In einem Event-Streaming-System werden die Ereignisse in einem verteilten Protokoll veröffentlicht, einem dauerhaften, nur anhängenden Datenspeicher. So können die Verbraucher die Ereignisse aus dem Stream konsumieren, die sie wollen, und sie können sie wiedergeben. Außerdem speichert das verteilte Protokoll die Ereignisse, nachdem sie konsumiert wurden, so dass neue Abonnenten Ereignisse abonnieren können, die vor ihrem Abonnement eingetreten sind.

Da die Komponenten lose gekoppelt sind, müssen sich die einzelnen Teile des Systems keine Sorgen um den Zustand anderer Komponenten machen. Lose gekoppelte Elemente erhöhen die Ausfallsicherheit des Gesamtsystems, da sie unabhängig voneinander eingesetzt und aktualisiert werden können. Die Ereignispersistenz ermöglicht die Wiederholung von Ereignissen, die im Falle eines Ausfalls aufgetreten sind.

Tabelle 1-1 fasst die relativen Vergleiche der Zuverlässigkeit, Skalierbarkeit und Wartbarkeit der drei gängigen Architekturmuster zusammen, die du in Systemen finden wirst.

Tabelle 1-1. Vergleich der Zuverlässigkeit, Skalierbarkeit und Wartbarkeit von Architekturen
Lagenweise Microservices Ereignisgesteuert

Verlässlichkeit

Mittel (eng gekoppelte Systeme)

Hoch

Hoch

Skalierbarkeit

Mittel (begrenzt innerhalb der Schichten)

Hoch

Hoch

Instandhaltbarkeit

Hoch

Niedrig (geringere Einfachheit)

Mittel (verminderte Prüfbarkeit)

Tipp

Natürlich sind das nicht die einzigen Muster, die du beim Systemdesign findest. Schau dir Martin Fowlers umfassende Website an, den Software Architecture Guide.

Wie Dinge kommunizieren

Eine Komponente eines Systems existiert nicht isoliert - jede Komponente kommuniziert mit anderen Komponenten im System, und diese Kommunikation kann durch das Architekturmuster beeinflusst werden(REST für eine N-Tier-Architektur, gRPC für eine ereignisgesteuerte Architektur).

Es gibt verschiedene Modelle, die die Kommunikation zwischen Komponenten beschreiben, z. B. das Internet-Modell, das Fünf-Schichten-Internet-Modell, das Fünf-Schichten-Referenzmodell von TCP/IP und das TCP/IP-Modell. Obwohl sich diese Modelle sehr ähneln, gibt es leichte Unterschiede, die sich auf die Art und Weise auswirken können, wie die Menschen über die Anwendungen und Dienste denken, die sie für die Kommunikation entwickeln.

Wenn eine Person oder eine Gruppe von Ingenieuren einen verbesserungswürdigen Bereich identifiziert, verfassen sie einen Request for Comment (RFC) und reichen ihn zur Begutachtung ein. Als offene internationale Gemeinschaft, die daran arbeitet, das Design, die Benutzerfreundlichkeit, die Wartbarkeit und die Interoperabilität des Internets zu erhalten und zu verbessern, nimmt die Internet Engineering Task Force (IETF ) einige der vorgeschlagenen RFCs als technische Standards an, die die offiziellen Spezifikationen und Protokolle festlegen. Die Protokollspezifikationen legen fest, wie Geräte miteinander kommunizieren und folgen dabei dem Internetmodell. Und diese Protokolle werden ständig weiterentwickelt, da das Internet wächst und sich die Bedürfnisse der Menschen ändern (ein Beispiel dafür findest du in Anhang B).

Wie in Tabelle 1-2 dargestellt, zeigt das Fünf-Schichten-Modell des Internets fünf diskrete Schichten. Jede Schicht kommuniziert über die darüber und darunter liegenden Schnittstellen über ein schichtspezifisches Nachrichtenobjekt. Die Schichtung eines Systems trennt die Zuständigkeiten auf jeder Schicht und ermöglicht es, verschiedene Systemteile zu erstellen (und zu ändern). Außerdem ermöglicht es eine Differenzierung auf den einzelnen Schichten.

Tabelle 1-2. Fünf-Schichten-Modell des Internets und Beispielprotokolle
Lagen Beispiel-Protokolle

Bewerbung

HTTP, DNS, BGP

Transport

TCP, UDP

Netzwerk

IP, ICMP

Datenverbindung

ARP

Physisch

Kupfer, Glasfaser, WiFi

Wie bei der Torte in Abbildung 1-1 gibt es keine knackigen Schichten, die dir genau sagen, wo ein Problem entstanden ist. Protokollimplementierungen müssen sich nicht strikt an die Spezifikationen halten und überschneiden sich mit anderen Schichten. Ein Beispiel: Das Protokoll, das die schnellste und effizienteste Route für die Datenübertragung bestimmt, ist das Border Gateway Protocol (BGP). Aufgrund der Implementierung des Protokolls kann man BGP entweder der Anwendungsschicht oder der Transportschicht zuordnen.

Die Schichten des Internetmodells geben dir die Möglichkeit, den Kontext einzugrenzen und dich auf die Bestandteile deiner Anwendung - den Quellcode und die Abhängigkeiten - oder auf eine niedrigere physikalische Ebene zu konzentrieren, wodurch das komplexe Kommunikationsmodell in verständliche Teile zerlegt wird. Manchmal stößt du jedoch auf Situationen, in denen die Reduzierung des Kontexts dir nicht hilft zu verstehen, was vor sich geht. Um dein Verständnis zu verbessern, musst du wissen, wie alles zusammenwirkt, um die Qualität deines Systems zu verbessern.

Schauen wir uns die Anwendungs-, Transport-, Netzwerk-, Datenübertragungs- und physikalischen Schichten genauer an.

Anwendungsschicht

Beginnen wir an der Spitze des Internetmodells mit der Anwendungsschicht. Die Anwendungsschicht beschreibt alle High-Level-Protokolle, mit denen Anwendungen in der Regel direkt interagieren. Die Protokolle dieser Schicht regeln, wie Anwendungen mit der darunter liegenden Transportschicht zusammenarbeiten, um Daten zu senden und zu empfangen.

Um diese Schicht zu verstehen, konzentriere dich auf die Bibliotheken oder Anwendungen, die die Protokolle implementieren, die deiner Anwendung zugrunde liegen. Wenn ein Kunde zum Beispiel deine Website mit einem gängigen Browser besucht, laufen die folgenden Schritte ab:

  1. Der Browser initiiert Bibliotheksaufrufe, um die IP-Adresse des Webservers über das Domain Name System (DNS) zu erhalten.

  2. Der Browser initiiert eine HTTP-Anfrage.

Die DNS- und HTTP-Protokolle arbeiten innerhalb der Anwendungsschicht des Internet-Modells.

Transportschicht

Die nächste Schicht im Internetmodell, die Transportschicht, regelt den Datenfluss zwischen den Hosts. Auch hier gibt es zwei Hauptprotokolle: das Transmission Control Protocol (TCP) und das User Datagram Protocol (UDP).

In der Vergangenheit war UDP die Grundlage für eher rudimentäre Protokolle wie Ping/ICMP, DHCP, ARP und DNS, während TCP die Grundlage für "interessantere" Protokolle wie HTTP, SSH, FTP und SMB war. Dies hat sich jedoch geändert, da die Eigenschaften, die TCP pro Sitzung zuverlässiger machen, in bestimmten Kontexten zu Leistungsengpässen führen.

UDP ist ein zustandsloses Protokoll, das nach bestem Wissen und Gewissen versucht, Nachrichten zu übertragen, aber nicht überprüft, ob die Netzwerkpartner Nachrichten erhalten haben; TCP hingegen ist ein verbindungsorientiertes Protokoll, das einen Drei-Wege-Handshake verwendet, um eine zuverlässige Sitzung mit einem Netzwerkpartner aufzubauen.

Die wesentlichen Merkmale von UDP sind folgende:

Verbindungslos

UDP ist kein sitzungsorientiertes Protokoll. Netzwerk-Peers können Pakete austauschen, ohne vorher eine Sitzung aufzubauen.

Verlustbehaftet

Es gibt keine Unterstützung für Fehlererkennung oder -korrektur. Die Anwendungen müssen eigene Mechanismen zur Fehlertoleranz implementieren.

Nicht blockierend

TCP ist anfällig für das "Head of Line Blocking"-Problem, bei dem fehlende Pakete oder ein nicht sequentieller Empfang von Daten dazu führen können, dass eine Sitzung stecken bleibt und eine erneute Übertragung ab dem Punkt des Fehlers erforderlich wird. Bei UDP ist die nicht sequentielle Zustellung kein Problem, und Anwendungen können gezielt die erneute Übertragung fehlender Daten anfordern, ohne Pakete, die erfolgreich zugestellt wurden, erneut zu senden.

Im Vergleich dazu sind die wesentlichen Merkmale von TCP wie folgt:

Danksagung

Der Empfänger benachrichtigt den Absender über den Erhalt der Daten für jedes Paket. Diese Empfangsbestätigung bedeutet nicht, dass die Anwendung die Daten erhalten oder verarbeitet hat, sondern nur, dass sie am Zielort angekommen sind.

Verbindungsorientiert

Der Absender baut eine Sitzung auf, bevor er Daten überträgt.

Verlässlichkeit

TCP verfolgt die Daten, die gesendet und empfangen werden. Empfängerbestätigungen können verloren gehen, so dass ein Empfänger keine Segmente in falscher Reihenfolge bestätigt; stattdessen sendet er ein Duplikat des zuletzt beobachteten geordneten Pakets oder eine doppelte kumulative Bestätigung. Diese Zuverlässigkeit kann die Latenzzeit verlängern.

Durchflusskontrolle

Der Empfänger teilt dem Absender mit, wie viele Daten empfangen werden können.

Beachte, dass die Sicherheit nicht Teil des Designs oder der grundlegenden Eigenschaften von TCP oder UDP war. Stattdessen führte der Mangel an Sicherheit in den ursprünglichen Entwürfen dieser Protokolle zu zusätzlicher Komplexität bei der Implementierung von Anwendungen und Systemen und zu weiteren Änderungen der Protokolle.

Netzwerkschicht

In der Mitte übersetzt die Netzwerkschicht zwischen der Transport- und der Datenübertragungsschicht und ermöglicht die Zustellung von Paketen auf der Grundlage einer eindeutigen hierarchischen Adresse, der IP-Adresse.

Das Internetprotokoll (IP) ist für die Regeln zur Adressierung und Fragmentierung von Daten zwischen zwei Systemen verantwortlich. Es sorgt für die eindeutige Identifizierung von Netzwerkschnittstellen, um Datenpakete über IP-Adressen zuzustellen. Das IP bricht Pakete auf und setzt sie bei Bedarf wieder zusammen, wenn Daten über Verbindungen mit einer kleineren maximalen Übertragungseinheit (MTU) übertragen werden. IPv4 ist die am weitesten verbreitete Version des IP mit einem 32-Bit-Adressraum, der in einer Zeichenkette aus vier binären Oktetten oder vier Dezimalzahlen dargestellt wird, die durch Punkte oder die Vier-Punkt-Dezimal-Notation getrennt sind. Der IPv6-Standard bietet Vorteile wie einen 128-Bit-Adressraum, ausgefeiltere Routing-Funktionen und eine bessere Unterstützung für die Multicast-Adressierung. Allerdings hat sich IPv6 nur langsam durchgesetzt, was zum Teil daran liegt, dass IPv4 und IPv6 nicht interoperabel sind und es im Allgemeinen einfacher war, sich mit den Unzulänglichkeiten von IPv4 zu begnügen, als alles auf den neuen Standard zu portieren.

Die zugrunde liegende binäre Definition gibt den Bereich in dezimaler Schreibweise für IPv4-Adressen von 0 bis 255 an. Außerdem werden in den RFCs reservierte Bereiche für private Netzwerke festgelegt, die nicht über das öffentliche Internet geroutet werden können.

Das IP-Protokoll der Netzwerkschicht konzentriert sich auf die Bereitstellung einer eindeutigen Adresse für die Interaktion zwischen den Netzwerkteilnehmern, ist aber nicht für die Übertragung auf der Datenübertragungsschicht zuständig und kümmert sich auch nicht um das Sitzungsmanagement, das von der Transportschicht übernommen wird.

Datenübertragungsschicht

Als Nächstes verwendet die Datenübertragungsschicht die physikalische Schicht, um Pakete zu senden und zu empfangen.

Das Address Resolution Protocol (ARP) sorgt für die Ermittlung der Hardware-Adresse anhand einer bekannten IP-Adresse. Hardwareadressen werden auch als MAC-Adressen ( Media Access Control ) bezeichnet. Jedem Network Interface Controller (NIC) wird eine eindeutige MAC-Adresse zugewiesen.

Die Industrie hat vorgesehen, dass MAC-Adressen weltweit eindeutig sind, so dass Netzwerkmanagementgeräte und -software davon ausgehen, dass dies für die Geräteauthentifizierung und -sicherheit gilt. Doppelte MAC-Adressen im selben Netzwerk können Probleme verursachen. Doppelte MAC-Adressen treten jedoch aufgrund von Produktionsfehlern bei der Herstellung von Hardware (oder absichtlichem Softwaredesign mit MAC-Zufallsgenerator) auf.4 Es kann aber auch bei virtualisierten Systemen vorkommen, z. B. bei VMs, die von einem Referenzimage geklont wurden. Wie auch immer, wenn mehrere Netzwerk-Hosts dieselbe MAC-Adresse melden, kann es zu Fehlern in der Netzwerkfunktion und erhöhten Latenzzeiten kommen.

Tipp

Menschen können die MAC-Adresse, die dem Netzwerk präsentiert wird, durch Software maskieren. Dies wird als MAC-Spoofing bezeichnet. Einige Angreifer nutzen MAC-Spoofing als Layer-2-Angriff, um zu versuchen, die Kommunikation zwischen zwei Systemen zu kapern und sich in eines der Systeme einzuhacken.

Das Reverse Address Resolution Protocol (RARP) prüft die Zuordnung von IP-Adressen zu Hardware-Adressen und kann so feststellen, ob mehrere IP-Adressen auf eine einzige MAC-Adresse antworten. Wenn du glaubst, dass zwei Geräte im Netzwerk eine IP-Adresse gemeinsam nutzen, z. B. weil jemand eine statische IP-Adresse zugewiesen hat, obwohl ein DHCP-Server dieselbe Adresse bereits einem anderen Host zugewiesen hat, hilft RARP, den Schuldigen zu finden.

Physikalische Schicht

Die physikalische Schicht übersetzt den binären Datenstrom aus den oberen Schichten in elektrische, Licht- oder Funksignale, die über die darunter liegende physikalische Hardware übertragen werden. Jede Art von physischem Medium hat eine andere maximale Länge und Geschwindigkeit.

Auch bei der Nutzung von Cloud-Diensten musst du dich um die physische Ebene kümmern, auch wenn du dich nicht um das Racking und Stacking der physischen Server kümmern musst. Erhöhte Latenzzeiten können durch das physische Routing zwischen zwei Punkten verursacht werden. Wenn z. B. in einem Rechenzentrum etwas passiert (ein Blitzschlag oder ein Eichhörnchen beschädigt die Kabel), werden die Ressourcen möglicherweise zu anderen, weiter entfernten Diensten umgeleitet. Außerdem kann es vorkommen, dass die Netzwerkausrüstung in einem Rechenzentrum neu gestartet werden muss oder ein defektes Kabel oder eine defekte Netzwerkkarte hat. Infolgedessen können Anfragen, die über diese physischen Komponenten gesendet werden, eine höhere Latenz aufweisen.

Einpacken

Du wirst in deiner Umgebung eine Mischung aus diesen Mustern (geschichtet, Microservices und ereignisgesteuert) und Protokollen finden. Das Verständnis der Systemarchitektur gibt Aufschluss darüber, wie die Komponenten zusammenhängen und miteinander kommunizieren, und deine Anforderungen wirken sich auf die Zuverlässigkeit, Wartbarkeit und Skalierbarkeit des Systems aus.

Im nächsten Kapitel erzähle ich dir, wie du über diese Muster und Zusammenhänge nachdenken kannst und wie sie sich auf deine Entscheidungen für deine Computerumgebungen in deinem Unternehmen auswirken.

1 Martin Fowler, "Software Architecture Guide," martinfowler.com, zuletzt geändert am 1. August 2019, www.martinfowler.com/architecture.

2 Mehr über die Zerlegung von Services erfährst du in Kapitel 3 von Sam Newmans Building Microservices (O'Reilly).

3 CloudEvents ist ein von der Community getragenes Projekt zur Definition einer Spezifikation für die Beschreibung von Ereignisdaten in einer Standardform, die über verschiedene Dienste und Plattformen hinweg implementiert werden kann.

4 Erfahre mehr über die Probleme mit der MAC-Randomisierung in "MAC Address Randomization: Datenschutz auf Kosten von Sicherheit und Bequemlichkeit".

Get Modern System Administration now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.