Verteilte Systeme mit Kubernetes entwerfen - Brendan Burns - E-Book

Verteilte Systeme mit Kubernetes entwerfen E-Book

Brendan Burns

0,0

Beschreibung

Container und Container-Orchestrierer haben die Entwicklung verteilter Systeme grundlegend verändert – es gibt jetzt Objekte und Schnittstellen für das Darstellen zentraler Muster für verteilte Systeme und das Bauen wiederverwendbarer, containerisierter Komponenten. Dieser praktische Ratgeber stellt Ihnen eine Reihe immer wieder einsetzbarer, generischer Muster vor, mit denen die Entwicklung zuverlässiger verteilter Systeme einfacher und effizienter geschehen kann. Bisher mussten Entwickler diese Systeme von Grund auf selbst bauen, daher ist jede Systemarchitektur einmalig. Brendan Burns, Director of Engineering bei Microsoft Azure, zeigt Ihnen in diesem Buch, wie Sie vorhandene Software-Entwurfsmuster adaptieren können, um zuverlässige verteilte Anwendungen zu bauen. System- und Anwendungsentwickler erfahren hier, wie diese Muster eine gemeinsame Sprache und ein Framework schaffen, die die Qualität dieser Systeme deutlich verbessern. In diesem Buch: - Verstehen Sie, wie Muster und wiederverwendbare Komponenten die schnelle Entwicklung zuverlässiger verteilter Systeme ermöglichen. - Nutzen Sie die Sidecar-, Adapter-und Ambassador-Muster, um Ihre Anwendung in eine Gruppe von Containern auf einer einzelnen Maschine zu unterteilen. - Verwenden Sie lose gekoppelte verteilte Multi-Node-Muster zur Replikation, zum Skalieren und für die Kommunikation zwischen den Komponenten. - Lernen Sie Muster für die Batch-Verarbeitung von Massendaten kennen, die sich um Work Queues, ereignisbasierte Verarbeitung und koordinierte Workflows drehen. Brendan Burns ist angesehener Entwickler in Microsoft Azure und Mitbegründer des Open-Source-Projekts Kubernetes. Bevor er zu Microsoft kam, arbeitete er bei Google an der Google Cloud Platform und half dabei, APIs wie den Deployment Manager und die Cloud DNS zu bauen.    

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 192

Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:

Android
iOS
Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Zu diesem Buch – sowie zu vielen weiteren O’Reilly-Büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei oreilly.plus+:

www.oreilly.plus

Verteilte Systememit Kubernetes entwerfen

Patterns und Prinzipien fürskalierbare und zuverlässige Services

Brendan Burns

Deutsche Übersetzung vonThomas Demmig

Brendan Burns

Übersetzung: Thomas Demmig

Lektorat: Sandra Bollenbacher

Korrektorat: Petra Heubach-Erdmann

Satz: III-satz, www.drei-satz.de

Herstellung: Stefanie Weidner

Umschlaggestaltung: Michael Oréal, www.oreal.de

Bibliografische Information Der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.

ISBN:

Print   978-3-96009-088-5

PDF    978-3-96010-240-3

ePub   978-3-96010-241-0

mobi   978-3-96010-242-7

Dieses Buch erscheint in Kooperation mit O’Reilly Media, Inc. unter dem Imprint »O’REILLY«.

O’REILLY ist ein Markenzeichen und eine eingetragene Marke von O’Reilly Media, Inc. und wird mit Einwilligung des Eigentümers verwendet.

1. Auflage 2018

Copyright © 2018 dpunkt.verlag GmbH

Wieblinger Weg 17

69123 Heidelberg

Authorized German translation of material included in the English edition of Designing Distributed Systems ISBN 978-1491983645 © 2018 Brendan Burns. This translation is published and sold by permission of O'Reilly Media, Inc., which owns or controls all rights to publish and sell the same

Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.

Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.

Die Informationen in diesem Buch wurden mit größter Sorgfalt erarbeitet. Dennoch können Fehler nicht vollständig ausgeschlossen werden. Verlag, Autoren und Übersetzer übernehmen keine juristische Verantwortung oder irgendeine Haftung für eventuell verbliebene Fehler und deren Folgen.

5 4 3 2 1 0

Inhalt

Vorwort

1Einführung

Eine kurze Geschichte der System-Entwicklung

Eine kurze Geschichte von Mustern in der Software-Entwicklung

Formalisierung der algorithmischen Programmierung

Muster für die objektorientierte Programmierung

Der Aufstieg von Open-Source-Software

Der Wert von Mustern, Praktiken und Komponenten

Auf den Schultern von Riesen stehen

Eine gemeinsame Sprache für Gespräche über unsere Praktiken

Gemeinsame Komponenten für einfache Wiederverwendung

Zusammenfassung

Teil I: Single-Node-Muster

Motivation

Zusammenfassung

2Sidecar

Ein Beispiel-Sidecar: HTTPS für einen alten Service

Dynamische Konfiguration mit Sidecars

Modulare Anwendungs-Container

Aus der Praxis: Den topz-Container deployen

Mit Sidecars eine einfache PaaS bauen

Modularität und Wiederverwendbarkeit durch Sidecars

Container parametrisieren

Die API jedes Containers definieren

Dokumentieren Sie Ihre Container

Zusammenfassung

3Ambassador

Mit einem Ambassador einen Service per Sharding aufteilen

Aus der Praxis: Einen Sharded Redis implementieren

Einen Ambassador zum Service Brokering einsetzen

Mit einem Ambassador experimentieren oder Requests splitten

Aus der Praxis: 10%-Experimente umsetzen

4Adapter

Monitoring

Aus der Praxis: Prometheus für das Monitoring einsetzen

Logging

Aus der Praxis: Verschiedene Logging-Formate mit fluentd normalisieren

Einen Health-Monitor ergänzen

Aus der Praxis: Ausführliches Health Monitoring für MySQL

Teil II: Serving-Muster

Einführung in Microservices

5Replizierte lastverteilte Services

Zustandslose Services

Readiness-Prüfungen für das Load Balancing

Aus der Praxis: Einen replizierten Service in Kubernetes erstellen

Services mit Session Tracking

Replizierte Services auf Anwendungsebene

Einziehen einer Caching-Schicht

Ihren Cache deployen

Aus der Praxis: Die Caching-Schicht deployen

Die Cache-Schicht erweitern

Rate Limiting und Denial-of-Service-Verteidigung

SSL Termination

Aus der Praxis: nginx und SSL Termination deployen

Zusammenfassung

6Sharded Services

Sharded Caching

Warum Sie einen Sharded Cache brauchen könnten

Die Rolle des Cache für die System-Performance

Replizierte Sharded Caches

Aus der Praxis: Einen Ambassador und Memcache für einen Sharded Cache deployen

Sharding-Funktionen

Auswahl eines Schlüssels

Konsistente Hashing-Funktionen

Aus der Praxis: Einen konsistenten HTTP Sharding Proxy bauen

Repliziertes Sharded Serving

Hot Sharding Systems

7Scatter/Gather

Scatter/Gather mit Root-Verteilung

Aus der Praxis: Verteilte Dokumentensuche

Scatter/Gather mit Leaf Sharding

Aus der Praxis: Sharded Dokumentensuche

Die richtige Anzahl an Blättern wählen

Scatter/Gather für mehr Zuverlässigkeit und bessere Skalierbarkeit replizieren

8Funktionen und ereignisgesteuerte Verarbeitung

Herausfinden, ob FaaS sinnvoll ist

Die Vorteile von FaaS

Die Herausforderungen von FaaS

Der Bedarf für Hintergrundprozesse

Der Bedarf für das Halten von Daten im Speicher

Die Kosten einer dauerhaften Request-basierten Verarbeitung

Muster für FaaS

Das Decorator-Muster

Aus der Praxis: Ein Request-Defaulting vor die Request-Verarbeitung schalten

Umgang mit Ereignissen

Aus der Praxis: Zwei-Faktor-Authentifizierung implementieren

Ereignisbasierte Pipelines

Aus der Praxis: Eine Pipeline für das Registrieren neuer Benutzer implementieren

9Ownership Election

Herausfinden, ob Sie überhaupt eine Master Election benötigen

Grundlagen der Master Election

Aus der Praxis: etcd deployen

Locks implementieren

Aus der Praxis: Locks in etcd implementieren

Ownership implementieren

Aus der Praxis: Leases in etcd implementieren

Parallele Datenverarbeitung

Teil III: Batch-Verarbeitung

10Work-Queue-Systeme

Ein generisches Work-Queue-System

Die Quell-Container-Schnittstelle

Die Worker-Container-Schnittstelle

Die Infrastruktur für die gemeinsame Work Queue

Aus der Praxis: Einen Video-Thumbnailer implementieren

Dynamisches Skalieren der Worker

Das Multi-Worker-Muster

11Ereignisgesteuerte Batch-Verarbeitung

Muster für die ereignisgesteuerte Verarbeitung

Copier

Filter

Splitter

Sharder

Merger

Aus der Praxis: Einen ereignisgesteuerten Flow für das Registrieren neuer Benutzer bauen

Publisher/Subscriber-Infrastruktur

Aus der Praxis: Kafka deployen

12Koordinierte Batch-Verarbeitung

Join (oder Barrier-Synchronization)

Reduce

Aus der Praxis: Count

Sum

Histogramm

Aus der Praxis: Eine Pipeline zum Taggen und Bearbeiten von Bildern

13Zusammenfassung: Ein Neuanfang?

Index

Vorwort

Wer dieses Buch lesen sollte

In der heutigen Zeit ist so gut wie jeder Entwickler ein Programmierer oder Konsument (oder beides) verteilter Systeme. Selbst recht einfache mobile Anwendungen sind durch Cloud-APIs unterfüttert, sodass deren Daten auf jedem Gerät genutzt werden können, das der Anwender einsetzt. Egal, ob Ihnen die Entwicklung verteilter Systeme neu ist oder Sie darin ein Experte sind – die in diesem Buch beschriebenen Muster und Komponenten können Ihre Entwicklung verteilter Systeme von einer Kunst in eine Wissenschaft verwandeln. Wiederverwendbare Komponenten und Muster für verteilte Systeme ermöglichen es Ihnen, sich auf die zentralen Details Ihrer Anwendung zu konzentrieren. Dieses Buch wird jedem Entwickler dabei helfen, besser, schneller und effizienter verteilte Systeme zu entwickeln.

Warum ich dieses Buch geschrieben habe

In meiner Karriere als Entwickler einer Vielzahl von Software-Systemen – von Web-Suchmaschinen bis zur Cloud – habe ich eine Reihe skalierbarer, zuverlässiger verteilter Systeme gebaut. Jedes dieser Systeme wurde mehr oder weniger von null auf erstellt. Im Allgemeinen gilt das für alle verteilte Anwendungen. Obwohl viele der Konzepte gleich sind und es sogar manchmal fast die gleiche Logik gibt, ist das Anwenden von Mustern oder das Wiederverwenden von Komponenten häufig ausgesprochen herausfordernd. Das hat mich dazu gezwungen, Zeit mit dem erneuten Implementieren von Systemen zu verschwenden, und jedes System war dadurch weniger ausgefeilt, als es hätte sein können.

Die aktuelle Entwicklung von Containern und Container-Orchestrierern hat die Landschaft der Entwicklung verteilter Systeme grundlegend geändert. Plötzlich haben wir ein Objekt und eine Schnittstelle, um zentrale Muster verteilter Systeme auszudrücken und wiederverwendbare containerisierte Komponenten zu bauen. Ich habe dieses Buch geschrieben, um all die Experten verteilter Systeme zusammenzubringen und eine gemeinsame Sprache und eine allgemeine Standard-Bibliothek zu schaffen, sodass wir alle schneller bessere Systeme bauen können.

Die aktuelle Welt verteilter Systeme

Es gab einmal eine Zeit, in der die Leute Programme geschrieben haben, die auf einem Rechner liefen und auch nur von dort aus bedient wurden. Aber die Zeiten haben sich geändert. Jetzt ist nahezu jede Anwendung ein verteiltes System, das auf mehreren Rechnern läuft und von mehreren Anwendern auf der ganzen Welt genutzt werden kann. Trotz des mittlerweile häufigen Einsatzes ist das Designen und Entwicklern solcher Systeme oft eine Schwarze Kunst, die von einer auserwählten Gruppe von Zauberern betrieben wird. Aber so wie alles Technologische entwickelt sich auch die Welt der verteilten Systeme weiter, sie wird geregelter und abstrakter. In diesem Buch habe ich eine Reihe wiederverwendbarer, generischer Muster zusammengefasst, die die Entwicklung zuverlässiger verteilter Systeme einfacher und effizienter gestalten. Die Übernahme von Mustern und wiederverwendbaren Komponenten befreit Entwickler davon, die gleichen Systeme wieder und wieder neu implementieren zu müssen. Diese gesparte Zeit kann dann genutzt werden, um sich besser um die eigentliche Anwendung zu kümmern.

Wie dieses Buch aufgebaut ist

Dieses Buch ist in vier Teile gegliedert:

Kapitel 1

Hier werden verteilte Systeme vorgestellt und es wird erklärt, warum Muster und wiederverwendbare Komponenten einen großen Unterschied in der schnellen Entwicklung zuverlässiger verteilter Systeme ausmachen können.

Teil I, Single-Node-Muster

In den Kapiteln 2 bis 4 werden wiederverwendbare Muster und Komponenten beschrieben, die auf den einzelnen Knoten eines verteilten Systems genutzt werden. Hier kommen die Single-Node-Muster Sidecar, Adapter und Ambassador vor.

Teil II, Serving-Muster

Die Kapitel 8 und 9 behandeln verteilte Multi-Node-Muster für lang laufende Serving-Systeme, wie zum Beispiel Webanwendungen. Es werden Muster für das Replizieren, Skalieren und die Auswahl eines Masters vorgestellt.

Teil III, Batch-Verarbeitung

Die Kapitel 10 bis 12 stellen Muster für verteilte Systeme zur Batch-Verarbeitung großer Datenmengen vor, wobei es um Work-Queries, ereignisbasierte Verarbeitung und koordinierte Workflows geht.

Sind Sie erfahrener Entwickler verteilter Systeme, werden Sie die ersten paar Kapitel vermutlich überspringen können. Aber es kann sich lohnen, sie zumindest zu überfliegen, um zu verstehen, wie diese Muster meiner Meinung nach angewandt werden sollten und warum die generelle Idee von Mustern für verteilte Systeme so wichtig ist.

Sehr wahrscheinlich wird jeder die Single-Node-Muster von Nutzen finden, da es sich bei ihnen um die generischsten und am besten wiederverwendbaren Muster im Buch handelt.

Abhängig von Ihren Zielen und den Systemen, an deren Entwicklung Sie interessiert sind, können Sie entscheiden, sich auf die Muster für die Verarbeitung großer Datenmengen oder auf die für lang laufende Server zu konzentrieren (oder auf beide). Beide Teile sind mehr oder weniger unabhängig voneinander und es gibt beim Lesen auch keine empfohlene Reihenfolge.

Wenn Sie schon umfangreiche Erfahrung mit verteilten Systemen haben, ist Ihnen der Inhalt einiger der ersten Muster-Kapitel (zum Beispiel in Teil II zu Naming, Discovery und Load Balancing) vielleicht schon bekannt – dann brauchen Sie diese natürlich nur zu überfliegen und können sich den fortgeschritteneren Techniken zuwenden. Vergessen Sie aber nicht, sich all die schönen Grafiken anzuschauen!

Konventionen in diesem Buch

Die folgenden typografischen Konventionen werden in diesem Buch genutzt:

Kursiv

Für neue Begriffe, URLs, E-Mail-Adressen, Dateinamen und Dateierweiterungen.

Nichtproportionalschrift

Für Programmlistings, aber auch für Codefragmente in Absätzen, wie zum Beispiel Variablen- oder Funktionsnamen, Datenbanken, Datentypen, Umgebungsvariablen, Anweisungen und Schlüsselwörter.

fette Nichtproportionalschrift

Für Befehle und anderen Text, der genau so vom Benutzer eingegeben werden sollte.

kursive Nichtproportionalschrift

Für Text, der vom Benutzer durch eigene Werte ersetzt werden sollte.

Dieses Symbol steht für einen Tipp, Vorschlag oder allgemeinen Hinweis.

Online-Ressourcen

Auch wenn dieses Buch allgemein anwendbare Muster für verteilte Systeme beschreibt, geht es davon aus, dass die Leser mit Containern und Systemen zur Container-Orchestrierung vertraut sind. Sind Ihnen diese Dinge noch eher unbekannt, empfehle ich die folgenden Ressourcen:

https://docker.io

https://kubernetes.io

https://dcos.io

Der Einsatz von Codebeispielen

Zusätzliches Material (Codebeispiele, Übungen und so weiter) finden Sie (auf Englisch) zum Herunterladen auf https://github.com/brendandburns/designing-distributed-systems.

Dieses Buch ist dazu da, Ihnen beim Erledigen Ihrer Arbeit zu helfen. Im Allgemeinen dürfen Sie die Codebeispiele aus diesem Buch in Ihren eigenen Programmen und der dazugehörigen Dokumentation verwenden. Sie müssen uns dazu nicht um Erlaubnis fragen, solange Sie nicht einen beträchtlichen Teil des Codes reproduzieren. Beispielsweise benötigen Sie keine Erlaubnis, um ein Programm zu schreiben, in dem mehrere Codefragmente aus diesem Buch vorkommen. Wollen Sie dagegen eine CD-ROM mit Beispielen aus Büchern von O’Reilly verkaufen oder verteilen, benötigen Sie eine Erlaubnis. Eine Frage zu beantworten, indem Sie aus diesem Buch zitieren und ein Codebeispiel wiedergeben, benötigt keine Erlaubnis. Eine beträchtliche Menge Beispielcode aus diesem Buch in die Dokumentation Ihres Produkts aufzunehmen, bedarf hingegen einer Erlaubnis.

Wir freuen uns über Zitate, verlangen diese aber nicht. Ein Zitat enthält Titel, Autor, Verlag und ISBN. Beispiel: »Verteilte Systeme mit Kubernetes entwerfen von Brendan Burns (O’Reilly). Copyright 2018 Brendan Burns, 978-3-96009-088-5.«

Wenn Sie glauben, dass Ihre Verwendung von Codebeispielen über die übliche Nutzung hinausgeht oder außerhalb der oben vorgestellten Nutzungsbedingungen liegt, kontaktieren Sie uns bitte unter [email protected].

Danksagung

Ich möchte mich bei meiner Frau Robin und meinen Kindern für all das bedanken, was sie getan haben, um mich glücklich und gesund zu halten. Danke auch an all die Leute, die sich die Zeit genommen haben, mir so viele Dinge beizubringen! Und ich danke meinen Eltern für diesen ersten SE/30.

KAPITEL 1

Einführung

Die heutige Welt der Always-on-Anwendungen und APIs stellt Anforderungen an Verfügbarkeit und Zuverlässigkeit, für die noch vor einiger Zeit eine Handvoll missionskritischer Systeme verteilt über die ganze Welt erforderlich gewesen wären. Genauso sorgt das Potenzial für ein schnelles und virales Wachstum eines Service dafür, dass jede Anwendung so gebaut werden muss, dass sie als Reaktion auf Benutzeranforderungen nahezu sofort skaliert. Diese Sachzwänge und Anforderungen führen dazu, dass so gut wie jede zu bauende Anwendung – sei es eine mobile App für Endverbraucher oder eine Backend-Payments-Anwendung – ein verteiltes System sein muss.

Aber das Bauen verteilter Systeme ist eine Herausforderung. Häufig handelt es sich um Unikate und die Entwicklung verteilter Systeme zeigt eine erstaunliche Ähnlichkeit zur Welt der Software-Entwicklung vor dem Entstehen moderner objektorientierter Programmiersprachen. Zum Glück brachte die Entwicklung wie bei objektorientierten Sprachen technische Fortschritte mit sich, die die Herausforderungen beim Bauen verteilter Systeme drastisch verringert haben. In diesem Fall ist es die wachsende Beliebtheit von Containern und Container-Orchestrierern. Wie beim Konzept der Objekte bei der objektorientierten Programmierung bilden diese containerisierten Bausteine die Grundlage für die Entwicklung wiederverwendbarer Komponenten und Muster, welche das Erstellen zuverlässiger verteilter Systeme drastisch vereinfachen und mehr Leuten zugänglich machen. In der folgenden Einführung gebe ich einen kurzen Überblick über die Entwicklungen, die zur heutigen Situation geführt haben.

Eine kurze Geschichte der System-Entwicklung

In den Anfängen gab es Maschinen, die für bestimmte Zwecke gebaut wurden, wie zum Beispiel das Berechnen von Artillerie-Tabellen oder den Tidenzeiten, das Entschlüsseln von Codes oder andere präzise und komplizierte mathematische Routine-Aufgaben. Schließlich entwickelten sich diese zweckgebundenen Maschinen zu allgemein programmierbaren Rechnern. Und irgendwann konnten diese Computer nicht nur ein Programm, sondern mehrere gleichzeitig ausführen – mithilfe von Timesharing-Betriebssystemen –, aber diese Computer waren immer noch getrennt voneinander.

Nach und nach wurden die Maschinen miteinander verbunden und es entstanden Client/Server-Architekturen, sodass auch recht schwachbrüstige Computer auf einem Schreibtisch genutzt werden konnten, um auf die größere Leistung eines Mainframes in einem anderen Raum oder Gebäude zugreifen zu können. Während diese Form der Client/Server-Programmierung schon etwas komplizierter war, als ein Programm für einen einzelnen Rechner zu schreiben, war es doch immer noch ganz gut zu verstehen. Der oder die Clients stellten Requests, der oder die Server beantworteten diese.

In den frühen 2000ern führte die zunehmende Verbreitung des Internets und großer Datacenter mit Tausenden verhältnismäßig günstiger, »normaler« Computer, die miteinander vernetzt sind, zu einer zunehmenden Entwicklung verteilter Systeme. Anders als Client/Server-Architekturen bestehen Anwendungen in verteilten Systemen aus vielen verschiedenen Anwendungen, die auf unterschiedlichen Maschinen laufen, oder aus vielen Replicas auf mehreren Rechnern, die alle miteinander kommunizieren, um ein System wie eine Websuche oder eine Verkaufsplattform zu implementieren.

Aufgrund der verteilten Natur der Systeme sind diese – bei ordentlichem Aufbau – inhärent zuverlässiger. Und wenn die Architektur sauber ist, können sie zu besser skalierbaren Organisationsmodellen für die Software-Entwicklungsteams führen, die diese bauen. Leider bringen diese Vorteile auch einen Preis mit sich. Die verteilten Systeme können signifikant komplizierter zu entwerfen, bauen und debuggen sein. Die erforderlichen Entwickler-Fähigkeiten zum Bauen eines zuverlässigen verteilten Systems sind deutlich umfangreicher als die, die zum Bauen einer Anwendung für einen Rechner gebraucht werden, wie für Mobile oder Web-Frontends. Aber der Bedarf nach zuverlässigen verteilten Systemen wächst trotzdem. Daher gibt es auch weiterhin zunehmenden Bedarf für die Werkzeuge, Muster und Praktiken, um sie zu bauen.

Zum Glück hat die verbesserte Technologie auch das Bauen verteilter Systeme vereinfacht. Container, Container-Images und Container-Orchestrierer sind in den letzten Jahren beliebt geworden, weil sie die Grundlage und Bausteine für zuverlässige verteilte Systeme legen. Mit Containern und Container-Orchestrierern als Grundlage können wir eine Reihe von Mustern und wiederverwendbaren Komponenten umsetzen. Diese sind ein Toolkit, auf das wir zum zuverlässigeren und effizienteren Bauen unserer Systeme zurückgreifen können.

Eine kurze Geschichte von Mustern in der Software-Entwicklung

Es ist nicht das erste Mal, dass solche eine Transformation in der Software-Branche abläuft. Um den Einfluss von Mustern, Praktiken und wiederverwendbaren Komponenten auf die frühere System-Entwicklung besser zu verstehen, hilft es, sich diese vergangenen Transformationen nochmals anzuschauen.

Formalisierung der algorithmischen Programmierung

Donald Knuths Sammlung The Art of Computer Programming (Addison-Wesley Professional) markiert einen wichtigen Meilenstein in der Entwicklung der Informatik, auch wenn vor der Veröffentlichung im Jahr 1962 schon über ein Jahrzehnt lang programmiert wurde. Insbesondere enthalten die Bücher keine Algorithmen, die für einen bestimmten Computer entworfen sind, sondern sie sollen dem Leser die Algorithmen selbst erklären. Diese Algorithmen können dann an die spezifische Architektur des eingesetzten Computers oder des zu lösenden Problems angepasst werden. Diese Formalisierung war wichtig, weil sie den Anwendern einen allgemein nutzbaren Werkzeugkasten zur Verfügung stellte, mit denen sie ihre Programme bauen konnten, aber auch, weil sie zeigte, dass es ein universelles Konzept gibt, das Programmierer lernen sollten, um es dann im Folgenden in verschiedensten Kontexten anzuwenden. Es lohnte sich, die Algorithmen selbst – unabhängig von einem zu lösenden spezifischen Problem – zu verstehen.

Muster für die objektorientierte Programmierung

Knuths Bücher repräsentieren einen wichtigen Meilenstein beim Nachdenken über Computer-Programmierung, und Algorithmen repräsentieren eine wichtige Komponente in der Entwicklung der Computer-Programmierung. Aber mit wachsender Komplexität der Programme und zunehmender Anzahl an Leuten, die an einem einzelnen Programm schreiben (von wenigen über Dutzende bis hin zu Tausenden), wurde klar, dass prozedurale Programmiersprachen und Algorithmen für die Aufgaben moderner Programmierung nicht ausreichend waren. Diese Änderungen in der Computer-Programmierung führten zur Entwicklung objektorientierter Programmiersprachen, die Daten, Wiederverwendbarkeit und Erweiterbarkeit zu Ebenbürtigen der Algorithmen machten.

Als Reaktion auf diese Veränderungen in der Programmierung gab es auch Änderungen an den Mustern und Praktiken. Während der frühen bis mittleren 1990er kamen haufenweise Bücher zu Mustern in der objektorientierten Programmierung heraus. Das bekannteste davon ist das der »Gang of Four«: Entwurfsmuster: Elemente wiederverwendbarer objektorientierter Software von Erich Gamma et al. (Addison-Wesley). In diesem Buch wurden eine gemeinsame Sprache und ein Framework für das Programmieren definiert. Es beschreibt eine Reihe Schnittstellenbasierter Muster, die sich in einer Vielzahl von Situationen einsetzen lassen. Aufgrund der Vorteile der objektorientierten Programmierung und insbesondere der Schnittstellen konnten diese Muster auch als allgemein wiederverwendbare Bibliotheken implementiert werden. Diese ließen sich einmalig von einer Entwickler-Community schreiben und dann wieder und wieder verwenden, wodurch Zeit gespart und die Zuverlässigkeit erhöht wurde.

Der Aufstieg von Open-Source-Software

Obwohl das Konzept, dass Entwickler gemeinsam Quellcode nutzen, schon nahezu seit Beginn des Computerzeitalters bekannt ist und formal freie Software-Organisationen seit Mitte der 1980er Jahre existieren, gab es in den späten 1990ern und 2000ern ein drastisches Wachstum bei der Entwicklung und Verbreitung von Open-Source-Software. Auch wenn Open Source nur am Rande mit der Entwicklung von Mustern für verteilte Systeme zu tun hat, ist es insoweit wichtig, dass durch die Open-Source-Communitys zunehmend klar wurde, dass Software-Entwicklung im Allgemeinen und verteilte Systeme im Speziellen gemeinschaftliche Anstrengungen erfordern. Es ist wichtig, darauf hinzuweisen, dass die gesamte Container-Technologie, die die Grundlage für die in diesem Buch beschriebenen Muster bildet, als Open-Source-Software entwickelt und freigegeben wurde. Der Wert von Mustern zum Beschreiben und Verbessern der Praktiken verteilter Entwicklung wird besonders dann klar, wenn Sie sie aus Sicht der Community betrachten.

Was ist ein Muster für ein verteiltes System? Es gibt eine Reihe von Anleitungen, die beschreiben, wie Sie bestimmte verteilte Systeme installieren (wie zum Beispiel eine NoSQL-Datenbank). Genauso gibt es Rezepte für eine Zusammenstellung bestimmter Systeme (wie einen MEAN-Stack). Aber wenn es um Muster geht, beziehe ich mich auf allgemeine Baupläne für das Organisieren verteilter Systeme, ohne bestimmten Technologien oder Anwendungen den Vorzug zu geben. Der Zweck eines Musters ist, allgemeine Ratschläge oder Strukturen zu bieten, an denen sich Ihr Design orientieren kann. Die Hoffnung ist, dass solche Muster Ihr Denken leiten und insgesamt auf viele verschiedene Anwendungen und Umgebungen anwendbar sind.

Der Wert von Mustern, Praktiken und Komponenten

Bevor Sie etwas von Ihrer wertvollen Zeit dafür aufwenden, etwas über eine Reihe von Mustern zu lesen, von denen ich behaupte, dass sie Ihre Entwicklungspraktiken verbessern, Sie etwas Neues lehren und – seien wir ehrlich – Ihr Leben verändern werden, dürfen Sie durchaus fragen: »Warum?« Worum geht es bei den Entwurfsmustern und Praktiken, die die Art und Weise ändern können, wie wir Software entwerfen und bauen? In diesem Abschnitt werde ich die Gründe erläutern, warum das meiner Meinung nach ein wichtiges Thema ist, und Sie hoffentlich davon überzeugen, mir für den Rest des Buches zu folgen.

Auf den Schultern von Riesen stehen

Als Ausgangsbasis ist der Wert, den Muster für verteilte Systeme bieten können, die Möglichkeit, im übertragenen Sinne auf den Schultern von Riesen zu stehen. Nur selten sind Probleme, die wir lösen wollen, oder Systeme, die wir bauen, wirklich einmalig. Vielleicht sind die Kombination aus Elementen, die wir zusammensetzen, und das gesamte Geschäftsmodell, das die Software ermöglicht, etwas, was die Welt noch nicht gesehen hat. Aber der Weg, auf dem das System gebaut wird, und die Probleme, die entstehen, weil es zuverlässig, agil und skalierbar sein soll, sind nicht neu.

Das ist daher der erste Wert von Mustern: Sie erlauben es uns, aus den Fehlern anderer zu lernen. Vielleicht haben Sie noch nie zuvor verteilte Systeme gebaut oder noch nie diese Art von verteilten Systemen. Statt also zu hoffen, dass ein Kollege in diesem Bereich ein bisschen Erfahrung hat, oder zu lernen, indem Sie die gleichen Fehler wie andere machen, können Sie Muster als Lotsen nutzen. Muster für die Entwicklung verteilter Systeme erlernen Sie genauso wie andere Best Practices im Computerumfeld. Sie beschleunigen Ihre Fähigkeit, Software zu bauen, ohne schon direkte Erfahrung mit den Systemen, Fehlern und Lehren aus erster Hand zu haben, die zum Kodifizieren der Muster geführt haben.

Eine gemeinsame Sprache für Gespräche über unsere Praktiken

Etwas über verteilte Systeme zu lernen und unser Verständnis dazu zu verbessern, ist nur der erste Wert eines gemeinsamen Satzes an Mustern. Muster haben auch für erfahrene Entwickler verteilter Systeme, die diese schon verstehen, einen Wert, denn sie liefern ein gemeinsames Vokabular, durch das wir uns gegenseitig schnell verstehen können. Dieses Verständnis bildet die Basis für die Weitergabe von Wissen und fortlaufendes Lernen.

Um dies besser zu verstehen, stellen Sie sich vor, wir nutzen beide das gleiche Objekt, um unser Haus zu bauen. Ich nenne dieses Objekt »Foo«, während Sie es als »Bar« bezeichnen. Wie lange werden wir uns über den Wert eines Foo im Gegensatz zum Bar unterhalten oder versuchen, die unterschiedlichen Eigenschaften von Foo und Bar zu diskutieren, bis wir bemerken, dass wir über das gleiche Objekt sprechen? Haben wir einmal erkannt, dass Foo und Bar das Gleiche sind, können wir endlich gegenseitig von der Erfahrung des anderen lernen.

Ohne gemeinsames Vokabular verschwenden wir Zeit mit unnötigen Diskussionen oder beim Erläutern von Konzepten, die andere verstehen, aber unter einem anderen Namen kennen. Daher ist ein weiterer Wert von Mustern, einen gemeinsamen Satz an Begriffen und Definitionen bereitzustellen, sodass wir unsere Zeit nicht mit Namensverwirrung verbringen und uns stattdessen direkt mit den Details und der Implementierung der zentralen Konzepte befassen können.

Ich habe das in der kurzen Zeit, in der ich mit Containern arbeite, schon erlebt. Dabei hat sich der Begriff des Sidecar-Containers (in Kapitel 2 beschrieben) in der Container-Community verbreitet. So müssen wir uns nicht mehr damit herumschlagen, was ein Sidecar ist, und können uns direkt darum kümmern, wie das Konzept genutzt werden kann, um ein bestimmtes Problem zu lösen. »Wenn wir ein Sidecar nutzen ...« – »Ja und ich kenne genau den Container, den wir dafür nehmen können.« Dieses Beispiel führt zum dritten Wert von Mustern – dem Erstellen wiederverwendbarer Komponenten.