Live data from Hacker News

Solid Queue 1.6.0 now supports fiber workers

github.com

11–20 of 41 posts

Re: Solid Queue 1.6.0 now supports fiber workers

#11
post #5

My concern is number of database connections. In the example it's 100 fibers per worker, at that rate you are going to exhaust db connections sooner. Happy to be wrong.

Carmine (which coded this Fibers update) wrote about this in his blog. See the section 'The database connection math'. And no, you won't have one connection per fiber.

The difference is staggering when you compare to threaded mode: it requires 1,320 database connections to run the same benchmark that the fiber mode runs with 60.

https://paolino.me/solid-queue-doesnt-need-a-thread-per-job/

Re: Solid Queue 1.6.0 now supports fiber workers

#12
post #2

This is a nice update. Is it possible to either have multiple ractors dispatching jobs with fibres or to set up multiple queues with different strategies? E.g. one for IO bound and one for CPU bound? With Sidekiq I’ve had luck having workers running on Truffleruby but generally don’t use it for my main rails apps.

You can, and Carmine (who coded this update) wrote exactly about this on this blog post: https://paolino.me/solid-queue-doesnt-need-a-thread-per-job/

From his article:

One backend, two modes

Fiber mode isn’t universally better. CPU-bound jobs get nothing from it, and blocking libraries or C extensions that do not cooperate with Ruby’s fiber scheduler stall the reactor. And that’s fine – you don’t have to pick one.

As Trevor Turk pointed out in the PR discussion, that’s the whole point: separately configured worker pools. Here’s what Chat with Work actually runs in production:

workers: - queues: [ chat ] fibers: 10 processes: 2 polling_interval: 0.1 - queues: [ turbo ] fibers: 10 processes: 1 polling_interval: 0.05 - queues: [ notifications, default, maintenance ] fibers: 5 processes: 1 polling_interval: 0.2 - queues: [ cpu ] threads: 1 processes: 1

Re: Solid Queue 1.6.0 now supports fiber workers

#14
post #8
post #3

So fibers are a lot like threads but they're more scoped to a task that can be paused and resumed, that's kinda cool

It’s more like goroutines or other lightweight concurrency mechanisms. If threads are OS-level concurrency primitives, fibers are scheduled within Ruby itself, which makes them much more efficient than threads. In fact, I got the following results in HTTP benchmark tests: Go: * Latency under stable load: p95 0.25–5.32 ms, p99 2.20–9.92 ms * Memory: 23–31 MB RSS across HTTP scenarios Ruby: * Latency under stable load:…

I'm unclear on the relevance of a comparison between Go and Ruby here. Ruby is radically slower than Go. It's down there with Python, if not a touch behind [1]. From the outside, I'd expect that it's possible that slight improvements in the context switching time will be dwarfed by the generally slow execution of Ruby itself; that is, if Ruby is going to take 100 microseconds to do something, whether it context switches in 1 microsecond (best-case OS thread cost) or .2 microseconds (best-case goroutine switch) is of somewhat less consequence then it is for a compiled langauge that can complete that task in 2 microseconds. That ratio of 50x is not just something I made up, it's about what you can expect in general. I'd need to see the actual Ruby benchmarks to come to any conclusions as to whether or not I'm right.

The other problem with this sort of benchmark, which is a mistake I also commonly see made by Node developers, is that the Ruby HTTP stack has significant native code in it, like: https://github.com/puma/puma/tree/main/ext/puma_http11 This is a good and proper thing that brings benefits to all involved; it's not like it's "cheating" or anything, it's a real performance benefit. But it does mean when you're benchmarking a simple HTTP server, you're benchmarking Ruby qua Ruby a lot less than you think you are, and so the relevance of such benchmarks to codebases that have actual Ruby in them will be less.

[1]: https://programming-language-benchmarks.vercel.app/python-vs...

Re: Solid Queue 1.6.0 now supports fiber workers

#15
post #14
post #8

Earlier quoted context omitted.

It’s more like goroutines or other lightweight concurrency mechanisms. If threads are OS-level concurrency primitives, fibers are scheduled within Ruby itself, which makes them much more efficient than threads. In fact, I got the following results in HTTP benchmark tests: Go: * Latency under stable load: p95 0.25–5.32 ms, p99 2.20–9.92 ms * Memory: 23–31 MB RSS across HTTP scenarios Ruby: * Latency under stable load:…

I'm unclear on the relevance of a comparison between Go and Ruby here. Ruby is radically slower than Go. It's down there with Python, if not a touch behind [1]. From the outside, I'd expect that it's possible that slight improvements in the context switching time will be dwarfed by the generally slow execution of Ruby itself; that is, if Ruby is going to take 100 microseconds to do something, whether it context switc…

I think the GP just showed that in a particular scenario, Ruby isn’t “radically slower” than Go. So how is the comparison not relevant?

Re: Solid Queue 1.6.0 now supports fiber workers

#16
post #4
post #3

So fibers are a lot like threads but they're more scoped to a task that can be paused and resumed, that's kinda cool

Some programmers find it easier to write concurrent programs that use "light-weight threads", "fibers", "goroutines", "coroutines" or other variants of this idea. This feature is obviously intended for them and it might enhance their productivity. Nonetheless, no program that uses a great number of any variant of the "light-weight threads" can ever be as efficient as a thread pool that is dimensioned to have the same…

Some context:

Fiber is a datastructure where the execution context is saved. Eg. registers (including instruction pointer) and stack etc. That is a fiber: data.

You normally use a threadpool, core pinned, to execute these fibers.

Since you jump in userspace, you more or less only have to pay for cache misses.

There are many upsides of designing a program using fibers. The major downside i see is that you can not blindly trust mutex and semaphores any longer - since the fiber can change execution thread while yielding/waiting for condition.

Re: Solid Queue 1.6.0 now supports fiber workers

#18

As someone who spent 15+ years doing Ruby/Rails, it’s nice to see this land. That said, these days you’ll pry the BEAM from my cold, dead hands. It’s hard to go back to any other concurrency story.

What's BEAM?

https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)

Re: Solid Queue 1.6.0 now supports fiber workers

#19
post #14

Earlier quoted context omitted.

I'm unclear on the relevance of a comparison between Go and Ruby here. Ruby is radically slower than Go. It's down there with Python, if not a touch behind [1]. From the outside, I'd expect that it's possible that slight improvements in the context switching time will be dwarfed by the generally slow execution of Ruby itself; that is, if Ruby is going to take 100 microseconds to do something, whether it context switc…

I think the GP just showed that in a particular scenario, Ruby isn’t “radically slower” than Go. So how is the comparison not relevant?

Thanks! That was exactly my point. The ruby community has made many performance improvements since 2.0, including JIT compilation, fibers and ractors.

Re: Solid Queue 1.6.0 now supports fiber workers

#20

As someone who spent 15+ years doing Ruby/Rails, it’s nice to see this land. That said, these days you’ll pry the BEAM from my cold, dead hands. It’s hard to go back to any other concurrency story.

Same path & agreed. The amount of things you do not have to care about with BEAM/Elixir compared to Rails is really interesting.
Post reply on HN