Kapitel 4. Arbeiten mit einer relationalen Datenbank

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

Inzwischen solltest du eine gute Vorstellung davon haben, was Cloud Run ist und wie du es nutzen kannst, um deine Container-basierten Anwendungen auszuführen und zu skalieren. Cloud Run braucht jedoch Daten, um interessant zu sein. Ob diese Daten nun aus einer Blob Speicherung, einer Datenbank oder einer anderen API stammen, auch ein serverloser Container braucht Daten. In diesem Kapitel zeige ich dir, wie du eine relationale Datenbank mit Cloud Run nutzen kannst.

Eine relationale Datenbank ist die gängigste Art, Daten für deine Anwendung zu speichern. Ich möchte dir zeigen, wie du mit Cloud SQL arbeiten kannst, einer verwalteten relationalen Datenbank in der Google Cloud. Als verwalteter Dienst nimmt Cloud SQL dir viele operative Aufgaben ab. Er unterstützt MySQL, PostgreSQL und SQL Server, gängige Datenbank-Engines, die du überall einsetzen kannst. Solltest du dich jemals entscheiden, zu einem anderen Anbieter zu wechseln, hast du einen Ausweg.

In diesem Kapitel helfe ich dir beim Einstieg in Cloud SQL, zeige dir, wie du meine To-Do-Listen-Demo-Anwendung einsetzt und erkunde die verschiedenen Möglichkeiten, einen Cloud Run-Dienst mit Cloud SQL zu verbinden.

Cloud Run kann sehr schnell auf bis zu tausend (oder mehr) Container skalieren. Das kann zu Leistungsengpässen in nachgelagerten Systemen führen, z. B. in deiner Cloud SQL-Datenbank. Im letzten Teil dieses Kapitels erkläre ich dir, warum das so ist, und zeige dir, welche Möglichkeiten du hast, um deine Datenbank am Laufen zu halten, wenn es zu einem Engpass kommt.

Einführung in die Demo-Anwendung

Die Demo-Anwendung für dieses und das nächste Kapitel ist eine To-Do-Liste. Sie hat ein browserbasiertes Frontend und speichert die Aufgaben in einer MySQL-Datenbank. Es gibt viele Anwendungen, die ähnlich aufgebaut sind. Wenn du schon einmal mit einem Projekt gearbeitet hast, das eine ähnliche Architektur hatte, wirst du dich gleich wie zu Hause fühlen(Abbildung 4-1).

A Cloud Run service backed by a Cloud SQL database
Abbildung 4-1. Ein Cloud Run-Dienst, der von einer Cloud SQL-Datenbank unterstützt wird

Ich habe das Frontend nicht selbst gebaut. Ich verwende Todo-Backend,, ein Projekt, mit dem du einen Backend-Technologie-Stack präsentieren kannst. Ich habe nur ihre Backend-API auf Cloud Run mit einer Go-App implementiert - so kann ich die vorgefertigte Benutzeroberfläche nutzen.

Der Quellcode zum Erstellen der Demoanwendung ist auf GitHub zu finden. Alles, was du tun musst, ist, das Repository zu klonen und die Infrastruktur einzurichten. Ich werde dich Schritt für Schritt durch die Einrichtung deiner eigenen Version der Anwendung führen(Abbildung 4-2).

Abbildung 4-2. Die Demo-Anwendung für dieses Kapitel

Das wirst du tun:

  1. Richte die Voraussetzungen ein.

  2. Erstelle eine MySQL Cloud SQL-Instanz.

  3. Verbinde dich mit Cloud SQL, um das Schema zu initialisieren.

  4. Setze die Demo-Anwendung in Cloud Run ein.

Während ich dich durch die verschiedenen Schritte führe, zeige ich dir, was passiert und erkläre, wie die Dinge unter der Haube funktionieren.

Du kannst die gesamte App lokal mit Docker Compose ausführen, ohne eine Abhängigkeit von Google Cloud zu haben. In Kapitel 6 wird Docker Compose ausführlicher behandelt. Wenn du es nur ausprobieren willst, kannst du die App starten, indem du docker-compose up im Verzeichnis ausführst .

Erstellen der Cloud SQL-Instanz

Die Daten für die Aufgabenliste werden in MySQL gespeichert, einem quelloffenen, traditionellen relationalen Datenbankserver, der seit über zwei Jahrzehnten für Webanwendungen verwendet wird. Cloud SQL unterstützt auch PostgreSQL und SQL Server - du bist nicht auf MySQL beschränkt. In einem ersten Schritt aktivierst du Cloud SQL in deinem Google Cloud-Projekt:

gcloud services enable sqladmin.googleapis.com
gcloud services enable sql-component.googleapis.com

Der nächste Schritt ist die Erstellung der Cloud SQL-Instanz. Eine Cloud-SQL-Instanz ist eine virtuelle Maschine, auf der ein Datenbankserver läuft. Der Datenbankserver kann entweder MySQL, PostgreSQL oder SQL Server sein und verwaltet eine oder mehrere Datenbanken (die eigentlichen Tabellen und Datenzeilen).

Dieser create Befehl kann einige Zeit (drei bis fünf Minuten) in Anspruch nehmen. Achte darauf, dass du dieselbe Region verwendest, in der du deine Cloud Run-Dienste einsetzt( in diesem Beispielus-central1 ). Du kannst deine Cloud-SQL-Instanz und den Cloud-Run-Dienst zwar in verschiedenen Regionen betreiben, aber das erhöht die Abfrage-Latenz und die Kosten:

gcloud sql instances create sql-db \
--tier db-f1-micro \
--database-version MYSQL_8_0 \
--region us-central1

Der Befehl erstellt eine MySQL-Instanz (Version 8) mit dem Namen sql-db mit dem kleinsten verfügbaren Maschinentyp (Tier) - db-f1-micro - und verwendet MySQL als Datenbankserver. Obwohl wir diese Instanz nicht als Produktionsinstanz verwenden würden, ist sie perfekt für unsere Beispielanwendung.

Der Maschinentyp (Tier) ist wichtig: Die Menge an CPU, RAM, und Festplattenspeicher, die du bereitstellst, spielt eine wichtige Rolle für die Leistung deiner Anwendung. In der Regel haben größere Festplatten mehr verfügbare Ein-/Ausgabeoperationen pro Sekunde (IOPS); es ist oft sinnvoll, große Festplatten bereitzustellen, um diesen Vorteil zu nutzen. Mach dir aber nicht zu viele Gedanken über die Wahl der richtigen Schicht und Festplattengröße. Du kannst die Größe der Instanz später ändern und die automatische Erhöhung der Speicherung einschalten.

Hinweis

Cloud SQL ist nicht serverlos: Du zahlst für jede Minute, die diese Instanz aktiv ist. Ab September 2020 kostet eine db-f1-micro-Instanz etwa $9 (USD), wenn sie einen ganzen Monat lang in us-central1 läuft. Überprüfe die Preise für aktuelle Informationen. Sobald du die Instanz entfernst, werden dir keine Kosten mehr in Rechnung gestellt (wie das geht, erfährst du unter "Herunterfahren").

Verstehen des Cloud SQL Proxy

Du kannst dich mit Cloud SQL über eine direkte Verbindung oder über den Cloud SQL Proxy verbinden, was meiner Meinung nach der beste Weg ist. Ich werde später erklären, warum das besser ist. Zunächst möchte ich erklären, wie der Cloud SQL Proxy funktioniert(Abbildung 4-3).

Understanding Cloud SQL Proxy
Abbildung 4-3. Verstehen des Cloud SQL Proxy

Cloud SQL Proxy ist ein Programm, das du auf deinem lokalen Rechner ausführen kannst. Es stellt automatisch eine sichere SSL/TLS-Verbindung zum Cloud SQL Proxy Server her, der auf der Cloud SQL-Instanz neben dem Datenbankserver läuft.

Der Cloud SQL Proxy Server authentifiziert eingehende Verbindungen mit Cloud IAM. In Kapitel 6 werde ich tiefer in Cloud IAM eintauchen, aber hier ist, was du wissen musst, um dieses Kapitel zu verstehen: du nutzt Cloud IAM, um Rollen an eine Identität zu binden. Eine Rolle enthält eine Liste von Berechtigungen (Dinge, die du tun darfst). Eine Identität ist dein Benutzerkonto, und jeder Cloud Run-Dienst hat auch eine zugewiesene Identität, ein Dienstkonto. Servicekonten sind nicht-persönliche (Roboter-)Identitäten bei Google Cloud. Eine virtuelle Maschine der Compute Engine ist ebenfalls mit einem Servicekonto verbunden.

Eine dieser Rollen ist "Cloud SQL Client". Wenn eine Identität diese Rolle hat, kann sie sich mit allen Cloud SQL-Datenbankinstanzen im Projekt verbinden. Da du das Google Cloud-Projekt erstellt hast, hast du die Rolle "Eigentümer" für das Projekt und damit auch die Berechtigung, eine Verbindung zu Cloud SQL-Instanzen herzustellen.

Verbinden und Laden des Schemas

Jetzt erstellst du die Tabellen, die die Anwendung zum Laufen braucht. Beginne mit der Installation des Cloud SQL Proxy auf deinem lokalen Rechner mit gcloud:

gcloud components install cloud_sql_proxy

Mit dem Cloud SQL Proxy kannst du eine Verbindung zu dem MySQL-Datenbankserver herstellen. Um SQL-Befehle zu senden, brauchst du immer noch den MySQL-Client. Mac-Nutzer können den Client über Homebrew installieren:

brew install mysql-client

Wenn du ein anderes Betriebssystem verwendest, befolge die Schritte in der MySQL-Dokumentation, um den MySQL-Kommandozeilen-Client zu installieren.

Jetzt solltest du in der Lage sein, das Programm cloud_sql_proxy zu starten und mit dem MySQL-Client zu verbinden. Du kannst aber auch gcloud damit beauftragen, dies für dich zu erledigen. (Warum installierst du die Tools und benutzt sie nicht? Weil gcloud sie unter der Haube verwendet.) Wenn du aufgefordert wirst, ein Passwort einzugeben, kannst du die Eingabeaufforderung leer lassen und sofort Enter drücken:

gcloud beta sql connect sql-db --user root

Standardmäßig hat eine MySQL Cloud SQL-Instanz einen Root-Benutzer ohne Passwort. Ich zeige dir, wie du das bald ändern kannst, keine Sorge. Du solltest in der Lage sein, dich anzumelden und eine Eingabeaufforderung von MySQL zu erhalten. Gib den Befehl show databases ein, um alle Datenbanken aufzulisten, nur um sicherzugehen, dass alles funktioniert:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.13 sec)

Tippe exit um die Eingabeaufforderung zu schließen und dich abzumelden.

Nachdem du die Verbindung getestet hast, kannst du das Schema der Datenbank laden, um die Tabellen zu initialisieren. Erstelle zunächst die Datenbank mit dem Namen todo:

gcloud sql databases create todo --instance sql-db

Das Schema befindet sich in dem Repository mit dem Quellcode der App. Klone das Repository und öffne das Verzeichnis. Lade nun die Datei schema.sql mit gcloud (drücke bei der Eingabeaufforderung erneut Enter):

gcloud beta sql connect sql-db --user root < schema.sql

Du hast jetzt die Tabellen erstellt, die die Anwendung zum Laufen braucht. Jetzt ist es an der Zeit, die Sicherheit der Cloud SQL-Instanz zu verbessern.

Absicherung des Standardbenutzers

Standardmäßig hat die MySQL-Instanz einen Superuser, root, ohne Passwort, und jeder Host (%) kann sich verbinden:

$: gcloud sql users list --instance sql-db
NAME  HOST
root  %

Du bist durch eine Firewall auf der Cloud SQL-Instanz geschützt, die standardmäßig allen eingehenden Datenverkehr stoppt. Dennoch gibt es einen MySQL-Superuser ohne Passwort, der für jeden Host hinter der Firewall zugänglich ist. Ich weiß nicht, wie es dir geht, aber ich fühle mich dabei unwohl. Lösche den Benutzer mit diesem Befehl:

$: gcloud sql users delete root --host % --instance sql-db
root@% will be deleted. New connections can no longer be made using
this user. Existing connections are not affected.

Do you want to continue (Y/n)?

Deleting Cloud SQL user...done.

Jetzt kannst du den Benutzer in der MySQL-Datenbank neu anlegen, und er kann sich nur über den Cloud SQL Proxy anmelden:

$: gcloud sql users create root \
--host "cloudsqlproxy~%" \
--instance sql-db Creating Cloud SQL user...done. Created user [root].

Mit dem Flag --host schränke ich den Benutzer ein, sich nur über das Netzwerk namens cloudsqlproxy anzumelden. Dies macht sich die Tatsache zunutze, dass der MySQL-Datenbankserver und der Cloud SQL Proxy Server dasselbe private interne Netzwerk auf der Cloud SQL-Instanz nutzen, das cloudsqlproxy heißt (wie du in Abbildung 4-3 gesehen hast).

Das bedeutet, dass der Cloud SQL Proxy die Authentifizierung für uns übernimmt. Wenn sich der Root-Benutzer bei der MySQL-Instanz anmeldet, kannst du jetzt sicher sein, dass die Anmeldung von einer Identität mit der Cloud IAM-Rolle "Cloud SQL Client" stammt.

Hinweis

Der neue Root-Benutzer, den du erstellt hast, hat Superuser-Rechte. In dem Beispiel in diesem Kapitel lasse ich die Demoanwendung sich mit diesem Benutzer verbinden. In einem Produktionssystem solltest du das Prinzip der geringsten Rechte anwenden und einen separaten Benutzer ohne administrative Rechte für deine Anwendung erstellen und ein Passwort für den Root-Benutzer festlegen.

Ich werde nun etwas tiefer in die verschiedenen Optionen für die Verbindung zu Cloud SQL von Cloud Run aus eintauchen. Wenn du weißt, wie das funktioniert, zeige ich dir, wie du die Demo-Anwendung einsetzen kannst.

Verbindung zwischen Cloud Run und Cloud SQL

Der Cloud SQL Proxy, mit dem du dich gerade verbunden und das Schema geladen hast, ist auch auf Cloud Run als integrierter und verwalteter Dienst verfügbar(Abbildung 4-4). Es gibt noch eine andere Möglichkeit, sich mit Cloud SQL zu verbinden: über eine direkte Verbindung. Ich glaube nicht, dass du diese Möglichkeit nutzen solltest, da sie mehr Orchestrierung erfordert, um sicher zu sein.

Wenn du einen Cloud Run-Dienst einsetzt oder aktualisierst, kannst du ihn mit dem Flag --add-cloudsql-instances mit Cloud SQL verbinden. Dadurch wird deinem Container eine spezielle Datei im Verzeichnis /cloudsql/ hinzugefügt.

Ich weiß, das mag verwirrend klingen, aber auf einem UNIX-basierten System, kannst du eine Datei statt eines Ports verwenden, um auf eingehende Verbindungen zu warten. Das ist so ähnlich, als würdest du einen Port öffnen (z. B. localhost:3306) und auf neue Verbindungen warten. Die Datei wird UNIX Domain Socket genannt. Ich zeige dir, wie du sie verwendest, wenn du die Demoanwendung einsetzt.

Connecting to Cloud SQL using the managed Cloud SQL Proxy
Abbildung 4-4. Verbindung zu Cloud SQL über den verwalteten Cloud SQL Proxy

Deaktivieren der Direktverbindung

Die andere Möglichkeit, sich von Cloud Run aus zu verbinden, ist eine Direktverbindung (direkt zur IP der Cloud SQL-Instanz). Obwohl es sicherlich Anwendungsfälle für eine Direktverbindung gibt, empfehle ich sie nicht von Cloud Run aus.1 Die direkte Verbindung ist standardmäßig nicht verschlüsselt; du kannst SSL/TLS verlangen, aber das bedeutet, dass du Client-Zertifikate erstellen und sie sicher zu deinem Cloud Run-Container bringen musst. Die direkte Verbindung umgeht immer Cloud IAM, und du musst die Firewall-Regeln deiner Cloud SQL-Instanz verwalten.

Ich denke, du wirst mir zustimmen, dass die Verwendung des Cloud SQL Proxy bequemer und sicherer ist als eine direkte Verbindung. Um eine weitere Hürde für direkte Verbindungen zu schaffen, kannst du SSL/TLS für diese Verbindungen verlangen:

gcloud sql instances patch --require-ssl sql-db

Wenn du require-ssl einstellst, kann sich niemand über eine direkte Verbindung anmelden, solange du keine Client-Zertifikate erstellst.

Einsatz der Demo-Anwendung

Wenn die Datenbank eingerichtet und das Schema geladen ist, kannst du den Container bauen und die Demo-Anwendung bereitstellen. Baue den Container und übermittle ihn mit Cloud Build an Artifact Registry (ich verwende das Cloud-Run-Book-Repository, das wir in Kapitel 3 erstellt haben). Es kann eine Weile dauern, bis der Container gebaut ist:

PROJECT=$(gcloud config get-value project)
IMAGE=us-docker.pkg.dev/$PROJECT/cloud-run-book/todo

gcloud builds submit --tag $IMAGE

Jetzt kannst du den Container in Cloud Run bereitstellen. Achte auf und REGION. Achte darauf, dass sie mit der Region übereinstimmt, in der du die Cloud SQL-Datenbankinstanz bereitgestellt hast:

REGION=us-central1
DB_INSTANCE=$PROJECT\:$REGION\:sql-db

gcloud run deploy todo \
--add-cloudsql-instances $DB_INSTANCE \
--image $IMAGE \
--region $REGION \
--allow-unauthenticated \
--set-env-vars DB="mysql://root@unix(/cloudsql/$DB_INSTANCE)/todo"

Das --add-cloudsql-instances Flag weist Cloud Run an, sich mit einer Cloud SQL-Instanz zu verbinden , die durch ihren vollständigen Namen identifiziert wird, der wie folgt formatiert ist: (<project>:<region>:<instance>).

Die Anwendung selbst weiß, wie sie sich über den UNIX Domain Socket mit CloudSQL verbinden kann, weil du einen Verbindungsstring in der Umgebungsvariablen DB (--set-env-vars DB=...) übergibst. Ich werde im nächsten Abschnitt mehr darüber erzählen, aber zuerst solltest du überprüfen, ob die Demo-Anwendung funktioniert.

Sobald das Deployment erfolgreich war, kannst du die URL deines neuen Dienstes öffnen und deine To-Dos eingeben. Mit diesem Befehl kannst du überprüfen, ob sie tatsächlich in der Datenbank auftauchen :

$: gcloud beta sql connect sql-db --user root
Starting Cloud SQL Proxy 
[..SNIP..]
mysql> SELECT * FROM todo.todos;

Wenn deine To-Do-Einträge angezeigt werden, hast du die Cloud SQL-Datenbank erfolgreich erstellt, das Schema geladen und den Cloud Run-Dienst verbunden.

Verbindung String

Das Format, das ich für diesen Verbindungsstring verwende, stammt aus demGo-MySQL-Treiber-Paket. Du wirst feststellen, dass er den Pfad des Domain-Sockets enthält: unix(/cloudsql/<project>:<region>:<instance>). Ich verwende gerne Umgebungsvariablen, um Verbindungsstrings zu übergeben, weil das die App portabler macht. Ein Beispiel findest du in der Datei docker-compose.yml (Docker Compose werde ich in Kapitel 6 genauer erklären ).

Öffentliche und private IP

Du kannst eine Cloud SQL-Instanz mit einer öffentlichen IP und einer privaten IP erstellen. Die Standardeinstellung ist eine öffentliche IP - deine Instanzen sind vom öffentlichen Internet aus erreichbar und durch den Cloud SQL Proxy Server, die eingebaute Firewall und SSL/TLS mit einem Client-Zertifikat geschützt (wenn du SSL benötigst). Wenn du die Sicherheit deiner Cloud SQL-Instanz verbessern und möglicherweise die Latenzzeit erhöhen möchtest, kannst du deiner Cloud SQL-Instanz nur eine private IP zuweisen.

Eine private IP ist nur innerhalb deines Virtual Private Cloud (VPC) Netzwerks zugänglich. Sie bietet ein privates Netzwerk für Ressourcen in deinem Google Cloud-Projekt, wie z.B. eine Cloud SQL-Instanz, eine Memorystore-Instanz (die wir uns in Kapitel 5 ansehen werden), virtuelle Maschinen der Compute Engine und Container auf der Google Kubernetes Engine.

Da ein Cloud Run-Dienst nicht Teil der VPC ist, brauchst du einen VPC Connector, um mit privaten IPs zu kommunizieren(Abbildung 4-5). Ein VPC Connector erstellt einen Netzwerkpfad zwischen den Containern in deinem Cloud Run-Dienst und den privaten IPs in der VPC (einschließlich der privaten IP von Cloud SQL). Ich weiß, das ist jetzt vielleicht etwas viel für dich. Im nächsten Kapitel findest du eine praktische Anleitung für die Arbeit mit einem VPC Connector.

Du kannst Cloud Run mit Cloud SQL über --add-cloudsql-instances und den UNIX Domain Socket verbinden, der durch IAM geschützt ist, unabhängig davon, ob du eine private oder öffentliche IP verwendest.

Abbildung 4-5. Verwendung eines VPC Connectors zur Kommunikation mit privaten IPs

Begrenzung der Gleichzeitigkeit

Cloud Run kann aufgrund seiner schnellen Skalierbarkeit zu Problemen führen mit nachgelagerten Systemen, die nicht die Kapazität haben, viele Anfragen gleichzeitig zu verarbeiten. Ein traditioneller relationaler Datenbankserver wie MySQL, PostgreSQL oder SQL Server ist ein gutes Beispiel dafür: Selbst ein kleiner Datenbankserver kann problemlos 10.000 Transaktionen pro Sekunde bewältigen, aber wenn die Gleichzeitigkeit der Transaktionen 200 übersteigt, ist es mit ihm nicht mehr getan.

DieTransaktionsgleichzeitigkeit ist die Anzahl der Transaktionen (Abfragen), die der Datenbankserver gleichzeitig bearbeitet. Wenn mehr Kunden gleichzeitig auf deine Datenbank zugreifen wollen, steigt die Gleichzeitigkeit der Transaktionen. Um eine gute Leistung deines Datenbankservers zu erzielen, solltest du eher eine niedrige als eine hohe Gleichzeitigkeit wählen. Die optimale Gleichzeitigkeit von Transaktionen ist für jeden Workload anders, aber eine gängige Heuristik besagt, dass sie ein kleines Vielfaches der Anzahl der vCPUs des Rechners ist.

Cloud Run kann schnell auf eintausend Instanzen (oder mehr durch Quotenerhöhung) skalieren und deine relationale Datenbank überlasten. In diesem Abschnitt erkläre ich die Mechanismen und zeige, wie du die Gleichzeitigkeit verwalten kannst.

Transaktionsgleichzeitigkeit

Abbildung 4-6 zeigt, wie sich die Gleichzeitigkeit von Transaktionen und die Transaktionsrate zueinander verhalten. Die Transaktionsrate wird als abgeschlossene Transaktionen pro Sekunde (TPS) angegeben. Dies ist ein vereinfachtes Diagramm, aber die allgemeinen Grundsätze gelten für alle relationalen Datenbankserver, die du auf Cloud SQL verwenden kannst.

Saturating a relational database with concurrent transactions
Abbildung 4-6. Sättigung einer relationalen Datenbank mit gleichzeitigen Transaktionen

Das Diagramm zeigt, was passiert, wenn du die Gleichzeitigkeit von Transaktionen erhöhst, indem du mehr Clients hinzufügst. Zunächst steigt mit zunehmender Gleichzeitigkeit auch die Transaktionsrate stetig an. Ab einem gewissen Punkt wird die Kurve der Transaktionsrate jedoch immer flacher und erreicht ein Maximum, wenn die Transaktionsdauer zunimmt. Irgendwann kann die Transaktionsrate sogar sinken, wenn es zu Transaktions-Timeouts kommt und neue Verbindungen abgelehnt werden.

Es ist schwer, eine genaue Zahl für die optimale Gleichzeitigkeit von Transaktionen zu finden. Sie hängt von der Datenbank (Version), der Form und Größe deiner Daten und den Abfragen ab, die deine Anwendung sendet. Große Transaktionen mit vielen Abfragen wirken sich anders auf deinen Datenbankserver aus als viele kleine und gezielte SELECT Anweisungen. Erschwerend kommt hinzu, dass sich all diese Faktoren im Laufe der Zeit ändern, ebenso wie deine Anwendung.

Ressourcenkonkurrenz

Wie du in Abbildung 4-6 gesehen hast, steigt die Transaktionsdauer ab einem bestimmten Punkt an, wenn die Gleichzeitigkeit zunimmt. Der Grund dafür ist die Ressourcenkonkurrenz. Ein Ressourcenkonflikt entsteht, wenn mehrere Transaktionen gleichzeitig auf eine gemeinsame Ressource zugreifen wollen. Eine gemeinsam genutzte Ressource können Daten (z. B. eine Zeile, Tabelle oder ein Index) oder Systemressourcen (z. B. CPU oder Festplatte) sein. Das System muss zusätzliche Verarbeitungszeit aufwenden, um den Ressourcenkonflikt zu lösen, wodurch sich die Dauer der Transaktionen verlängert.

Sperren sind eine häufige Ursache für Ressourcenkonflikte. Wenn eine Transaktion exklusiven Zugriff auf einen Teil der Daten benötigt, sperrt die Datenbankmaschine die Daten. Wenn eine andere Transaktion zur gleichen Zeit exklusiven Zugriff benötigt, muss sie warten.

Skalierungsgrenzen und Pooling von Verbindungen

Ich zeige dir die verschiedenen Kontrollmöglichkeiten, mit denen du die Gleichzeitigkeit einschränken kannst. Du musst die richtigen Einstellungen für dein System herausfinden, indem du mit deinem Produktionssystem experimentierst und die Metriken kontinuierlich überwachst.

Es gibt zwei Möglichkeiten, die Gleichzeitigkeit von Transaktionen mit den Standardeinstellungen zu begrenzen. Sieh dir Abbildung 4-7 an.

Managing transaction concurrency with scaling boundaries and connection pools
Abbildung 4-7. Verwaltung der Gleichzeitigkeit von Transaktionen mit Skalierungsgrenzen und Verbindungspools

Die Skalierungsgrenze deines Cloud Run-Dienstes ist die erste Kontrolle. Sie begrenzt die maximale Anzahl von Containern, die Cloud Run hinzufügt, was wiederum die Anzahl der HTTP-Anfragen begrenzt, die gleichzeitig von einem Cloud Run-Dienst bearbeitet werden können.

Dieser gcloud-Befehl setzt die maximale Anzahl von Containern für den Dienst todo auf 100:

gcloud run services update todo \
--max-instances 100

Wenn alle Container ausgelastet sind, werden die Anfragen in der Warteschlange zurückgehalten, bis ein Slot in einem Container frei wird. Wenn die Last weiter ansteigt, kann es sein, dass du abgelehnte Anfragen mit dem HTTP-Antwortstatus 429 siehst.

Von deiner Anwendung aus kannst du die Gleichzeitigkeit weiter einschränken, indem du einen internen Verbindungspool verwendest. Ein Verbindungspool unterhält langlaufende Verbindungen zum Datenbankserver. Wenn dein Anwendungscode eine Abfrage senden will, leiht er sich exklusiv eine Verbindung aus dem Verbindungspool und gibt die Verbindung zurück, wenn er fertig ist. Auf diese Weise kannst du eine Verbindung für mehrere Abfrage-Threads freigeben. In der Demoanwendung habe ich die maximale Anzahl offener Verbindungen wie folgt festgelegt:

db.SetMaxOpenConns(2)

Mit dieser Einstellung wird die Gesamtzahl der aktiven Verbindungen zu Cloud SQL auf max. Instanzen × 2 begrenzt. Ein kleiner Verbindungspool stellt sicher, dass es immer Anfrage-Threads gibt, die bereit sind, eine Verbindung zu nutzen, wenn sie freigegeben wird.

Externer Verbindungspool

Du könntest in eine Situation geraten, in der du interne Verbindungspools nicht effektiv nutzen kannst, um die Gleichzeitigkeit zu begrenzen. In diesem Fall kannst du von der Verwendung eines externen Verbindungspools wie PgBouncer auf einer virtuellen Maschine der Compute Engine vor deiner PostgreSQL Cloud SQL-Instanz profitieren. Das ist ein fortgeschrittenes Setup, aber ich wollte dir die Lösung nicht vorenthalten - du könntest sie brauchen.

Ein externer Verbindungspool läuft auf einem Server und nimmt Verbindungen von deiner Anwendung entgegen. Er überlagert deine Transaktionen transparent mit einer begrenzten Anzahl bestehender Verbindungen zu der nachgelagerten Datenbank, genau wie ein interner Verbindungspool.

Chris Tippett hat ein sehr gut dokumentiertes GitHub-Repository zur Verfügung gestellt, das dir zeigt, wie das geht (für PostgreSQL). Um das Repository nutzen zu können, musst du Terraform erst einmal verstehen (siehe Kapitel 8).

Ein Beispiel aus der Praxis

Um das alles mit ein paar Zahlen aus der Praxis zu verdeutlichen, möchte ich ein Beispiel aus der Praxis nennen. Einer unserer Kunden ist www.yoursurprise.eu, ein Unternehmen, das personalisierte Geschenke herstellt und verkauft, wie z. B. individuell bedruckte Tassen, T-Shirts, Fotoalben und Sektgläser mit individuellen Gravuren. Das Unternehmen verschickt seine Produkte in ganz Europa (seine Website ist in 18 Sprachen verfügbar).

Ich habe ihnen geholfen, zu Google Cloud zu wechseln, als sie ihr lokales Rechenzentrum verlassen wollten. Das Geschenkgeschäft ist stark saisonabhängig. Rund um den Muttertag verlassen viele herzförmige Geschenke mit individuellen Fotodrucken die Produktionsstätten von YourSurprise. Die Weihnachtszeit ist ein weiterer Zeitraum mit hoher Nachfrage. Im Dezember 2019 bedeutete das, dass sie in der Spitzenzeit rund 10.000 MySQL-Transaktionen pro Sekunde abwickelten. MySQL läuft auf dem db-n1-standard-16 Tier, einer Cloud SQL-Maschine mit 16 vCPUs. Die optimale Gleichzeitigkeit der Transaktionen liegt bei etwa 110, was ein kleines Vielfaches der Anzahl der vCPUs der Cloud-SQL-Instanz ist.

Cloud SQL in der Produktion

Cloud SQL ist ein verwaltetes Produkt, mit dem du produktionsreife Funktionen erhältst. In den folgenden Abschnitten werden einige der Highlights vorgestellt.

Überwachung

Die Nutzung eines verwalteten Produkts wie Cloud SQL befreit dich nicht von allen betrieblichen Aufgaben. Du musst die Instanzen überwachen. Mit Cloud Monitoring kannst du Warnungen zur CPU-Auslastung einrichten. Wenn du einen anhaltenden Anstieg über ein bestimmtes Niveau hinaus feststellst, musst du möglicherweise auf eine größere Instanzstufe wechseln.

Automatische Erhöhung der Speicherung

Wenn du diese Funktion aktivierst, erhöht Cloud SQL automatisch die Speicherkapazität, wenn deine Festplatte voll wird. Diesen Überwachungsalarm kannst du abschalten.

Hohe Verfügbarkeit

Wenn du Hochverfügbarkeit aktivierst, erstellt Cloud SQL zwei Instanzen in verschiedenen Zonen innerhalb derselben Region. Wenn die primäre Instanz nicht mehr reagiert, übernimmt die sekundäre den Betrieb. Dieser Failover-Prozess kann einige Zeit in Anspruch nehmen, aber er ist schneller als ein Neustart des gesamten Servers.

Für diese Demoanwendung war eine Einzelzonenbereitstellung ausreichend (das ist die Standardeinstellung), aber in einer Produktionsumgebung solltest du Hochverfügbarkeit aktivieren.

Deine Anwendung gegen kurze Ausfallzeiten resilient machen

Es gibt einen wichtigen Vorbehalt: Selbst in einem Hochverfügbarkeits-Setup sollte deine Anwendung so konzipiert sein, dass sie kurzen Ausfällen von etwa einer Minute standhält. Das kann bei einem Failover oder bei Wartungsarbeiten passieren. Ich erwähne das, weil man leicht davon ausgehen kann, dass es in einer Hochverfügbarkeitslösung keine Ausfallzeiten gibt.

Die Nutzung eines verwalteten Produkts wie Cloud SQL befreit dich nicht von betrieblichen Aufgaben. Wenn du nur eine Sache tust, solltest du unbedingt automatische Backups aktivieren.

Abschalten

Die Cloud SQL-Datenbank, die du in diesem Kapitel erstellt hast, ist immer aktiv. Wenn du vergisst, sie zu stoppen, werden dir Kosten entstehen.

Mit gcloud sql instances listkannst du deine Cloud-SQL-Instanzen auflisten, die gerade aktiv sind. Es sollte nur die Instanz aufgelistet werden, die du in diesem Kapitel erstellt hast: sql-db. Entferne die Cloud SQL-Instanz:

gcloud sql instances delete sql-db

Du hast außerdem einen weiteren Cloud Run-Dienst eingerichtet. Du kannst ihn behalten - solange du keine Anfragen an ihn sendest, entstehen dir keine Kosten.

Zusammenfassung

In diesem Kapitel hast du eine Cloud SQL-Instanz eingerichtet und sie mit einem Cloud Run-Dienst verbunden. Du hast den Cloud SQL Proxy kennengelernt: wie du ihn von deinem lokalen Rechner aus nutzen kannst und dass er in Cloud Run integriert ist.

Der Cloud SQL Proxy verschlüsselt deine Verbindung automatisch und führt die Client-Authentifizierung mit Cloud IAM durch. Es ist praktisch, dass du die Zertifikate nicht selbst verwalten musst.

Du hast auch gelernt, dass die Begrenzung der Gleichzeitigkeit der Schlüssel zur Steuerung der Leistung deiner nachgelagerten Systeme ist. Du hast herausgefunden, welche Kontrollmechanismen du im Cloud Run-Dienst und in deiner Anwendung einsetzen kannst, um zu verhindern, dass deine Cloud SQL-Instanz überlastet wird, wenn dein Dienst plötzlich einen Datenverkehrsburst bewältigt.

Im nächsten Kapitel zeige ich dir, wie du mit HTTP-Sitzungen umgehst - ein weiterer wichtiger Aspekt von Webanwendungen. Da Cloud Run Einweg-Container verwendet, musst du Sitzungsdaten in einer Datenbank (oder alternativ auf dem Client) speichern. Eine Möglichkeit, Sitzungen in der Google Cloud aufzubewahren, ist Memorystore, eine verwaltete Redis-Datenbank. Ich zeige dir, wie du Memorystore mithilfe eines VPC Connectors mit deinem Cloud Run Service verbindest.

1 Auch wenn du eine private IP verwendest, ist es nicht empfehlenswert, unverschlüsselte Verbindungen zu nutzen.

Get Serverlose Anwendungen mit Google Cloud Run erstellen 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.