35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English 35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English
Rails Solid Cache: Database-Backed Caching in Rails 8 Zonder Redis of Memcached

Rails Solid Cache: Database-Backed Caching in Rails 8 Zonder Redis of Memcached

Roger Heykoop
Ruby on Rails, DevOps
Rails Solid Cache in productie: disk-backed caching in Postgres, encryptie, eviction, trimmen, sizing en wanneer het Redis of Memcached verslaat.

Afgelopen zomer legde een klant hun AWS-rekening voor me neer en wees naar de ElastiCache-regel. “Waarom is onze cache duurder dan onze applicatieservers?” Dat was een terechte vraag. Ze draaiden een Redis-cluster met drie nodes, replicatie, snapshots en cross-AZ verkeer, en ze gebruikten het om gerenderde fragmenten en een handvol ActiveRecord-query’s te cachen. Hun hit rate was hoog. Hun verkeer was bescheiden. Hun operationele overhead was dat niet.

Na negentien jaar Rails heb ik het caching-verhaal zien evolueren van file stores die niemand vertrouwde naar Memcached naar Redis naar nu Rails Solid Cache — en voor het eerst kan ik de meeste klanten eerlijk vertellen dat hun cache niet buiten hun database hoeft te leven. Dit is de praktische gids die ik teams geef als we Redis eruit trekken en overstappen naar Rails Solid Cache in productie.

Wat Rails Solid Cache Eigenlijk Is

Rails Solid Cache is een disk-backed cache store voor Active Support die een relationele database — meestal Postgres of MySQL — als backend gebruikt. Het wordt standaard meegeleverd in nieuwe Rails 8-applicaties, samen met zijn broers Solid Queue en Solid Cable. Met z’n drieën zijn ze de reden waarom een verse Rails 8-app in productie kan draaien zonder überhaupt Redis te gebruiken.

Het interessante woord in die beschrijving is disk-backed. Memcached en Redis zijn geheugencaches die met tegenzin naar disk spillen. Rails Solid Cache is een disk-cache die profiteert van de buffercache van Postgres. Dat klinkt als een downgrade en dat is het niet. Moderne NVMe-opslag met een goed getunede Postgres is snel genoeg dat het latency-verschil wegvalt in netwerkoverhead, en je kunt veel meer data per euro cachen dan je in RAM kunt houden.

Een van mijn klanten draait een Rails Solid Cache van 400GB tegen een Postgres-instance met 32GB RAM. Ze zouden een Redis-cluster nodig hebben dat tien keer duurder is om dezelfde working set in geheugen te houden. Hun p99 cache-leeslatentie zit onder de drie milliseconden.

Wanneer Kies Je Rails Solid Cache Boven Redis of Memcached

Ik geef klanten een korte beslisregel: als je cache reads onder een paar duizend per seconde zitten en je cache groter is dan je RAM-budget, gebruik dan Rails Solid Cache. Als je sub-milliseconde reads nodig hebt bij tienduizenden requests per seconde, blijf bij Redis.

Rails Solid Cache is de juiste keuze wanneer:

  • Je working set groot is — tientallen gigabytes tot terabytes — en je meer wilt cachen dan een Redis-node kan vasthouden.
  • Je al Postgres draait en één minder service wilt beheren, patchen en wakker van liggen.
  • Je cache reads een enkele milliseconde kunnen verdragen, wat voor de meeste webapplicaties geldt.
  • Je encryptie at-rest, eenvoudige backups en point-in-time recovery wilt zonder het zelf te bouwen.
  • Je op Rails 7.1+ zit en het Rails 8-operatiemodel wilt omarmen.

Blijf bij Redis of Memcached wanneer:

  • Je microseconde cache-hits nodig hebt — ad tech, realtime bidding, exchange matching.
  • Je een cache-working-set hebt die comfortabel in geheugen past en sneller churnt dan Postgres vacuum kan bijhouden.
  • Je Redis gebruikt voor zaken die een cache store niet kan — pub/sub, sorted sets, rate limiting, leaderboards. Houd Redis voor die dingen; stop alleen met het gebruik als fragment cache.

De meeste Rails-apps die ik zie raken geen van de “blijf bij Redis”-punten. Ze draaien Redis omdat dat is wat het blogpost uit 2014 zei dat je moest doen. In 2026 is dat antwoord veranderd.

Rails Solid Cache Installeren

Op een verse Rails 8-app is het al geconfigureerd. Voor een bestaande app op Rails 7.1 of nieuwer:

# Gemfile
gem "solid_cache"
bundle install
bin/rails solid_cache:install
bin/rails db:migrate

De installer genereert een migratie voor de solid_cache_entries-tabel en werkt config/environments/production.rb bij om de nieuwe store te gebruiken. Ik raad sterk aan om de cache in een aparte database te draaien van je primaire applicatiedata — op dezelfde manier als ik voor Solid Queue aanbeveel. Een op hol geslagen cache-backfill zou nooit je order-tabel moeten blokkeren.

# config/database.yml
production:
  primary:
    <<: *default
    database: myapp_production
    username: myapp
    password: <%= ENV["DATABASE_PASSWORD"] %>
  cache:
    <<: *default
    database: myapp_cache_production
    migrations_paths: db/cache_migrate
# config/environments/production.rb
config.cache_store = :solid_cache_store
# config/solid_cache.yml
production:
  database: cache
  store_options:
    max_age: <%= 30.days.to_i %>
    max_size: 256.gigabytes
    namespace: myapp_production

Drie instellingen dragen hier het meeste gewicht: max_age, max_size en namespace. Krijg die goed en de cache draait grotendeels zichzelf.

Hoe Rails Solid Cache Data Opslaat en Evict

Onder de motorkap ziet de cachetabel er bijna saai uit:

create_table :solid_cache_entries do |t|
  t.binary :key, null: false, limit: 1024
  t.binary :value, null: false, limit: 512.megabytes
  t.datetime :created_at, null: false
  t.integer :key_hash, null: false, limit: 8
  t.integer :byte_size, null: false, limit: 4
end

add_index :solid_cache_entries, :key_hash, unique: true
add_index :solid_cache_entries, [:key_hash, :byte_size]
add_index :solid_cache_entries, :byte_size

Sleutels worden opgeslagen als binary samen met een 64-bit hash voor snelle lookups. Waarden worden precies zo geserialiseerd als Active Support’s cache ze naar Redis zou serialiseren — inclusief compressie als je dat aanzet. De byte_size-kolom stuurt de size-based eviction-logica aan.

Eviction is geen LRU. Rails Solid Cache gebruikt een FIFO-met-trim-model: de oudste entries worden eerst verwijderd zodra de cache max_size overschrijdt. Dat klinkt slechter dan LRU maar werkt in de praktijk prima voor webcaches, omdat de hot keys elke keer dat ze worden benaderd opnieuw worden geschreven, wat ze naar de voorkant van de queue verplaatst. Een thread binnen het Rails-proces draait een background trim-job zodat de eviction incrementeel gebeurt, niet als een stop-the-world batch.

De tradeoff is echt maar acceptabel: een sleutel die een week geleden is gecached en net één keer is opgevraagd, overleeft misschien niet als de cache vol zit met recentere writes. Voor fragment caches is dat precies wat je wilt.

Een Realistische Rails Solid Cache-Configuratie

Dit is de configuratie die ik daadwerkelijk uitrol voor klanten met middelmatig verkeer. Stem de getallen af op jouw working set.

# config/environments/production.rb
config.cache_store = :solid_cache_store, {
  expires_in: 7.days,
  compress: true,
  compress_threshold: 1.kilobyte,
  error_handler: ->(method:, returning:, exception:) do
    Rails.error.report(exception, handled: true, context: { method: method })
    returning
  end
}
# config/solid_cache.yml
default: &default
  store_options:
    max_age: <%= 30.days.to_i %>
    max_size: <%= 512.gigabytes %>
    max_entries: 50_000_000
    namespace: <%= ENV.fetch("SOLID_CACHE_NAMESPACE", "myapp") %>
    cluster:
      shards: [cache_primary, cache_secondary]

production:
  <<: *default
  database: cache

De cluster-key is hoe Rails Solid Cache sharding doet. Als je hem naar twee Postgres-databases wijst, consistent-hasht hij sleutels erover. Je hebt dit op dag één waarschijnlijk niet nodig — een enkele goed geprovisioneerde Postgres handelt de meeste workloads af — maar het is fijn om te weten dat het schaalpad bestaat zonder applicatiecode aan te raken.

Twee instellingen in dat fragment waar mensen op vastlopen:

  • compress_threshold: 1.kilobyte verdient zichzelf snel terug. Gecomprimeerde waarden delen dezelfde byte_size-index en laten je meer keys per gigabyte kwijt. Ik heb 3–5x effectieve capaciteitswinst gezien op fragment-zware caches.
  • error_handler is essentieel. Zonder hem kan een enkele onbetrouwbare cache-write omhoogkomen in een controller action. Met hem blijven cache misses gewoon cache misses.

Gebruik in Echte Code

Applicatie-niveau gebruik is identiek aan elke andere Active Support cache. Dat is het punt.

class DashboardsController < ApplicationController
  def show
    @summary = Rails.cache.fetch(
      ["user_dashboard", current_user.id, current_user.updated_at.to_i],
      expires_in: 10.minutes
    ) do
      DashboardSummary.build(current_user)
    end
  end
end

Fragment caching werkt hetzelfde:

<% cache [@product, I18n.locale], expires_in: 1.hour do %>
  <%= render @product %>
<% end %>

Wat verandert is waar je mee wegkomt. Met Redis maak je je druk om cache keys omdat elke key geheugen kost. Met Rails Solid Cache kun je agressief cachen — gerenderde pagina’s, berekende rapporten, dure JSON payloads — omdat disk goedkoop is en de backend schaalt door een Postgres-volume uit te breiden.

Eén patroon dat ik nu zonder aarzeling gebruik: zware API-responses cachen voor uitgelogde gebruikers.

class Api::V1::ProductsController < ApiController
  def index
    key = ["api_v1_products", params.permit!.to_h.sort, Product.maximum(:updated_at).to_i]

    json = Rails.cache.fetch(key, expires_in: 1.hour) do
      ProductSerializer.render_as_hash(filtered_products).to_json
    end

    render json: json
  end
end

Op Redis was dit duur en broos geweest. Op Rails Solid Cache is het wegwerpmateriaal. Als het wordt geëvicteerd, wordt het opnieuw gegenereerd.

Encryptie At Rest

Dit is het deel van Rails Solid Cache waarvan de meeste teams niet beseffen dat ze het wilden totdat ze het zien. Omdat cache-entries gewoon rijen in Postgres zijn, erven ze alle beveiligingsmaatregelen die je al hebt — at-rest encryptie op de database-volume, netwerk-TLS, IAM-policies, audit logs. Met Redis is at-rest encryptie instellen of “betaal voor de managed versie” of “bedien je eigen TLS tussen elke hop”.

Als je een extra laag wilt — en dat zou moeten als je cache geserialiseerde ActiveRecord-objecten bevat met PII — werkt Active Record Encryption op de cachekolommen precies zoals het op elke andere binary kolom werkt. Ik configureer het zo:

# config/initializers/solid_cache.rb
Rails.application.config.to_prepare do
  next unless defined?(SolidCache::Entry)

  SolidCache::Entry.encrypts :value
end

Er is een echte CPU-kost — ik heb het gemeten op ongeveer 8% op een hot API — maar het is de juiste default voor gereguleerde workloads. Ik heb een klant die op deze manier HIPAA-workloads draait en het audit-gesprek ging van meerdere uren naar vijftien minuten.

Sizing en Monitoring

De twee vragen die ik het meeste krijg over Rails Solid Cache in productie:

Hoe groot moet ik hem maken? Begin met iets dat 10–20% is van de grootte van je primaire database. Houd de hit rate en de trimfrequentie twee weken in de gaten. Groei als een van die cijfers zegt dat je dat moet.

Hoe monitor ik hem? Drie SQL-queries vertellen je bijna alles.

# Hit rate — instrumenteer via Active Support notifications
ActiveSupport::Notifications.subscribe("cache_read.active_support") do |_, _, _, _, payload|
  StatsD.increment("cache.#{payload[:hit] ? 'hit' : 'miss'}")
end

# Grootte in bytes
SolidCache::Entry.connection.select_value(
  "SELECT SUM(byte_size) FROM solid_cache_entries"
)

# Oudste overlevende entry — een proxy voor trim-druk
SolidCache::Entry.minimum(:created_at)

Als de oudste entry jonger is dan je max_age, trim je op basis van grootte en moet je of de cache vergroten of je write-volume verlagen. Als hij gelijk is aan je max_age, coast je op capaciteit en kun je hem waarschijnlijk verkleinen.

Voor de meeste teams is dit genoeg. Wil je een web-UI, dan heeft het Mission Control job-dashboard experimentele cache-integratie in de Rails 8-roadmap.

Wat Breekt, en Hoe Je Het Afhandelt

In twee jaar Rails Solid Cache draaien over acht klantapps vallen de enige echte incidenten die ik heb gezien in drie categorieën.

Vacuum-druk op de cachetabel. Cache writes zijn een churn-workload. Postgres autovacuum moet agressief draaien op solid_cache_entries of de tabel bloat. Ik heb de tuning uitgebreid behandeld in de autovacuum-gids, maar de korte versie: zet autovacuum_vacuum_scale_factor = 0.05 en autovacuum_vacuum_cost_limit = 2000 voor de cachetabel. Sla dit niet over.

Cold start na een deploy. Een verse cache retourneert misses totdat hij opwarmt. Voor fragment caches is dat prima. Voor kritieke-pad queries wil je misschien een kleine warming job die bekende hot keys voor-vult. Ik koppel dit meestal aan de post-deploy hook.

Per ongeluk enorme waarden cachen. De standaard compress_threshold helpt, maar iemand zal uiteindelijk proberen een CSV van 200MB te cachen. Zet een harde size_limit op de store en let op fouten:

config.cache_store = :solid_cache_store, { size_limit: 10.megabytes }

Geen van deze is een dealbreaker. Al deze zaken moet je bij Redis ook afhandelen, alleen in andere vormen.

Het Grotere Plaatje

Rails Solid Cache is niet alleen een cache store. Het is onderdeel van een bewuste beweging van het Rails-team om kleine teams serieuze applicaties te laten draaien met minder services in de stack. Ik schreef vorige week over Rails Solid Queue als vervanger voor Sidekiq. Solid Cache vervangt Redis voor caching. Solid Cable vervangt Redis voor Action Cable. Tel daar Kamal 2 voor deploys bij op en het hele operationele verhaal past op één pagina.

Dat doet er voor fractional CTO’s en kleine teams meer toe dan voor wie dan ook. Elke service die je niet draait, is een pagerrotatie die je niet hoeft te bemensen. De Solid-trinity is niet het snelste antwoord op elk caching-probleem. Het is het simpelste antwoord dat standhoudt in productie, en simpel stapelt zich op over de jaren.

FAQ

Is Rails Solid Cache sneller dan Redis?

Nee. Redis is sneller voor pure point reads — doorgaans sub-milliseconde versus 1–3ms voor Rails Solid Cache op Postgres. De reden om Rails Solid Cache te gebruiken is niet rauwe snelheid, het is operationele eenvoud, grotere capaciteit per euro en één minder service om te draaien. Voor de overgrote meerderheid van webapplicaties is het latencyverschil onzichtbaar achter netwerk- en serialisatie-overhead.

Kan ik Rails Solid Cache gebruiken met Rails 7?

Ja. Rails Solid Cache vereist Rails 7.1 of nieuwer. Het wordt standaard meegeleverd met Rails 8 maar werkt prima op 7.1 en 7.2 zodra je de gem toevoegt en de installer draait. Ik heb productiedeployments op alle drie de versies.

Hoeveel diskruimte gebruikt Rails Solid Cache?

Ongeveer de grootte van de gecachede waarden plus zo’n 10–15% index-overhead. Met compressie ingeschakeld boven 1KB kun je 3–5x effectieve capaciteit verwachten ten opzichte van ruwe opslag. Op NVMe-backed Postgres is dat goedkoop — een cache van 256GB kost een paar euro per maand aan opslag.

Heb ik nog steeds Redis nodig als ik Rails Solid Cache gebruik?

Alleen als je Redis gebruikt voor iets anders dan caching — pub/sub, sorted sets, rate limiting, Sidekiq. Als Redis voor jou puur een fragment cache is, kan Rails Solid Cache het volledig vervangen. In een Rails 8-app die ook Solid Queue en Solid Cable gebruikt, verdwijnt Redis vaak volledig uit de stack.


Denk je erover je Redis-rekening te killen of een cache naar Postgres te verhuizen? TTB Software is gespecialiseerd in operationele vereenvoudiging voor Rails-applicaties, van caching en background jobs tot deploys en observability. We doen dit al negentien jaar.

#rails-solid-cache #rails-8 #rails-caching #postgres-cache #redis-alternative #activesupport-cache #ruby
R

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 Touch

Share this article

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