Rack Mini Profiler: Prestatieprofiling voor Rails in Development en Productie
Rack Mini Profiler voor Rails: profileer SQL-queries, partials, geheugen en GC in development en productie. Vind N+1s, trage views en verborgen knelpunten snel.
De pagina laadde in drie seconden. Niet consistent — soms twee, soms vier. Geen errors, niets opvallends in de logs. De applicatie draaide al achttien maanden in productie en dit admin-dashboard was stilletjes onbruikbaar geworden terwijl het team druk was met het uitbrengen van nieuwe features.
Ik vroeg of ze rack-mini-profiler hadden geïnstalleerd. Dat hadden ze niet. Ik voegde het toe, opende de pagina, en binnen dertig seconden hadden we het antwoord: 94 SQL-queries bij één enkele page load. Een klassieke N+1 op een has_many through:-associatie, begraven in een partial die in de loop der tijd zes verschillende modellen was gaan aanraken. De fix was een eager load van twee regels. De fix kostte een middag. De profiler kostte dertig seconden.
Na negentien jaar Rails is rack-mini-profiler nog steeds het eerste gereedschap dat ik erbij pak als iemand me vertelt dat een pagina traag is.
Wat Rack Mini Profiler Je Laat Zien
Rack-mini-profiler is een Rack-middleware die een kleine profiling-toolbar in je HTML-responses injecteert. De toolbar toont de totale requesttijd, de tijd die Rails besteedt aan rendering, en de tijd in de database — uitgesplitst naar aantal SQL-queries en duur.
Dat klinkt eenvoudig. De kracht zit in de details. De toolbar is persistent, per pagina, en verschijnt in de context van de pagina die je aan het debuggen bent — niet in een apart tool waar je het scenario opnieuw moet reproduceren. Je ziet de cijfers terwijl je de applicatie normaal gebruikt.
Klik op de toolbar en je krijgt een query-voor-query-breakdown: elke SQL-statement, de duur ervan, de aanroepende stacktrace, en hoe vaak het werd uitgevoerd. Die stacktrace is hoe je de bronregel vindt die je N+1 veroorzaakt — je hoeft niet te zoeken naar eager load-kandidaten of query-plannen te lezen. De profiler vertelt je precies welke regel Ruby elke query uitvoert.
Installatie en Configuratie
Voeg toe aan je Gemfile:
gem "rack-mini-profiler"
gem "memory_profiler" # schakelt geheugen-profiling in
gem "stackprof" # schakelt flamegraph-ondersteuning in
Rack-mini-profiler activeert zichzelf automatisch in development en voegt de toolbar toe aan elke HTML-response. In productie en staging is het standaard stil — de toolbar verschijnt alleen bij geautoriseerde requests.
Basisconfiguratie in een initializer:
# config/initializers/rack_profiler.rb
if Rails.env.development?
Rack::MiniProfiler.config.start_hidden = false
Rack::MiniProfiler.config.position = "bottom-right"
Rack::MiniProfiler.config.skip_paths = ["/assets", "/cable"]
end
skip_paths voorkomt dat de profiler draait op asset-requests en Action Cable-pings. Die vervuilen de toolbar-geschiedenis zonder nuttig te zijn voor applicatieprofiling.
Voor Rails-apps met Propshaft of Sprockets integreert de gem automatisch. Geen handmatige middleware-insertie nodig — hij detecteert de Rack-stack en voegt zichzelf op de juiste positie in.
N+1-queries Vinden met Rack Mini Profiler
Dit is het dagelijkse gebruik. Het SQL-tabblad in rack-mini-profiler toont elke query gegroepeerd per aanroeper. Een N+1 verschijnt als een herhalende query met een aantal groter dan één — meestal met een kleine duur per query die optelt tot een significante totaaltijd.
De werkwijze:
- Laad de pagina
- Klik op de snelheidsbadge in de hoek
- Ga naar het SQL-tabblad
- Zoek naar queries met een aantal van N, waarbij N evenredig is aan het aantal records op de pagina
Als je 20 orders hebt en je ziet SELECT * FROM line_items WHERE order_id = ? 20 keer staan, heb je je N+1 gevonden. De stacktrace bij elke query-instantie wijst naar de exacte partial of methode die hem aanroept.
De fix:
# Voorheen: N+1 — één query per order
@orders = Order.where(user: current_user).order(created_at: :desc)
# Daarna: eager load line_items in één query
@orders = Order.where(user: current_user)
.includes(:line_items)
.order(created_at: :desc)
De N+1-querygids behandelt Bullet-integratie en strict loading naast rack-mini-profiler. Gebruik de profiler om N+1s interactief te vinden; gebruik Bullet om regressies automatisch te onderscheppen in CI. Het zijn complementaire tools, geen alternatieven.
Geheugen Profileren
Met memory_profiler geïnstalleerd, voeg je ?pp=profile-memory toe aan een URL voor een volledig allocatierapport van die request:
http://localhost:3000/admin/orders?pp=profile-memory
De response is een tekstrapport met gealloceerde objecten per gem, per bestand en per regelnummer. Het is uitgebreid, maar de samenvatting Total allocated: bovenaan is je startpunt. Een typische Rails-request alloceert ergens tussen de 50.000 en 300.000 objecten. Requests die meerdere miljoenen objecten alloceren zijn de moeite waard om te onderzoeken.
Het rapport groepeert allocaties per gem, zodat je kunt zien of de druk komt van je eigen applicatiecode, van ActiveRecord, van je templating-laag of van een third-party gem. Een rapport dat 80% van de allocaties toeschrijft aan een serializer-gem is actionable: de gem maakt te veel tussenliggende objecten aan, en de gem moet worden vervangen of de serialisatie moet worden gecachet.
Voor dieper onderzoek naar productie-geheugengroei behandelt de Ruby GC-tuninggids GC.stat-analyse, heap-size-configuratie en ObjectSpace — de juiste tools zodra je hebt bepaald waar de druk vandaan komt.
Flamegraphs
Voeg ?pp=flamegraph toe voor een Speedscope-compatibele flamegraph van de volledige request-callstack:
http://localhost:3000/admin/orders?pp=flamegraph
De flamegraph rendert in de browser via Speedscope. Elk horizontaal blok is een stackframe; de breedte staat voor de tijd. Hoge stacks die je niet verwachtte, of brede blokken op onverwachte plaatsen, vertellen je wat het proces werkelijk aan het doen is — niet wat je aanneemt dat het doet.
De flamegraph is het juiste gereedschap wanneer het SQL-queryaantal er redelijk uitziet maar de pagina toch traag is. Als de databasetijd onder de 50ms blijft maar de totale requesttijd 800ms is, zit de resterende 750ms in Ruby-executie: serialisatie, view-rendering, objectallocatie, reguliere expressies in template-helpers, of een gem die iets duur doet wat je nooit hebt geïnspecteerd. De flamegraph brengt het aan de oppervlakte zonder giswerk.
stackprof moet geïnstalleerd zijn voor ?pp=flamegraph. De request moet in een paar minuten afgerond zijn om de output correct te genereren.
Rack Mini Profiler Inschakelen in Staging en Productie
De toolbar is een beveiligingsrisico als hij zichtbaar is voor niet-geauthenticeerde gebruikers — hij onthult querystructuur, partial-namen en timingdata die een aanvaller kan gebruiken om de internals van je applicatie te begrijpen. Het juiste patroon koppelt het aan je bestaande authenticatie:
# config/initializers/rack_profiler.rb
Rack::MiniProfiler.config.authorization_mode = :allowlist
# app/controllers/admin/base_controller.rb
class Admin::BaseController < ApplicationController
before_action :authorize_profiler
private
def authorize_profiler
Rack::MiniProfiler.authorize_request if current_user&.admin?
end
end
Met deze configuratie activeert het bezoeken van een admin-URL als beheerder de profiler-toolbar voor je sessie. Niet-admin-requests zien niets. Dit is veilig om permanent in productie te laten staan — verwaarloosbare overhead voor geprofileerde sessies, nul overhead voor al het andere.
Voor eenmalige onderzoeken op specifieke productiepagina’s geven de parameters ?pp=env en ?pp=profile-gc plain-text responses in plaats van een toolbar te injecteren. Je kunt ze ophalen met curl via een geauthenticeerde sessie:
curl -b "session_cookie=jouw_sessiewaarde" \
"https://jouwapp.com/admin/trage-pagina?pp=env"
Combineren met EXPLAIN ANALYZE
Rack-mini-profiler toont welke queries traag zijn en hoe vaak ze draaien. Het verklaart niet waarom een individuele query traag is op databaseniveau — daarvoor heb je EXPLAIN ANALYZE nodig.
De werkwijze:
- Identificeer trage queries in het SQL-tabblad van de profiler (alles boven 50ms is de moeite waard)
- Kopieer de query-tekst
- Voer hem uit met EXPLAIN ANALYZE in psql of je databaseclient
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM orders
WHERE user_id = 42 AND status = 'pending'
ORDER BY created_at DESC;
De Postgres EXPLAIN ANALYZE-gids behandelt het lezen van queryplannen, het herkennen van sequential scans en het kiezen van het juiste indextype. De combinatie — rack-mini-profiler om te bepalen welke query onderzocht moet worden, EXPLAIN ANALYZE om te begrijpen waarom hij traag is — dekt vrijwel elk productie-databaseprestatieprobleem dat ik tegenkom.
Achtergrondtaken Profileren
Rack-middleware onderschept alleen HTTP-requests. Het profileert geen Solid Queue- of Sidekiq-workers. Gebruik voor jobs direct stackprof:
# app/jobs/process_orders_job.rb
class ProcessOrdersJob < ApplicationJob
def perform
result = StackProf.run(mode: :wall, raw: true) do
Order.pending.find_each do |order|
ProcessOrder.call(order)
end
end
report = StackProf::Report.new(result)
report.print_text(false, 50) # top 50 frames op self-tijd
end
end
Voer dit handmatig uit vanuit de Rails-console in development of staging. De output is een plain-text tabel van de zwaarste stackframes — het job-equivalent van een flamegraph, zonder de browserrendering.
Voor doorlopende monitoring van jobprestaties in productie is OpenTelemetry-instrumentatie de betere investering: spans op elke job-executie met databasetijd en wachttijd in de queue automatisch bijgehouden over alle workers heen.
FAQ
Werkt rack-mini-profiler samen met Turbo en Hotwire?
Ja, met een kleine nuance. Turbo Drive onderschept volledige paginanavigaties, waardoor de toolbar tussen pagina’s blijft staan zonder volledige herlaadbeurt — je kunt daardoor een meerstaps-flow profileren zonder eerdere resultaten te verliezen. Turbo Frame-requests zijn afzonderlijke HTTP-requests en verschijnen als individuele vermeldingen in de dropdown-geschiedenis van de toolbar. Als de partial van een Turbo Frame traag is, staat het profiel als de meest recente vermelding in de geschiedenis nadat je het frame hebt getriggerd.
Is het veilig om rack-mini-profiler in productie te draaien?
Met autorisatie ingeschakeld: ja. Zonder autorisatie: nee. De SQL-output onthult je schema, querypatronen en tabelnamen in voldoende detail om een gerichte aanval te informeren. Gebruik de allowlist-autorisatiemodus en koppel toegang aan admin-authenticatie zoals hierboven getoond. De overhead voor niet-geprofileerde requests is één middleware-check — onmeetbaar in productieverKeer.
Hoe profileer ik een trage actie die POST-data vereist?
De parameters ?pp=flamegraph en ?pp=profile-memory werken ook op POST-requests. Voeg ze als queryparameters toe aan de action-URL van het formulier, of aan de fetch-URL als de actie via JavaScript wordt aangeroepen. De profiler koppelt aan de server-side verwerking ongeacht de HTTP-methode.
Hoe verhoudt rack-mini-profiler zich tot APM-diensten zoals Skylight of Scout?
Ze dienen verschillende doelen. Rack-mini-profiler is een per-request debug-tool — interactief, direct beschikbaar, met volledige SQL- en stackdetails voor één request. Skylight en Scout APM zijn productie-monitoringdiensten die prestatiedata over duizenden requests in de loop van de tijd aggregeren en trage endpoints, regressies en trends op fleetschaal zichtbaar maken. Gebruik rack-mini-profiler om specifieke trage pagina’s te diagnosticeren in development; gebruik een APM-dienst om te weten welke pagina’s in de eerste plaats gediagnosticeerd moeten worden. Het zijn geen alternatieven — de best onderhouden Rails-applicaties die ik heb gezien gebruiken beide.
Ben je op zoek naar een prestatieprobleem dat zich niet duidelijk laat zien in je logs? TTB Software profileert Rails-applicaties in development en productie al negentien jaar. We weten welke cijfers we als eerste bekijken en hoe we van een trage pagina naar een gecommitte fix komen in één sessie.
Related Articles
Rails Content Security Policy: CSP-headers, Nonces en Turbo-compatibiliteit
Rails content security policy: configureer CSP-headers, genereer nonces voor Turbo en Stimulus, los schendingen op en...
Rails Event Sourcing: Append-Only Domain Events, Projecties en CQRS in Productie
Rails event sourcing: bouw append-only domain event logs, schrijf projecties en implementeer CQRS-patronen in product...
Rails Zeitwerk Autoloading: NameErrors oplossen, Eager Loading en de Classic Loader Migratie
Rails Zeitwerk autoloading uitgelegd: fix NameErrors, begrijp eager loading valkuilen, migreer van Classic loader, en...