1 Punkte von GN⁺ 2024-09-13 | 1 Kommentare | Auf WhatsApp teilen
  • Im letzten Jahr wurde intensiv daran gearbeitet, genau zu verstehen, wie sich Rails-Anwendungen mit SQLite performant und stabil betreiben lassen
  • Dabei wurden verschiedene Erkenntnisse gewonnen, die hier geteilt werden sollen
  • Es wird erklärt, woher die Probleme kommen und wie sie gelöst werden können

Probleme mit SQLite und Rails

  • Standardmäßig ist eine Rails-Anwendung mit SQLite nicht sofort ohne Weiteres einsatzbereit
  • Mit etwas Anpassung und Feintuning lässt sich jedoch eine performante und stabile Anwendung erstellen
  • Für Rails 8 ist das Ziel, dass bereits die Standardeinstellungen produktionsreif sind

Demo-Anwendung "Lorem News"

  • Zur Erläuterung von Problemen und Lösungen wird die Demo-Anwendung "Lorem News" verwendet
  • Diese Anwendung ist ein Klon von Hacker News, in dem Nutzer Beiträge und Kommentare verfassen können

Performance-Tests

  • Die Performance wird mit der oha-Load-Test-CLI und einem Benchmark-Pfad innerhalb der Anwendung getestet
  • Die Leistung wird sowohl mit einzelnen als auch mit gleichzeitigen Anfragen gemessen

Hauptproblem: SQLITE_BUSY-Ausnahmen

  • SQLite verwendet Schreibsperren, um jeweils nur einen Schreibvorgang gleichzeitig zuzulassen
  • Wenn mehrere Verbindungen gleichzeitig versuchen, die Schreibsperre zu erhalten, treten SQLITE_BUSY-Ausnahmen auf
  • Zur Lösung dieses Problems sollten Immediate Transactions verwendet werden

Immediate Transactions

  • Standardmäßig verwendet SQLite den verzögerten Transaktionsmodus
  • Mit Immediate Transactions wird sofort versucht, die Schreibsperre zu erhalten, und bei einem Fehlschlag kann ein erneuter Versuch erfolgen
  • Mit dem sqlite3-ruby-Gem lässt sich der Standard-Transaktionsmodus auf den Immediate-Modus setzen

Timeout-Einstellungen

  • Über Timeout-Einstellungen in der Datei database.yml lassen sich SQLITE_BUSY-Ausnahmen reduzieren
  • Mit der busy_timeout-Einstellung von SQLite können Wiederholungsversuche für Schreibsperren konfiguriert werden

GVL-Problem (Global VM Lock)

  • Das sqlite3-ruby-Gem gibt den GVL beim Aufruf des SQLite-C-Codes nicht frei
  • Das verschlechtert die Parallelitäts-Performance
  • Mit busy_handler lässt sich der GVL freigeben und die Performance verbessern

Neuimplementierung von busy_timeout

  • busy_timeout wird neu implementiert, damit alle Abfragen mit derselben Frequenz erneut versucht werden
  • Dadurch wird verhindert, dass ältere Abfragen durch ein Timeout fehlschlagen

Performance-Verbesserungen

  • Zur Verbesserung der Performance sollten folgende Einstellungen angewendet werden
    • Immediate Transactions verwenden
    • Timeout konfigurieren
    • busy_handler verwenden
    • WAL-Modus (Write-Ahead Logging) verwenden
    • Getrennte Verbindungspools für Lese- und Schreibzugriffe verwenden

Zusammenfassung von GN⁺

  • Es geht um Performance-Probleme von Rails-Anwendungen mit SQLite und deren Lösungen
  • Mit Methoden wie Immediate Transactions, Timeout-Konfiguration, Freigabe des GVL, WAL-Modus und getrennten Lese-/Schreib-Verbindungspools lässt sich die Performance verbessern
  • Der Artikel ist sehr nützlich für Entwickler, die SQLite und Rails verwenden
  • Als andere Projekte mit ähnlichen Funktionen werden PostgreSQL und MySQL empfohlen

1 Kommentare

 
GN⁺ 2024-09-13
Hacker-News-Kommentare
  • Vorstellung von Oldmoes Litestack-Projekt

    • Wer SQLite und Rails verwendet, sollte sich Oldmoes Litestack-Projekt ansehen
    • Litestack ist ein Ruby-Gem, das die Leistungsfähigkeit von SQLite nutzt, um eine Dateninfrastruktur für Webanwendungen bereitzustellen
    • Es bietet SQL-Datenbank, schnellen Cache, leistungsfähige Job-Queue, zuverlässigen Message-Broker, Full-Text-Suchmaschine und Metrik-Plattform in einem Paket
    • Wird derzeit im Projekt eingesetzt und ich bin sehr zufrieden damit
  • Dank für den ausführlichen Artikel

    • Nützliche Informationen für alle, die SQLite-Webanwendungen skalieren möchten
    • Lässt sich auch über Rails hinaus auf andere Frameworks anwenden
    • Danke an den Autor
  • Empfehlung für alle, die mit SQLite arbeiten

    • Unabhängig von Sprache oder Framework sollte jeder, der mit SQLite arbeitet, diesen Artikel lesen
    • Er behandelt Probleme, die man vor einigen Jahren noch selbst lösen musste
    • Danke an den Autor
  • Frage zu einem FOSS-Analytics-System

    • Ich baue ein leicht zu installierendes FOSS-Analytics-System
    • Ereignisdaten sollen in eine separate SQLite-Datenbank geschrieben werden, um sie von den Daten der Hauptanwendung zu trennen
    • Es gibt Bedenken hinsichtlich der Skalierbarkeit bei mehr als 1000 Events pro Sekunde
    • Ich erwäge, Events im Serverspeicher zu halten und einmal pro Sekunde gebündelt zu schreiben
    • Ich frage nach Meinungen, ob das ein vernünftiger Ansatz ist, um viele DB-Schreibvorgänge in SQLite zu bewältigen
  • GVL-Problem des sqlite3-ruby-Gems

    • Das sqlite3-ruby-Gem gibt den GVL bei SQLite-Aufrufen nicht frei
    • Das scheint größtenteils eine sinnvolle Entscheidung zu sein
    • Bei Python-Erweiterungen wurde das möglicherweise anders entworfen
    • Das extralite-Gem gibt den GVL während des Blockierens frei, ist im Allgemeinen schneller und hat keine Nebenläufigkeitsprobleme
  • Setup für einen persönlichen Webservice

    • Einige Einstellungen, die ich in meinem persönlichen Webservice verwende:
      • PRAGMA journal_mode = WAL
      • PRAGMA busy_timeout = 5000
      • PRAGMA synchronous = NORMAL
      • PRAGMA cache_size = 1000000000
      • PRAGMA foreign_keys = true
      • PRAGMA temp_store = memory
      • Verwendung von BEGIN IMMEDIATE-Transaktionen
  • Frage zu Django

    • Dieser Artikel ist großartig
    • Ich frage mich, ob es eine ähnliche Lösung für Django gibt
    • ArchiveBox verwendet SQLite über Django und stößt oft auf die in Bezug auf Rails erwähnten Probleme
    • Es wäre gut, wenn es eine SQLite-Schicht-Lösung gäbe, die nicht alle Schreibvorgänge über einen anderen Kanal der App serialisiert
  • Frage zur Standardeinstellung von busy_timeout

    • Ein sehr informativer und gut geschriebener Artikel
    • Ich frage mich, warum die Standardmethode busy_timeout eine Verzögerung hat, die ältere Queries benachteiligt
    • Ich frage mich, warum das als Standardeinstellung sinnvoll ist
  • Meinung zur Verwendung von SQLite und Rails

    • Ich mag SQLite und Rails, aber das ist ähnlich, als würde man MS Access in einer Produktionsumgebung verwenden
  • Dank für das Lösen von Rails-Integrationsproblemen

    • Es freut mich immer, wenn jemand Integrationsprobleme löst und anderen hilft
    • Ich hoffe, dass diese Änderungen in die Standardkonfiguration von Rails aufgenommen werden
    • Ich betreibe eine Rails-App, bin aber vor einigen Jahren zu Postgres gewechselt und sehr zufrieden damit
    • Trotzdem ist es gut, weiterhin eine Alternative zu haben, und ich verwende SQLite für andere Aufgaben