3 ms·
Thanks for the anecdotal counterpoint, that is what I was looking for! I think we're talking about different things though. I think OP was suggesting/question
by jrochkind1 4y ago
Thanks for the anecdotal counterpoint, that is what I was looking for!
I think we're talking about different things though.
I think OP was suggesting/questioning whether a typical Rails apps may spend 90% of it's overall time in I/O.
I am suggesting the reverse, that typical Rails apps (so long as they don't have bugs where they fetch more than they need) will spend spend 60-80% of their time in CPU rather than I/O.
I am curious if this is true of shoppify's app; my guess is it still would be (especially cause I think shopify will not have very many bugs where it's fetching things inefficiently or that it doesn't need to fetch, shopify will be higher-quality than a random rails app).
You are suggesting, I think, that at shopify atypical, problem requests were always due to I/O.
I think all of this can be simultaneously true.
I think a side issue to what I'm talking about, but:
> We spent significant amounts of time finding ways to work around Rail's inability to do these sorts of things in parallel
Rails 7 actually recently introduced a feature to do multiple ActiveRecord fetches concurrently... perhaps motivated by/developed by Shopify? https://pawelurbanek.com/rails-load-async https://pawelurbanek.com/rails-load-async
I haven't used that one yet. In the past when I've needed to do things like external API requests in parallel, I have had success just using futures/promises from Ruby::Concurrent, without even telling Rails about it. I've had to do this only rarely, but I haven't run into too much trouble. But one thing you can run into if your threads try to store things in ActiveRecord themselves, is running out of database connections with Rails "long connection checkout" model, involving explicit handling of pool checkouts once you do your own threads. Sequel (vs ActiveRecord) has a much more connection-efficient way of pooling database connections, where they are transparently checked out of the pool, under the hood without you usually needing to manage it explicitly, for only as long as it takes to execute a single statement. When doing heavily concurrent things with AR, I have often wished it used Sequel's concurrency/connection-pooling model.
- joshmn 4y agoSo many familiar faces in this thread. :) With Ruby::Concurrent, I found similar weird-isms until I wrapped in `Rails.application.executor`. Rails has its quirks and purists can be put off by all the "extra work" that needs to happen for things to play nicely together. To that I say: Rails gives me superpowers and I need to abuse them appropriately.
- jrochkind1 4y agoTotally -- I've been trying to do multi-threaded concurrency like this since before Rails actually had `Rails.application.executor` -- it was possible, there were some gotchas. It is very helpful to now have API available at that level of abstraction. It can still get weird sometimes. There are still some gotchas. Usually about ActiveRecord. With what we know now from seeing how it all works out, if we were able to do it over again greenfield, I think it's pretty clear that sequel's concurrency/pooling model is preferable to ActiveRecord's. Although I'm sure it would have it's own downsides I'd run into if I used it more and at scale.
- notpachet 4y agoYou're right, I think we're using IO/CPU bound in different senses. You're talking about where an average request spends most of its time; I was thinking more in terms of Shopify's scaling bottlenecks. Even though individual requests probably spent a lot of their time in CPU, we didn't really have to worry about CPU as a bottleneck for the larger application. Whereas IO was a different matter, and we had a lot of difficulties ensuring that we had enough capacity for spikes in the IO-heavy stuff. So the overarching Shopify application was "IO bound" in that sense.
- weatherlite 4y agoI think it also depends on architecture and what the specific endpoint does. Let's say it's a microservice architecture with lots of network calls (to fetch data from different services or even outside API calls) ...how will CPU be 80% of the time? Doesn't sound reasonable. But if there's not much calls at all and it's rendering one huge view then yeah maybe it's mostly CPU...