Repository navigation
The README's benchmark on a 2M-message database: Rails, the open performance PRs, the Spinel binary, Rust and Go #333
namespaceMarcello
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
The README's table measures five workloads on a small database. These are the same five workloads, measured the same way (16 concurrent clients, four hardware threads per app), on a database with 2 million messages and 10,008 users. The same run on a small database sits beside them, on the same machine.
Setup
wrk -t2 -c16to 4 others. Each run had 5 s of warm-up and 20 s measured.config/puma.rb's workers (3 × 5 threads on 4 CPUs), with resque-pool beside it and Redis in the same container.rails 90b3300: the commit Roundhouse pins;rails + PRs:d2155e8(which includes Preload only uncached messages and reduce rendering overhead #292, Index messages by room and creation time #295, Check for a second page of messages without counting the room #297, Search for operator words instead of parsing them #298, Read the newest search matches off the index instead of sorting them all #304 and Post a webhook reply as an attachment only when the bot answered 200 #306) plus the open Fan the unread room notice out from a job #296, Find a direct room with one query instead of checking every one #310, Find the messages a refresh replaces through an index #312 and List one page of account members at a time #316, on the same gems;spinel: the published Roundhouse/Spinel archive of90b3300;rust: once-campfire-rustccece30;go: once-campfire-go8d2f7f2.Requests per second
wrkcounted 26 socket timeouts across the Rust and Go runs, out of about 1.1 million requests, and none on Rails or the binary. No responses outside 2xx/3xx.What the table shows:
90b3300it drops about twentyfold.90b3300drops the same way, from 2,154 to 9.2. The cost is in the query, so compiling doesn't change it.created_atbefore taking 100. That is the sort Read the newest search matches off the index instead of sorting them all #304 removed from Rails (on a copy of the large database, 62 ms against 0.1 ms per query for the same 100 ids). We'll offer the ports the same change.* Posting into a room with 10,003 members: in the request at
90b3300, Rails publishes one Redis message per member (Message::Broadcasts#broadcast_unread_room). #296 moves that into a job, so the response is fast, but the work remains: after the 20 s run, 5,897 jobs were still queued. Measured on its own, with no subscribers and Redis in the same container, sending those 10,003 publishes one at a time took 1,038 ms through Action Cable's Redis adapter, and 24 ms in one Redis pipeline. A batched broadcast would lift that limit. We'll take that to Rails separately.One request at a time (large database, ms, median of 11 after 3 warm-ups)
Rails ran as one Puma worker with five threads, as in
bench/compare_http.rb, and each app was limited to 8 CPUs.before)† One page of 500 members (1 MB), where the others render all 10,008 (16–20 MB). That difference is the change #316 makes.
Rails' own log splits the time. At
90b3300the room page spends 352 of its 370 ms in SQL, refresh 417 of 423, and "Ping" makes 40,005 queries. With the PRs these are 0.9 ms of SQL, 2 ms in total, and 8 queries.Limits
rails + PRsalso differs from90b3300by the other upstream commits since then, Preload only uncached messages and reduce rendering overhead #292 among them.The scripts (seed,
wrkdriver, latency probe) are in this gist.Written by Claude Code (AI assistant) on behalf of @namespaceMarcello, who directs this work.
All reactions