Zum Inhalt springen
BlogDatenbankenDjango und SQL: Ihr dynamisches Duo für skalierende Datenbanken

Django und SQL: Ihr dynamisches Duo für skalierende Datenbanken

Datenbanken mit Django und SQL-BlogHeader skalieren

Die Skalierung und Optimierung von Datenbanken, um den Anforderungen Ihrer Anwendungen gerecht zu werden, kann eine große Herausforderung darstellen. Wenn Sie meinen jüngsten Blog darüber, wie Django die schwere Arbeit für Python und SQL-Datenbankanwendungen erledigen kann, noch nicht gelesen haben, empfehle ich Ihnen dringend, ihn zu lesen. Aber die Kurzfassung ist, dass SQL für SQL-Datenbanken optimiert ist, Python nicht, und Django ist ein großartiger Vermittler, der Ihnen hilft, effektivere Anwendungen zu erstellen, mit weniger Reibung, Komplexität und Code, wenn Sie diese beiden Sprachen zusammen verwenden.

Während Django also die schwere Arbeit der Erstellung der Datenbankanwendung übernimmt, sind Sie weiterhin für die tägliche Verwaltung und Überwachung Ihrer Datenbanken verantwortlich. Einige dieser Verwaltungsaufgaben können an Ihren Cloudanbieter übertragen werden, indem Sie Dienste wie Linode Managed Databases nutzen, aber Sie könnten bei der Skalierung neue Hindernisse entdecken, wie z. B.:

  • Datenbank-Migrationen. Konvertierung einer bestehenden Datenbank in einen neuen, gewünschten Zustand mit kontrollierten Änderungen am Datenbankschema.
  • Multi-Datenbank-Einsätze. Um die Leistung zu optimieren, können Entwickler ihre Anwendungen so konzipieren, dass sie separate Datenbanken für segmentierte Funktionen verwenden. Zum Beispiel eine primäre Lese-/Schreib-Datenbank und eine Lese-Replikat-Datenbank für allgemeine Abfragen.

Wenn eine Ihrer Datenbanken SQL verwendet, können Sie Django einsetzen, um die Reibungsverluste zu verringern und Ihr Leben zu erleichtern, während Sie eine große Menge an Daten verarbeiten.

Diese Einführung in zwei wichtige Konzepte der Datenbankverwaltung passt zu den Schritt-für-Schritt-Anleitungen für die Erstellung einer produktionsreifen Django-Anwendung, die Sie im E-Book Understanding Databases und in meiner neuen Lehrvideo-Serie finden. Beide Lernpfade werden Ihnen helfen, Django dazu zu bringen, die schweren SQL-Aufgaben für Sie zu erledigen.

Datenbank-Migrationen
Am Anfang kann es schwierig sein, die richtigen Datentypen für eine bestimmte Spalte zu finden, zumal sich Ihre Datenanforderungen im Laufe der Zeit unweigerlich ändern werden. Was ist, wenn Ihr Titelfeld nur 80 Zeichen lang sein soll? Was ist, wenn Sie ein Zeitstempelfeld hinzufügen müssen, damit Sie genau nachverfolgen können, wann Elemente zur Datenbank hinzugefügt wurden?

Das Ändern einer Tabelle, nachdem sie erstellt wurde, kann aus mehreren Gründen ziemlich unübersichtlich werden:

  • Was machen Sie mit bereits vorhandenen Werten?
  • Was ist, wenn in bereits vorhandenen Zeilen Daten für neue Spalten/Felder fehlen?
  • Was passiert, wenn Sie eine Spalte/ein Feld entfernen? Was passiert mit den Daten?
  • Was ist, wenn Sie eine Beziehung hinzufügen, die es vorher nicht gab (z. B. Fremdschlüssel)?

Zum Glück für Django-Entwickler haben wir etwas namens makemigrations und migrate.

Schauen wir uns einmal an, wie das in der Praxis funktioniert.

Hier ist unser Django-Beispiel-Datenmodell:

class BlogArticle(models.Model):
    user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
    title = models.CharField(max_length=120)
    slug = models.SlugField(blank=True, null=True)
    content = models.TextField(blank=True, null=True)
    publish_timestamp = models.DateTimeField(
        auto_now_add=False,
        auto_now=False,
        blank=True,
        null=True,
    )

Fügen wir das Feld hinzu:

updated_by = models.ForeignKey(
        User, related_name="editor", null=True, blank=True, on_delete=models.SET_NULL
)

Dieses Feld ermöglicht es uns, den letzten Benutzer zu verfolgen, der eine Änderung an unserem Modell vorgenommen hat. 

Aktualisieren wir unser Modell:

class BlogArticle(models.Model):
    user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
    title = models.CharField(max_length=120)
    slug = models.SlugField(blank=True, null=True)
    content = models.TextField(blank=True, null=True)
    publish_timestamp = models.DateTimeField(
        auto_now_add=False,
        auto_now=False,
        blank=True,
        null=True,
    )
    # our new field
    updated_by = models.ForeignKey(
        User, related_name="editor", null=True, blank=True, on_delete=models.SET_NULL
    )

Nachdem wir diese Datei gespeichert haben, wird diese BlogArticle Klasse deklariert ist in (models.py), wie können wir unserer Datenbank mitteilen, dass diese Änderung stattgefunden hat?

Es gibt zwei Möglichkeiten:

  1. python manage.py makemigrations
  2. python manage.py migrate

Lassen Sie uns besprechen, was diese beiden Befehle bewirken:

python manage.py makemigrations

python manage.py makemigrations sucht nach Veränderungen in alle models.py Dateien in Ihrem Django-Projekt und sucht nach Änderungen. Wenn Änderungen gefunden werden, wird eine neue python Datei mit der vorgeschlagene Änderungen dass unsere SQL-Datenbank braucht zu machen. Die vorgeschlagenen Änderungen sehen in etwa so aus:

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('articles', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='article',
            name='updated_by',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='editor', to=settings.AUTH_USER_MODEL),
        ),
    ]

Dies ist natürlich nur eine weitere Python Datei. Diese Datei teilt uns (den Entwicklern) mit, was in unserer Datenbank geschehen soll. Sie ist in Python und nicht in SQL geschrieben, um die Kohäsion zu wahren und die in Django ORM eingebauten Funktionen zu nutzen.

Aber warum ist dies eine Datei für das, was passieren sollte? Nun, dafür gibt es einige Gründe:

  • Wenn wir überprüfen müssen, was passieren soll, bevor es passiert, können wir das hier tun.
  • Diese makemigrations Befehl nicht prüfen mit die Datenbank, um zu sehen, ob diese Änderung kann sogar passieren.
  • Die Datenbank kann bereits geändert worden sein, um diese Anforderungen zu erfüllen (abhängig von einer Reihe von Faktoren, die damit zusammenhängen, wer/was die Datenbank verwaltet).
  • Wenn wir vor der Änderung einer Produktionsdatenbank Tests durchführen müssen, wäre jetzt ein hervorragender Zeitpunkt, dies zu tun.

Unter der Annahme, dass diese Änderung gültig ist (soweit wir das beurteilen können), können wir die Änderungen festschreiben:

python manage.py migrieren

python manage.py migrate wird versuchen, unsere Datenbank für uns zu ändern - alle Felder, Spalten, Tabellen, Fremdschlüssel, was auch immer - Django wird die Arbeit für uns erledigen, um sicherzustellen, dass die Datenbank so aktualisiert wird, wie wir es beabsichtigen.

Es ist wichtig zu wissen, dass Django diese Änderungen aus einer Reihe von Gründen nicht durchführen kann. Für neue Django-Entwickler ist dies fast immer auf das Hinzufügen und Entfernen von Feldern und Spalten und die nicht korrekte Ausführung von Migrationen zurückzuführen.

Wenn es richtig gemacht wird, python manage.py migrate sorgt für ein stabiles System, das unseren Python Code mit unseren SQL-Tabellen abgleicht und uns so alle Möglichkeiten bietet, die sowohl Django als auch SQL-Datenbanken bieten.

Inwiefern verschafft uns das mehr Flexibilität?

Python hat breite Anwendungsmöglichkeiten, die SQL nicht hat. Die Grenzen der strukturierten Abfragesprache sind bereits im Namen enthalten. Wer erstellt Pixar-Animationen nur mit SQL?

OK, all das soll heißen, dass die Einfachheit von Python den Entwicklern hilft, sich die Leistungsfähigkeit von SQL anzueignen, und das möglicherweise sogar ohne es zu wissen.

Warum verwaltete Datenbanken und Django sinnvoll sind

Wenn es darum geht, eine Webanwendung, einschließlich Django, zu erstellen, müssen Sie ein paar Dinge entscheiden:

  • Welche Datenspeicherlösung(en) wollen wir? MySQL, Postgres, MongoDB, Redis, Objektspeicher usw.
  • Wie werden wir mit der Datenspeicherlösung arbeiten/integriert?
  • Wie erholen wir uns von Unterbrechungen oder Ausfallzeiten?
  • Wie werden wir die Speicherlösung warten?
  • Wie werden wir unsere Speicherlösung sichern?
  • Wie werden wir unsere Speicherlösung sichern?

Die Antworten auf diese Fragen können sich mit zunehmender Komplexität Ihres Projekts ändern, aber sie beginnen alle an der gleichen Stelle: der Entscheidung zwischen Selbstverwaltung und Fremdverwaltung.

Selbstverwaltet:

  • Vorteile: Kontrolle und Kosten.
  • (Signifikant) Contra: Sie sind für alles verantwortlich.

Verwaltete Dienste sind oft von Anfang an teurer, während die Selbstverwaltung bedeutet, dass Sie Ihre bevorzugte Linux-Distribution verwenden können, die irgendwie (oder einigermaßen) für Ihre Bedürfnisse optimiert ist. Dazu kann auch eine von Ihrem Team modifizierte Version von MySQL gehören. Sie sparen vielleicht Geld beim Betrieb Ihres Dienstes, aber die Wartung wird immer mehr Zeit in Anspruch nehmen.

Verwaltete Datenbanken von Drittanbietern: 

Ja, es ist vielleicht etwas teurer in Dollar und Cent, aber der Wartungsaufwand ist deutlich geringer. Diese Option und verwaltete Datenspeicherlösungen sind meine de facto Wahl für meine Webanwendungen. In diesem Beispiel nutzen wir bereits Django, um Datenbanktransaktionen zu verwalten. SQLAlchemy teilt diese Stärke ebenfalls, da es mit Frameworks wie FastAPI, Flask und vielen anderen verwendet wird. Wenn Sie Ihre SQL-Schreibarbeiten bereits an ein Python -Paket auslagern, warum dann nicht auch den Betrieb Ihrer SQL-Server auslagern?

Angesichts der Effektivität von Python ORMs (wie Django ORM und SQLAlchemy) empfehle ich Ihnen, wann immer möglich, verwaltete Datenbanken und/oder verwaltete Datenspeicherdienste zu verwenden:

  • Verkürzte Entwicklungszeit
  • Geringere Verwaltungszeit
  • Verkürzte Erholungszeit
  • Geringere Betriebsunterbrechungen
  • Geringere Komplexität bei Bereitstellung und Entwicklung
  • Geringere Komplexität bei Datenbankmigrationen (von anderen Diensten)
  • Reduzierung repetitiver/ineffektiver/ineffizienter Tätigkeiten für SQL-Entwickler
  • Reduzierte DevOps/Ops-Komplexität
  • Erhöhte Effektivität von Nicht-SQL-Entwicklern
  • Höhere Bereitstellungs- und Entwicklungsgeschwindigkeit
  • Erhöhte Zuverlässigkeit (oft durch ein Service Level Agreement abgesichert)
  • Erhöhte Sicherheit
  • Erhöhte Wartungsfreundlichkeit
  • Verstärkte Backups und Redundanz
  • Geringfügiger Anstieg der Kosten

Ich habe die obige Liste mit dem Gedanken erstellt, ein verwaltetes MySQL-Datenbankcluster auf Linode sowie Linode-Objektspeicher (zum Speichern von Dateien wie CSS, JavaScript, Bilder, Videos usw.) zu verwenden. Praktisch gesehen hilft uns die Nutzung dieser Services dabei, uns auf die Erstellung einer hervorragenden Webanwendung mit Django, FastAPI, Flask, Node.js oder etwas anderem zu konzentrieren. Anders ausgedrückt: Wir verlagern den Schwerpunkt auf die Entwicklung der Tools und Software, die Ihre Nutzer tatsächlich benötigen, also auf den realen Mehrwert.

MySQL, PostgreSQL, Redis und Django

Für eine lange Zeit war PostgreSQL die führende Datenbank von Django. Ich würde behaupten, dass dies zu einem großen Teil auf die Tatsache zurückzuführen ist, dass man ein JSONField nur innerhalb von Postgres verwenden konnte. Mit Django 3.2+ und MySQL 5.7.8+ ist das JSONField nun auch für MySQL verfügbar.

Warum ist das wichtig?

Die Speicherung unstrukturierter Daten, wie JSON, ist häufig erforderlich, wenn es um die Verarbeitung von nutzergenerierten Inhalten oder die Speicherung von Daten aus anderen API Diensten. Lassen Sie uns sehen, wie:

from django.db import models

class Pet(models.Model):
    name = models.CharField(max_length=200)
    data = models.JSONField(null=True)

    def __str__(self):
        return self.name

Hier sind die Daten, die ich im Zusammenhang mit diesem Pet speichern möchte:

pet1 = {
    "name": "Bruno",
    "type": "Rat",
    "nickname": "We don't talk about it",
    "age": 2,
    "age_interval": "months"
}

pet2 = {
    "name": "Tom",
    "type": "Cat",
    "breed": "Mixed"
    "age": 4,
    "age_interval: "years",
    "favorite_food": [{"brand": "Acme", "flavor": "Tuna" }]
}

pet3 = {
    "name": "Stewey",
    "type": "Dog",
    "breed": "unknown"
    "age": 34,
    "age_interval: "dog years",
    "nickname": "Football"
}

Diese Daten zeigen uns, wann wir möglicherweise eine JSONField . Wir können alle Namen der Haustiere speichern (unter Verwendung der name Schlüssel) und der Rest wird im JSONField gespeichert. Das Tolle an JSONFields ist, dass sie wie jedes andere standardmäßige Django-Feld abgefragt werden können, auch mit diesen unterschiedlichen Schemata.

Unter Django-Entwicklern gibt es eine anhaltende Debatte darüber, welche Datenbank zu verwenden ist: MySQL oder PostgreSQL. Die längste Zeit habe ich mich immer für PostgreSQL entschieden, weil JSONField nur auf PostgreSQL verfügbar war. Ich sage, suchen Sie sich eine aus und bleiben Sie dabei, bis sie Ihren Bedürfnissen nicht mehr gerecht wird.

Aber wofür verwenden wir Redis?

Redis ist ein In-Memory-Datenspeicher, der unglaublich schnell ist und oft als temporäre Datenbank (mehr dazu in einer Sekunde), als Caching-Dienst und/oder als Messaging-Queue verwendet wird. Der Grund, warum ich ihn als temporäre Datenbank bezeichne, ist die Tatsache, dass er speicherintern ist. Arbeitsspeicher ist oft teurer als Festplattenspeicher, so dass eine langfristige Speicherung von Daten im Arbeitsspeicher oft nicht machbar ist.

Mein primärer Anwendungsfall für Redis und Django sind Caching und Queuing

Caching: Angenommen, Sie haben mehrere Webseiten, die von den Benutzern häufig besucht werden. Sie möchten, dass die Daten auf diesen Seiten den Benutzern so schnell wie möglich angezeigt werden. Redis, als Cachesystem für Django, macht dies unglaublich einfach. Die Daten auf diesen Seiten können aus einer SQL-Datenbank gerendert werden, aber Redis kann diese gerenderten Daten im Cache speichern. Mit anderen Worten, die Verwendung von Redis mit SQL kann Ihre Antworten oft beschleunigen und gleichzeitig die Anzahl der Abfragen an Ihre SQL-Datenbanken reduzieren.

Warteschlangen: Ein weiterer beliebter Anwendungsfall von Redis ist das Auslagern lang laufender Aufgaben an einen anderen Prozess (oft über ein Python Paket namens Celery). Wenn Sie dies tun müssen, können Sie Redis als Warteschlange für die Aufgaben verwenden, die zu einem anderen Zeitpunkt erledigt werden sollen.

Wenn Sie zum Beispiel einen Benutzer haben, der einen Bericht über alle seine Transaktionen der letzten fünf Jahre benötigt, kann die Software Stunden brauchen, um diesen Bericht zu erstellen. Natürlich wird niemand stundenlang auf einen Rechner starren. Daher würden wir diese Anfrage von unserem Benutzer in eine Redis-Warteschlange auslagern. Einmal in Redis, können wir einen Worker-Prozess laufen lassen (wie bei der Verwendung von Celery mit Django), um den Bericht tatsächlich zu erstellen. Sobald der Bericht fertig ist, egal wie lange er gedauert hat, würde der Benutzer benachrichtigt werden. Diese Benachrichtigung, wie auch andere Benachrichtigungen, könnte auch über eine Redis-Warteschlange in Verbindung mit einem Celery/Django-Arbeitsprozess erfolgen.

Das heißt, Redis und MySQL ergänzen sich eigentlich sehr gut. Sie können einen selbstverwalteten Redis-Datenbankserver über die Linode Marketplace bereitstellen.

Object Storage

Der letzte datenbezogene verwaltete Dienst, den ich empfehle, ist Linode-Objektspeicher. Dieser ist für all die anderen Arten von Daten zuständig, die Sie möglicherweise speichern müssen. Wir würden zum Beispiel nicht alle Bytes eines Videos in MySQL speichern. Stattdessen würden wir Metadaten zu diesem Video speichern und das Video im Objektspeicher ablegen.

Hier sind einige Dinge, für die Sie Objektspeicher verwenden würden:

  • Cascading Style Sheets (CSS)
  • JavaScript (wie React.js, Vue.js, Vanilla.js, usw.)
  • Videos
  • Images (roh und komprimiert)
  • CSVs, XLSX
  • Datenbank Backups
  • Docker-Container-Image-Schichten (wenn selbst verwaltet)
  • Iterationen von trainierten Algorithmen für maschinelles Lernen
  • Terraform Staatliche Akten
  • PDF-Dateien (sowohl große als auch kleine)
  • Jede dauerhafte Datei, die häufig heruntergeladen (oder hochgeladen) werden muss

Zusammenfassung

Ich hoffe, Sie fühlen sich nach dieser Lektüre motiviert, die Leistungsfähigkeit von Managed Services für Ihre Webanwendungsprojekte zu nutzen. Django ist eine hervorragende Lösung für die Entwicklung von Webanwendungen auf der Grundlage von SQL-Datenbanken, aber es ist sicherlich nicht die einzige Lösung. Wenn Sie in die Interna von SQL und SQL-Servern eintauchen wollen, ist es eine lohnende Übung zu sehen, wie viele erfolgreiche Anwendungen Django nutzen, um den Großteil dessen zu bewältigen, was Django kann.

Hier sind ein paar (oder viele) Highlights, die Django mit Managed MySQL auf Linode großartig machen:

  • Django übernimmt die schweren SQL-Aufgaben für Sie (dies gilt auch für Tools wie SQLAlchemy für Flask/FastAPI)
  • Django ermöglicht auch rohe SQL-Befehle (dies gilt auch für Tools wie SQLAlchemy)
  • Django hilft Anfängern beim Erlernen von SQL-Befehlen
  • Django hat integrierte Unterstützung für MySQL und PostgreSQL (zusätzlich zu einem db-spezifischen python Client)
  • Erhöht die Geschwindigkeit der Produktionsbereitstellung
  • Erhöhte Zuverlässigkeit und Wiederherstellbarkeit
  • Ermöglicht es, dass Entwicklungs- und Produktionsumgebungen fast genau der Datenbanktechnologie entsprechen
  • Erleichtert und erhöht die Zuverlässigkeit von Django auf Containerbasis
  • Ermöglicht die Skalierung von einem Ein-Knoten-Einsatz zu einem Mehr-Knoten-Einsatz oder sogar die vollständige Umstellung auf Kubernetes
  • Einfacher für neue Django/Python -Entwickler, produktionsreife Systeme zu nutzen
  • Die gemeinsame Nutzung von Datenbanken durch mehrere python-basierte Anwendungen ist einfacher und sicherer (z. B. eine FastAPI-Anwendung, die von/auf eine Django-basierte MySQL-Datenbank liest/schreibt).
  • Django's JSONField wird jetzt auch von MySQL unterstützt (vorher nur PostgreSQL)
  • Einfach zu testen (während CI/CD oder in lokalen Entwicklungsumgebungen)
  • Skalierbar für die Anforderungen von Django
  • Unterstützung für mehrere Datenbanken in einem einzigen Django-Projekt, z. B.: Verwendung von MySQL als primäre Lese-/Schreibdatenbank und einer MySQL-Lesereplikat-Datenbank für allgemeine Abfragen.
  • Strenge Zugangskontrollen (Linode Private IPs, lokale Entwicklung)
  • Erfordert SSL-Zertifikat für die Verbindung (erhöht die Komplexität der Bereitstellung, aber auch die Sicherheit)
  • Ermöglicht privaten Anschluss (in derselben Region; senkt die Anschlusskosten)

Wenn Sie an einem modernen Ansatz für die Bereitstellung von Django-Anwendungen auf Linode zusammen mit einer verwalteten MySQL-Datenbank, GitHub-Aktionen für CI/CD, Terraform und Ansible interessiert sind, finden Sie hier tonnenweise kostenlose Schritt-für-Schritt-Lerninhalte:

Um Ihnen den Einstieg zu erleichtern, finden Sie auf dem Coding for Entrepreneurs GitHub ein Repository mit Code, der zu jedem Schritt der Serie gehört. Viel Glück, und lassen Sie mich über Twitter @JustinMitchel wissen, wie es läuft.


Kommentare

Kommentar abgeben

Ihre E-Mail Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit *gekennzeichnet