Reading the numbers: Solid Cable against Redis under load

Free preview 4 min to read

The mid-level course "Solid Cable: scaling WebSockets" looked at this app's solid_cable_messages table in development, where one browser tab over a few sessions had written every row. That never had to answer a harder question: what happens when it isn't one tab but a thousand?

You don't have to guess. The rails/solid_cable repository has a bench/ directory with a small Rails app, a deploy configuration and a load-testing script built on k6, set up following an Evil Martians article on WebSocket stress testing. bench/ isn't part of the installed gem; listing the installed package finds no bench/ files. But the maintainers ran it on a server, a Hetzner CCX13, pushed a rising number of simulated WebSocket connections at it, and published the numbers in the gem's README.md, which is installed, at solid_cable-4.0.2/README.md. These are the numbers for the version in this app's Gemfile.lock, not a vendor's marketing page.

What the benchmark measures

Each simulated connection is a virtual user, or VU: one WebSocket, subscribed and receiving broadcasts, much like one of the app's connected browser tabs. The load test runs at 100, 250, 500 and 750 VUs and records RTT, the round-trip time from a message being broadcast to a subscribed client receiving it. Lower is better. The report gives the average and the percentiles p(90) and p(95), the RTT that 90% and 95% of messages beat. Those matter more than the average once you're asking whether most users have a good experience.

PostgreSQL with Solid Cable, against Redis on the same host

These are the gem's numbers for average RTT, with PostgreSQL on Solid Cable's defaults (polling_interval: 0.1.seconds, autotrimming on) against Redis on the same machine:

VUs    Solid Cable (PG)    Redis
100    137.45ms            68.95ms
250    151.63ms            69.32ms
500    362.79ms            87.50ms

At 100 VUs, Solid Cable's latency is already about double Redis's. At 500 VUs it's over four times as slow, while Redis has barely moved: 87 ms is close enough to its 100-VU number to call flat. The gap isn't a bug or a misconfiguration. It's the cost of the two adapters working in different ways.

Why the curves diverge

"Solid Cable: scaling WebSockets" walked through the listener thread: one per server process, looping forever, sleeping polling_interval (0.1 seconds by default) between passes. On every pass it runs a query, the broadcastable scope filtered by channel and ordered by id, for the channels that process has subscribers on. That query's cost depends on how much there is to check: more subscribed channels and more rows written since the last pass mean a bigger result to walk. As the VU count rises, so does the volume each pass moves through, and RTT rises with it.

Redis's SUBSCRIBE and PUBLISH have no such step. There's no table, no interval and no scheduled query. Redis keeps each channel's subscribers in memory and pushes a published message to all of them as it arrives, so there's no polling loop whose cost grows with what it has to check.

That's the trade this course unpacks. Solid Cable gives up Redis's near-flat curve in exchange for one less service to run, and the published numbers show the shape of that trade.

Where this course goes

  • Lesson 2: the adapter next door, PostgreSQL's own LISTEN/NOTIFY, which Action Cable has long shipped, and the hard limit that decides whether you can use it.
  • Lesson 3: polling_interval, the one setting that touches latency directly, and its cost.
  • Lesson 4: autotrim, what changes when broadcast volume rises, and a detail in the gem's source a quick README read misses.
  • Lesson 5: connects_to and this app's production database.yml, a deliberate trade-off.
  • Lesson 6: what happens once you run more than one server process.
  • Lesson 7: the whole picture, from where Solid Cable's defaults are plenty to where the answer is a different adapter.

By the end you won't be choosing between Solid Cable and Redis on faith. You'll know which number you're trading for which dependency.

Key takeaways

  • The numbers come from the gem's own bench/ load test, run with k6 on a Hetzner CCX13 and published in the installed README.md of solid_cable 4.0.2.
  • At 100 VUs, Solid Cable on PostgreSQL averages about double Redis's round-trip time, and at 500 VUs over four times.
  • Solid Cable's RTT rises because each polling pass has more to check as channels and rows grow; Redis pushes each message to its subscribers as it arrives.
  • A VU is one simulated WebSocket connection, subscribed and receiving broadcasts.
Lesson 1 of 7 · free

Keep going with lesson 2

The adapter next door: PostgreSQL's own LISTEN/NOTIFY

Compares Solid Cable with Action Cable's postgresql adapter, which uses LISTEN/NOTIFY and limits payloads to just under 8 kB.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...