16 Punkte von GN⁺ 2026-01-15 | 2 Kommentare | Auf WhatsApp teilen
  • Rails 8 entfernt die Redis-Abhängigkeit aus dem Standard-Stack und stellt mit SolidQueue, SolidCache und SolidCable alle Aufgaben auf relationale Datenbanken (RDB) um
  • Redis ist schnell und zuverlässig, verursacht aber operative Komplexität bei Konfiguration, Sicherheit, Cluster-Verwaltung und Backups
  • SolidQueue nutzt die PostgreSQL-Funktion FOR UPDATE SKIP LOCKED, um parallele Verarbeitung ohne Konkurrenz zu ermöglichen
  • Wiederkehrende Jobs, Concurrency Control, Monitoring-Dashboard (Mission Control) und andere kostenpflichtige Funktionen aus dem Redis+Sidekiq-Umfeld werden kostenlos bereitgestellt
  • Für die meisten Rails-Anwendungen reicht SolidQueue aus; nur in einigen Fällen mit extrem hoher Geschwindigkeit oder Echtzeitverarbeitung sollte Redis beibehalten werden

Die versteckten Kosten von Redis

  • Neben den reinen Hosting-Kosten bringt Redis laufenden Verwaltungsaufwand mit sich, etwa für Installation, Wartung, Sicherheitskonfiguration und HA-Cluster-Management
    • Erforderlich sind Netzwerkverbindungen und Firewall-Konfiguration zwischen Rails und Redis, Client-Authentifizierung sowie die Orchestrierung von Sidekiq-Prozessen
  • Im Fehlerfall müssen Redis und das RDBMS gleichzeitig debuggt werden; zusätzlich ist eine doppelte Backup-Strategie nötig
  • Bei einem Rails-Stack ohne Redis muss dagegen nur ein einziges PostgreSQL-System verwaltet werden, was alles deutlich vereinfacht

So funktioniert SolidQueue

  • Mit PostgreSQLs FOR UPDATE SKIP LOCKED holen sich mehrere Worker gleichzeitig Jobs, ohne Lock Contention zu erzeugen
  • Zentrale Tabellenstruktur
    1. solid_queue_jobs: speichert Job-Metadaten
    2. solid_queue_scheduled_executions: wartet auf geplante Jobs
    3. solid_queue_ready_executions: Queue für ausführungsbereite Jobs
  • Worker-, Dispatcher-, Scheduler- und Supervisor-Prozesse pollen in regelmäßigen Abständen unterschiedliche Tabellen und arbeiten zusammen
  • Dank PostgreSQLs MVCC-Architektur und autovacuum lassen sich auch große Mengen an Insert- und Delete-Operationen stabil verarbeiten

Planung wiederkehrender Aufgaben

  • SolidQueue bietet cron-artige wiederkehrende Jobs standardmäßig und wird über die Datei config/recurring.yml konfiguriert
  • Der Scheduler legt fällige Jobs in die Queue und plant den nächsten Ausführungszeitpunkt automatisch
  • Die Bibliothek Fugit parst natürliche Zeitpläne, und Concurrent::ScheduledTask erzeugt die Threads
  • Übernommen wurde der deterministische Scheduling-Ansatz von GoodJob, sodass Zeitpläne auch nach Prozessneustarts erhalten bleiben

Funktionen zur Concurrency Control

  • SolidQueue unterstützt mit einem POSIX-Semaphor-Muster die Begrenzung gleichzeitiger Ausführungen pro Job-Einheit
    • Beispiel: Mit limits_concurrency to: 1, key: ->(user) { user.id } wird pro Benutzer nur ein Job gleichzeitig ausgeführt
  • Durch das Setzen einer Semaphore-Ablaufzeit (duration) lassen sich Job-Konflikte und Deadlocks vermeiden
  • Zugehörige Tabellen
    • solid_queue_semaphores: verfolgt Concurrency-Limits
    • solid_queue_blocked_executions: speichert wartende Jobs

Monitoring mit Mission Control

  • Mission Control Jobs ist ein kostenloses Open-Source-Dashboard für Rails 8 und lässt sich einfach unter dem Pfad /jobs mounten
  • Wichtige Funktionen
    • Echtzeitstatus der Queues, Nachverfolgung fehlgeschlagener Jobs sowie Steuerung von Retry/Discard
    • Visualisierung von Zeitachsen für geplante und wiederkehrende Jobs
    • Durchsatz- und Metrikdiagramme pro Queue
  • Da Abfragen auf SQL basieren, ist direkte Analyse in der Datenbank ohne zusätzliche Tools möglich

Migration von Sidekiq zu SolidQueue

  • Schritt 1: config.active_job.queue_adapter = :solid_queue setzen
  • Schritt 2: bundle add solid_queue ausführen, danach rails solid_queue:install und db:migrate
  • Schritt 3: Cron-Schedules aus sidekiq.yml nach recurring.yml übertragen
  • Schritt 4: In der Procfile jobs: bundle exec rake solid_queue:start ergänzen
  • Schritt 5: Redis- und Sidekiq-bezogene Gems entfernen
  • Vorhandener ActiveJob-Code funktioniert unverändert weiter

Wann Redis weiterhin nötig ist

  • Dauerhafte Verarbeitung von mehreren tausend Jobs pro Sekunde
  • Echtzeitsysteme, bei denen Latenz unter 1 ms zwingend erforderlich ist
  • Bedarf an komplexen Pub/Sub-Strukturen oder ausgefeiltem Rate Limiting bzw. Counter-Operationen
  • Als Beispiel betreibt Shopify 833 Requests pro Sekunde und 1.172 Worker-Prozesse und nutzt dafür eine Redis-Infrastruktur

Leitfaden für die praktische Implementierung

  • Beim Erstellen einer neuen Rails-8-App werden SolidQueue, SolidCache und SolidCable automatisch konfiguriert
  • In config/database.yml wird eine separate Queue-Datenbankverbindung empfohlen
  • Authentifizierung für Mission Control hinzufügen und die Route /jobs mounten
  • Procfile.dev um jobs: bundle exec rake solid_queue:start ergänzen und dann alles mit bin/dev starten
  • Nach dem Erzeugen von Test-Jobs lässt sich ihr Status in Mission Control prüfen

Häufige Probleme und Lösungen

  • Auch eine Single-Database-Konfiguration ist möglich, reduziert aber die betriebliche Flexibilität
  • In Mission Control in Produktion sollte unbedingt Authentifizierung aktiviert werden
  • Die Standardwerte für das Polling-Intervall – 1 Sekunde für geplante Jobs, 0,2 Sekunden für sofortige Jobs – passen für die meisten Anwendungen
  • Bei Nutzung von ActionCable/Turbo Streams sollte SolidCable mit einer separaten Datenbankverbindung konfiguriert werden

Skalierbarkeit und Performance

  • SolidQueue skaliert für die meisten Rails-Anwendungen ausreichend
  • Auf PostgreSQL-Basis sind 200 bis 300 Jobs pro Sekunde möglich, und 37signals verarbeitet 20 Millionen Jobs pro Tag ohne Redis
  • Vergleichstabelle
    Punkt Redis + Sidekiq SolidQueue
    Konfigurationsaufwand Separater Service nötig Integrierte DB
    Abfragesprache Redis-Befehle SQL
    Monitoring Separates Dashboard Mission Control
    Fehlerszenarien 6 oder mehr 2
    Durchsatz Tausende Jobs/Sek. 200–300 Jobs/Sek.
    Geeignet für 99,9 % Apps 95 % Apps

Fazit

  • Redis und Sidekiq sind hervorragende Technologien, verursachen aber für die meisten Rails-Anwendungen unnötige Komplexität und zusätzliche Kosten
  • SolidQueue ermöglicht auf Basis einer einzigen Datenbank einfacheren Betrieb, geringere Kosten und effizientere Wartung
  • Für das Rails-8-Zeitalter wird der Umstieg auf SolidQueue als Standardwahl empfohlen

2 Kommentare

 
kaydash 2026-01-17

Redis ist gut.

 
GN⁺ 2026-01-15
Hacker-News-Kommentare
  • Ich finde, jeder Open-Source-Autor hat das Recht, den Umfang seines Projekts zu kontrollieren
    Allerdings bereuen wir im Team, von good_job auf SolidQueue umgestiegen zu sein
    Basecamp ist MySQL-zentriert und akzeptiert daher keine RDBMS-Engine-spezifischen Queries. In den GitHub-Issues sieht man, dass der Fokus fast nur auf der MySQL-Performance liegt
    Außerdem gibt es noch keine Unterstützung für Batch-Jobs (zugehöriger PR)

    • Klingt nach der schlechtesten aller Kombinationen. Wir nutzen auch MySQL, könnten aber ohne engine-spezifische Queries nicht leben
      Bei komplexen JOINs erstellt MySQL oft schlechte Query-Pläne, deshalb erzwinge ich die Reihenfolge mit STRAIGHT_JOIN. Das ist Zukunftsvorsorge
    • Wenn ihr ohnehin so tief an MySQL gebunden seid, wäre es dann nicht logisch, MySQL-spezifische Features zu nutzen? Mir scheint, da fehlt etwas
    • Ich würde gern etwas konkreter hören, warum du GoodJob gegenüber SolidQueue empfiehlst
      Ich vergleiche beide gerade als Kandidaten für einen Umstieg von resque. GoodJob ist wegen seiner pg-spezifischen Features nicht mit dem Transaction-Modus von pgbouncer kompatibel
      Dass man persistente Sessions braucht, ist lästig, aber der Performance-Gewinn ist in den meisten Größenordnungen nicht besonders relevant
      Trotzdem wirken das Entwicklungsmodell und die Lesbarkeit des Codes von GoodJob deutlich vertrauenswürdiger
    • Stimme zu. good_job ist als Postgres-basierte Queue ein idealer Ansatz
    • Mit SolidQueue kenne ich mich noch nicht gut aus, aber good_job zu nutzen macht wirklich Spaß. Es funktioniert einfach gut
  • Wenn die Produktionsumgebung einfacher werden kann, ist das immer gut
    Ich denke, im Idealfall sollte Rails eine Architektur bieten, die einen einfachen Wechsel zu Redis erlaubt
    Es wäre gut, mit SolidQueue zu starten und bei Skalierungsgrenzen später auf Redis wechseln zu können
    Die meisten Rails-Apps haben keinen hohen Traffic, daher ist der Betrieb beider Systeme eher zusätzliche Komplexität

    • Rails bietet mit Active Job eine abstrahierte API, sodass ein Wechsel zu Redis ziemlich einfach ist
      Natürlich gibt es Apps, die von einer bestimmten Queue-Implementierung abhängen, aber normalerweise reicht es, die Konfiguration zu ändern
    • Ich frage mich, ob der Redis-AOF-Modus wie ein WAL alle Änderungen protokolliert
      Ich würde gern wissen, ob zusätzlich Snapshots verwendet werden, um zu große Logs zu vermeiden, und ob das auch im verteilten Modus funktioniert
    • Wenn man sich zu stark auf Transaktionen stützt, werden Migrationen schwieriger
      Vor allem wenn Jobs zusammen mit anderen DB-Änderungen erzeugt werden, ist der Verlust dieser Garantien problematisch
    • Es ist verwirrend, dass Rails den Background-Job-Prozessor nicht von der Produktionsdatenbank trennt
      Redis war hier im Vorteil, weil es ein leichtgewichtiges, unabhängiges Storage-System ist
      SolidQueue scheint diese Trennung nicht klar zu machen (riverqueue.com)
  • Ich habe SolidQueue in meinem Side-Project ausprobiert
    Mein Fazit: Wenn es mit Sidekiq kein Problem gibt, gibt es keinen Grund für einen Wechsel
    In Betracht ziehen würde ich es nur, wenn man die Redis-Infrastruktur loswerden will
    Für neue Projekte wirkt GoodJob reifer und hat auch die bessere Community
    Die UI von SolidQueue ist zu schlicht, das war unpraktisch. Ohne Index-Optimierung hing die Seite bei größeren Datenmengen
    Man sollte auch bedenken, dass mit einem RDBMS zusätzlicher Aufwand für das Connection-Pool-Management entsteht

  • Für alle, die sich Sorgen um die Skalierung machen: Der Benchmark von Elixirs Oban zeigt
    auf einem einzelnen Node die Verarbeitung von einer Million Jobs pro Minute. Die meisten Apps liegen weit darunter

    • Unsere Firma nutzt ebenfalls Oban, und Oban verwendet Redis als Notifier oder empfiehlt Polling (Scaling-Doku)
    • Allerdings ist dieser Benchmark ziemlich weit von einer realen App entfernt
      Dort werden 5000 Jobs auf einmal als Batch eingefügt, die TPS liegt also real nur bei etwa 200
      Fügt man einzelne Jobs ohne Batch ein, ist die Belastung durch SQL-Transaktionen deutlich höher
  • Wir haben schon vor SolidQueue Jobs in der DB gespeichert
    Der Vorteil ist, dass man den Produktionszustand als Snapshot direkt in die Entwicklungsumgebung übernehmen kann
    Den Rate Limiter lassen wir aber in Redis, um die DB-Last zu begrenzen

  • Die Grenze DB-basierter Queues sind große Payloads
    Wenn man große JSON-Daten in die Queue legt, ist das wegen des DB-Schreib-Overheads ineffizient
    Redis (Sidekiq) ist in solchen Fällen deutlich schneller
    SolidQueue+SQLite ist als reine Übergabe des Primary Keys noch okay
    Aber wenn viele Worker dieselbe DB pollen, wird das schnell zum Bottleneck

    • In der Praxis ist es üblich, in Job-Parametern nur ein oder zwei IDs zu übergeben. Mehr ist ineffizient
    • Auch Redis ist wegen seiner Speichergrenzen für große Payloads ungeeignet
      Ich denke, große Daten sollten in externem Storage wie S3 liegen und nur per Referenz übergeben werden
    • Da man für andere Teile des Systems ohnehin Storage braucht, ist die Nutzung eines temporären Speichers wie S3 oder garage realistisch
      Mich würde interessieren, ob es dazu irgendwo zusammengefasste Benchmark-Ergebnisse gibt
    • Auch die Sidekiq-Dokumentation empfiehlt, nur Identifikatoren zu übergeben
    • Große Payloads in Redis zu speichern ist schlechte Praxis, weil der Speicher begrenzt ist
  • In SolidQueue wird SKIP LOCKED erwähnt, aber einen 15-Minuten-Job in einer Transaktion offen zu halten, ist riskant
    Lang laufende offene Transaktionen ruinieren die DB-Performance und sind auch anfällig für Netzwerkabbrüche
    So ein Aufbau kann in ein Antipattern führen. Später habe ich gesehen, dass es wohl lease-basiert ist

  • Ich kann mich mit der Philosophie Postgres for everything identifizieren
    Ich halte es für gut, die Dinge einfach zu halten und alles in PostgreSQL zu konsolidieren

    • Ich mag die Idee auch, komplett auf PG zu setzen, aber ich höre oft: „Wenn man nur einen Hammer hat, sieht alles wie ein Nagel aus“
      Ich weiß nicht recht, wie ich auf dieses Bild entgegnen soll
    • Heutzutage ist NVMe-Storage so schnell, dass der Vorteil von Redis kleiner geworden ist
      Ich frage mich, ob Redis die zusätzliche Komplexität überhaupt noch wert ist
  • „Ein Business, bei dem Latenzen unter 1 ms wichtig sind“ — soll das heißen, man macht HFT mit Rails?

    • Natürlich nicht. Wenn man sich die SimpleThread-Fallstudien ansieht, ist die Firma weit von HFT entfernt
    • Die Trading-Engine würde man nicht in Rails betreiben, aber eine UI zur Handelsüberwachung könnte durchaus in Rails gebaut sein
  • Postgres wird die Welt verschlingen

    • Stimme zu. Wenn irgendwann eine pg_kernel-Erweiterung erscheint, löschen wir vielleicht sogar Linux
    • Andererseits könnte man in ein paar Jahren feststellen, dass auch „Postgres for everything“ nur ein überdrehter Trend war — wie einst „MongoDB for everything“
    • Trotzdem ist MySQL pflegeleicht und leistungsmäßig absolut ordentlich (das sage ich als Postgres-Nutzer)
    • Ich nutze derzeit PGQM und PG_CRON, und das ist deutlich sauberer als die frühere Kombination aus MySQL + Redis + AWS
    • Am Ende zählt das Feature-Set. RDBMS werden die Welt verschlingen