Rails 8 Solid Cable: WebSockets Zonder Redis — Eén Dependency Minder
Rails 8 levert Solid Cable standaard mee als Action Cable adapter voor nieuwe applicaties. Als je Redis alleen draaide voor WebSocket-broadcasts, kun je die dependency nu volledig verwijderen. Je database handelt het af.
Hier lees je hoe je het instelt, wat de prestaties zijn in productie, en waar de grenzen liggen.
Wat Solid Cable Precies Is
Solid Cable is een database-backed adapter voor Action Cable. In plaats van berichten via Redis pub/sub te publiceren, schrijft het broadcast-berichten naar een databasetabel en pollt het voor nieuwe berichten. Het wordt geleverd als de solid_cable gem, standaard inbegrepen in Rails 8.0+.
Het verschil met Redis: Solid Cable gebruikt polling in plaats van pub/sub. Een achtergrondthread controleert de database op nieuwe berichten met een instelbaar interval (standaard: 0.1 seconden). Dat klinkt alsof het trager zou moeten zijn, en technisch is dat ook zo — maar voor de overgrote meerderheid van applicaties merkt geen gebruiker het verschil.
Stel het je zo voor: als je chatbericht in 100ms aankomt in plaats van 5ms, merkt niemand dat. Als het verwijderen van Redis je een managed instance van €15/maand bespaart en één ding minder om 3 uur ‘s nachts te monitoren, merkt iedereen dat.
Solid Cable Instellen in een Nieuwe Rails 8 App
Nieuwe Rails 8 apps krijgen Solid Cable standaard geconfigureerd. Start rails new myapp en bekijk config/cable.yml:
development:
adapter: solid_cable
silence_polling: true
test:
adapter: test
production:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
Het connects_to-blok wijst Solid Cable naar een aparte database. Rails 8 configureert standaard een apart SQLite-database voor cable in config/database.yml:
production:
primary:
<<: *default
database: storage/production.sqlite3
cable:
<<: *default
database: storage/production_cable.sqlite3
migrations_paths: db/cable_migrate
Voer de installer uit als het niet automatisch was geconfigureerd:
bin/rails solid_cable:install
Dit genereert de migratie voor de solid_cable_messages tabel en werkt je configuratiebestanden bij.
Migreren van Redis naar Solid Cable
Als je Rails 7 of een vroege Rails 8 app draait met Redis als cable adapter, is dit het migratiepad.
Stap 1: Voeg de gem toe
# Gemfile
gem "solid_cable"
bundle install
bin/rails solid_cable:install
Stap 2: Voer de migratie uit
bin/rails db:migrate
De migratie maakt één tabel aan:
create_table :solid_cable_messages do |t|
t.text :channel, null: false
t.text :payload, null: false, limit: 536870912
t.datetime :created_at, null: false
t.index [:channel, :created_at]
t.index :created_at
end
Stap 3: Werk cable.yml bij
Vervang je Redis-configuratie:
# Voorheen
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL", "redis://localhost:6379/1") %>
# Nu
production:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
Stap 4: Configureer de aparte database
Voeg een cable database-entry toe aan config/database.yml. Voor PostgreSQL:
production:
primary:
<<: *default
database: myapp_production
cable:
<<: *default
database: myapp_production_cable
migrations_paths: db/cable_migrate
Stap 5: Deploy en verifieer
Na het deployen van je Rails 8 app, controleer de logs op SolidCable initialisatieberichten. Open een browserconsole op een pagina met een actieve WebSocket-verbinding en bevestig dat berichten doorstromen.
Als alles werkt, kun je de redis gem uit je Gemfile verwijderen (mits niets anders het gebruikt — controleer eerst je achtergrondtaken-setup en caching-configuratie).
Prestaties: Wat Je Kunt Verwachten
Ik heb Solid Cable gedraaid op een productie-app met ~200 gelijktijdige WebSocket-verbindingen en ongeveer 50 broadcasts per seconde. De setup: een enkele PostgreSQL 15 instantie op een 2-vCPU server met 4GB RAM.
Resultaten:
- Berichtlatentie: 95e percentiel op 85ms (vs ~12ms met Redis op dezelfde hardware)
- Databasebelasting: De polling-queries voegden ~3% CPU-gebruik toe aan de PostgreSQL-instantie
- Geheugen: Elimineerde ~60MB aan Redis-geheugengebruik
- Tabelgrootte: Met de standaard
message_retentionvan 5 minuten bleef de tabel onder de 2.000 rijen
Het latentieverschil is reëel maar irrelevant voor de meeste use cases. Notificatiesystemen, live dashboards, chatfuncties in zakelijke apps, cursors voor collaborative editing — ze werken allemaal prima met sub-100ms levering.
Waar het begint uit te maken: high-frequency trading dashboards, multiplayer game state synchronisatie, of elk scenario met honderden berichten per seconde naar duizenden clients. Daarvoor houd je Redis.
Configuratie-opties Die Ertoe Doen
Solid Cable heeft een paar knoppen die de moeite waard zijn:
production:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
message_retention: 5.minutes
autotrim: true
polling_interval — Hoe vaak Solid Cable controleert op nieuwe berichten. De standaard van 0.1 seconden (100ms) is een goede balans. Lager verhoogt de databasebelasting. Hoger verhoogt de latentie. Ik zou niet onder 0.05 seconden gaan tenzij je je database hebt gebenchmarkt.
message_retention — Hoe lang berichten in de tabel blijven voor ze worden opgeruimd. De standaard van 5 minuten is ruim. Als je WebSocket-verbindingen stabiel zijn en berichten snel worden geconsumeerd, kun je dit naar 1 minuut verlagen.
autotrim — Verwijdert automatisch verlopen berichten. Laat dit aan. Zonder groeit je berichtentabel oneindig en worden de polling-queries trager.
Aparte Database (en Waarom Je Dat Wilt)
Solid Cable werkt prima op je primaire database. Maar een aparte database is beter om twee redenen:
- Isolatie: Polling-queries concurreren niet met je applicatie-queries om connection pool slots of I/O-bandbreedte
- Opruimen: Het trimmen van oude berichten veroorzaakt writes en mogelijke table bloat. Op een aparte database raakt dit je primaire data niet.
Voor SQLite-deployments (single-server setups) is de aparte database vrijwel gratis — het is gewoon een extra bestand. Voor PostgreSQL betekent het een extra logische database op dezelfde server, wat bijna niets kost.
Als je ook Solid Queue draait voor achtergrondtaken, vraag je je misschien af of je een database kunt delen tussen Solid Cable en Solid Queue. Niet doen. Hun toegangspatronen zijn anders — Solid Queue doet veel row locking, Solid Cable doet veel sequential scans. Houd ze gescheiden.
Het Trim-probleem op Drukke Systemen
Iets wat de docs onvoldoende benadrukken: op high-throughput systemen kan de autotrim af en toe lock contention veroorzaken. De trim-operatie voert een DELETE FROM solid_cable_messages WHERE created_at < ? query uit, die op PostgreSQL row-level locks verwerft.
Als je PG::LockNotAvailable fouten ziet in je logs tijdens drukke broadcast-periodes, heb je twee opties:
- Trim minder frequent door
message_retentionte verhogen - Plan een scheduled job voor trimmen in rustigere periodes:
# app/jobs/trim_cable_messages_job.rb
class TrimCableMessagesJob < ApplicationJob
queue_as :maintenance
def perform
SolidCable::Message.where("created_at < ?", 5.minutes.ago)
.in_batches(of: 1000)
.delete_all
end
end
Schakel dan autotrim uit in de config en plan deze job in tijdens rustigere momenten.
Multi-Server Deployments
Solid Cable werkt over meerdere app-servers zolang ze allemaal verbinden met dezelfde cable-database. Dat is het hele punt van een database-adapter — gedeelde state zonder een apart service.
Met Redis moest elke server verbinden met dezelfde Redis-instantie. Met Solid Cable moet elke server verbinden met dezelfde cable-database. De operationele complexiteit is vergelijkbaar, maar je hebt één service minder draaien.
Eén kanttekening: als je SQLite gebruikt als cable-database, werkt multi-server niet (SQLite ondersteunt geen gelijktijdige toegang van meerdere machines). Gebruik PostgreSQL of MySQL voor multi-server setups.
Wanneer Je Redis Houdt
Solid Cable is niet overal de juiste keuze. Houd Redis voor Action Cable als:
- Je consistent meer dan 500 berichten per seconde broadcast
- Sub-10ms berichtlatentie een zakelijke vereiste is
- Je Redis al draait voor caching of achtergrondtaken en de operationele overhead al betaald is
- Je een cluster van 10+ app-servers draait (de polling-belasting schaalt lineair met het aantal servers)
Het omslagpunt in mijn ervaring: als Redis er alleen is voor Action Cable, verwijder het. Als Redis drie doelen dient en je het toch zou houden, maakt de adapterkeuze minder uit.
FAQ
Kan Solid Cable duizenden gelijktijdige WebSocket-verbindingen aan?
Ja, maar de bottleneck is niet de adapter — het is het vermogen van je app-server om open verbindingen vast te houden. Een enkel Puma-proces met 5 threads kan ongeveer 1.000 WebSocket-verbindingen aan voordat geheugen de beperkende factor wordt. Solid Cable’s polling is lichtgewicht ongeacht het aantal verbindingen, omdat het per channel queryt, niet per verbinding.
Werkt Solid Cable met Turbo Streams?
Solid Cable is volledig compatibel met Turbo Streams. Turbo Streams gebruiken Action Cable onder de motorkap, en Solid Cable is een drop-in adapter-vervanging. Je turbo_stream_from helpers, broadcasts_to callbacks en Turbo::StreamsChannel subscriptions werken ongewijzigd.
Wat gebeurt er als de cable-database uitvalt?
WebSocket-verbindingen blijven open maar stoppen met het ontvangen van broadcasts. Zodra de database herstelt, hervat polling en worden berichten die tijdens de storing zijn geschreven (door servers die nog konden schrijven) bezorgd als ze binnen het retentievenster vallen. Clients disconnecten niet — ze stoppen tijdelijk met het ontvangen van updates.
Moet ik SQLite of PostgreSQL gebruiken voor de cable-database?
SQLite is prima voor single-server deployments en houdt het simpel. PostgreSQL is nodig voor multi-server setups. De prestaties zijn vergelijkbaar voor typische broadcast-volumes (onder 100 berichten/seconde). Als je PostgreSQL al draait als primaire database, gebruik het dan ook voor cable — één database-engine minder om over na te denken.
Is Solid Cable productie-klaar?
Het werd geleverd als de standaard in Rails 8.0 en is stabiel sinds de 1.0 release. Basecamp en HEY (37signals apps) gebruiken de Solid-familie van libraries in productie. Het is niet experimenteel — het is het beoogde pad voorwaarts voor Rails-applicaties die geen Redis-niveau throughput nodig hebben.
About the Author
Roger Heykoop is een senior Ruby on Rails ontwikkelaar met 19+ jaar Rails ervaring en 35+ jaar ervaring in softwareontwikkeling. Hij is gespecialiseerd in Rails modernisering, performance optimalisatie, en AI-ondersteunde ontwikkeling.
Get in TouchRelated Articles
Need Expert Rails Development?
Let's discuss how we can help you build or modernize your Rails application with 19+ years of expertise
Schedule a Free Consultation