Rage: Fast web framework compatible with Rails
github.com
github.com
The first benchmark is pretty much an empty request, so it measure each framework "overhead". That shows Rails+Puma at `0.25ms` overhead per request, and rage+iodine at `0.013ms`. That is significantly less yes, but it the overwhelming majority of case it absolutely don't matter, and this difference mostly come from Rails providing extra features.
As for the second one, it's entirely irrelevant. It's benchmarking a purely IO workload with Puma caped at 5 threads vs Iodine without a concurrency cap. You can increase "Rails" throughput about as much as you want in that benchmark by raising the number of Puma threads or switching to Falcon.
But also, not capping concurrency like this is risky. The second some CPU heavy work is mixed with this pure IO work, latency will suffer terribly. It's fine for a micro-service where you know it's really all IO though.
Disclaimer: I'm a member of Rails, but I welcome alternative frameworks, I'm just very annoyed at how terrible most benchmarks are.
Is it to use Puma? Unicorn, etc?
No idea what other options are out there though
https://www.phusionpassenger.com/library/deploy/nginx/deploy...
But then I got reverse proxy (caddy) in front
A derivative of Unicorn named Pitchfork is also in the works from Shopify - https://github.com/Shopify/pitchfork
If you run falcon on rails and access database, then you have to explicitly checkin/checkout a connection to be safe. Details here - https://github.com/rails/rails/issues/42271.
It appears the benchmark sets the Iodine thread count to 1 as the legend says. Do you think that’s not the case?
Facil.io uses an event loop to handle high concurrency in a single thread, results are not out if line with code that used LibUV.
The Puma process is likely 99% idle in that benchmark, you could crank up the thread count to 50 and get (not quite) 10x better results.
An event loop is definitely more efficient than a thread pool for such a work-load, I'm not denying that, but in this specific instance Rails+Puma is configured (granted it's just the defaults) with ball and chain.
I'm not saying the benchmark is dishonest, I'm saying it makes no sense.
It's like saying comparing Node to Rhino, or Vertx vs Spring Boot is unfair. Better performance per thread / core is the whole point.
You will not achieve the same level of performance with threads except in low-volume benchmarks, and _especially_ in any kind of cloud environment where you usually only have a single core and a shared kernel.
When you have a workload that is CPU heavy enough that you won't have more than a handful of threads of concurrency, using a thread pool will allow preemption, hence give you a better tail latency, etc.
It's all tradeoff, event loops are good for some work loads, threads for others.
So to make an analogy of my own, it's like making a race between an F1 car and a semi-truck. They are both useful and efficient motor vehicule, but they're not optimized for the same thing.
You said the benchmark is "entirely irrelevant" because it doesn't take into account a scenario that is explicitly not the goal of either project. For those workloads Ruby is already far down the list of best choices.
No, that's where I disagree. The average Ruby web application isn't as IO heavy as people claim, and often contains big chunks of CPU work (typically HTML templating or JSON generation/parsing) that run havoc in an event loop.
My measurements on dozens of Rails app showed the IO ratio tend to be in the 30-70% range. Most closer to 50%. The apps that do more IO than that either have terribly optimized DB queries, or are mostly acting as some sort of HTTP client for an API, but from my experience that's the exception, not the rule.
> For those workloads Ruby is already far down the list of best choices.
Raw speed is far from the only criteria when one chose a stack...
Does that mean the typical Ruby workload would be a better match for userspace preemptive threads like BEAM?
You needn't use your real name, of course, but for HN to be a community, users need some identity for other users to relate to. Otherwise we may as well have no usernames and no community, and that would be a different kind of forum. https://hn.algolia.com/?sort=byDate&dateRange=all&type=comme...
> The RealWorld Demo is a large community-backed open source project that showcases all web frameworks client or server-side through a building an example app that is much more substantial than the typical TodoMVC toy demos or the stripped out scenarios you find in benchmarks. As Conduit, a Medium clone of sorts, your application has to handle real issues like authentication, routing, and async data loading. It has a standardized specification [...]
Or something simpler?
It all depends on what you are trying to demonstrate. The current benchmarks would be fine if properly contextualized and presented a bit differently.
e.g. for the first one, instead of representing it in request/second, do a breakdown of average/p50/p90/p99 latency over X requests. That's both much more interesting data, and much less misleading.
Even the second one could be fine if used to demonstrate why an event loop can be the appropriate thing to use for IO heavy workloads.
But here they are just included with no explanations, implying a blanket "we're 25 times faster than Rails".
Off the top of my head:
- json serialization
- fetching random objects from an actual mysql/psql database
- cached queries
- performing mutations / data updates
writing "hello world" as a response is naturally going to do 75k per second
I'm not saying don't bother optimizing something written in Ruby, I'm saying Ruby has inherent limitations in terms of performance. If performance is your goal you're using the wrong language.
And yet, the fastest Ruby entry is at 274th place while Rails is at 427th.
https://www.techempower.com/benchmarks/#hw=ph&test=fortune&s...
These are pretty standard benchmarks showing the overhead of a framework and how it behaves with certain types of operations.
Thanks. I'll pass on that one. Nevertheless, both rage and iodine seem like pretty cool projects FWIW.
> Thanks. I'll pass on that one.
I don't know, there's definitely some merit in separating your front end from your back end - at least that's the impression I got after struggling on JSF/PrimeFaces Java projects for a few years, because at least with a well defined API and no magic behind the scenes everything becomes more observable and easier to reason about, with fewer bugs. Some might prefer TypeScript or something else to JavaScript, but I think the point still stands.
In addition, this lets migrate or change everything piece by piece, as long as the interface isn't broken:
- different frameworks (let's say from Spring to Spring Boot, or from the old ASP.NET to the new variety that runs on Linux, or Rails to Rage or vice versa)
- different languages (if someone decided to take their PHP Laravel solution and migrate to Ruby with Ruby on Rails, or Python, or anything else)
- deprecated technologies can also be handled gradually (e.g. supporting an EOL AngularJS solution while developing a new front end in Vue/React/Angular/whatever)
As for the reason for those migrations, sometimes code just rots due to neglect, other times you need features that aren't available in your solution of choice (for example, pre-made UI components, like PrimeVue, PrimeReact and PrimeNG have; or maybe needing to have responsive maps in the app). In addition, you can also deploy your front end and back end separately, have different rules for the reverse proxy in front of them, suddenly have a very clear view of where your static assets are, might have all of the benefits of a SPA and PWA (if needed), anyone can integrate with your API if needed/allowed because you've hopefully built it to actually be usable and so on. Plus, your front end can talk to multiple different APIs, so if you have multiple teams working on those, suddenly that is a solved issue for you as well.That said, it's also a lot of work because SPA and adjacent approaches bring a lot of complexity into the mix and something like Vue/React/Angular and its ecosystem will bring its own pain points and things you have to learn. If all you need is a bunch of forms, then pretty much anything will do fine and SSR is a good choice. If you need an "app" on the web, then HTML/JS/CSS isn't a very good choice to begin with (historically not built for that; though I don't think there are actually good choices, same as with desktop software), but those SPA solutions will see you pretty far.
Rails especially is very good for this with partials. Use ERBs (or Haml, Slim, etc) and it's an absolute bliss with the added benefit of easy caching.
Stop duplicating state. Stop duplicating logic. Maybe in the future when your app needs 5 different clients, it makes sense to only have an API. But let's not pretend that should be the default!
I still cry every time I see a new application using GraphQL to have literally one client which is simply serving HTML with a bloated JS framework. The whole premise of it was to be flexible for multiple frontends. Come on folks, YAGNI.
If you have a lot of components to implement, everything requires thinking. Example: You want to add a repeat field to a form. Easy, get the input from an endpoint, and append. Done? No, how do you remove a field? Add a line of JS, simple! Drag and drop if the order needs to change? Let's add a dependency! [1]
I really love it for simple applications though. Resist implementing a complicated menu, live notifications, an editable data-table and such non-web-native things and you can create the fastest CRUD app ever.
And you will need another client (don't YAGNI me on this one, burned too many times by people not caring about endpoint design), but that's not really an issue if your view model does not contain non-public data (it shouldn't), as you can convert it to JSON at the same endpoint (respect the accepts header) and call it an API.
This is 100% true and the biggest loss in web development in my opinion.
SPAs actually end up making this worse in the long run though. The major SPA frameworks are all moving to an RPC model of all things, entirely coupling your frontend and back end together. The original SPA approach did offer the ability to separate frontend and backend, but the frontend scaled poorly and brought in too many complex considerations like routing, caching, error handling and recovery, etc. The new approach is basically abandoning the benefits of an isolated back end in favor of tight coupling simply because the existing frameworks are too far down the wrong path.
If your goal is ever to isolate the frontend and backend you'll want to consider three environments - backend, web server, and frontend. Ironically that's exactly where we were when SPAs broke out onto the scene
I'm not familiar with this development. Do you mean that for example React has grown a backend running on a server, querying the database, etc?
I know that backend frameworks like Rails and basically all the major ones added a JS layer running inside the browser and obeying to the backend. It listens to messages from the backend with changes to the UI elements and that saves full page reloads.
Rails has been a full stack framework since the start, with the JS component changing frequently over the decades, but with template helpers that generate JS being a fundamental component since the beginning.
They're all adding features where code is marshalled back to the server either through useServer() hooks, pragmas, or magic $ signs and imports.
They all create RPC calls as part of the build and bundle step. Depending on the specific implementation, that usually means taking code that otherwise looks like client code, moving it to the server bundle with a unique API signature, and swapping the RPC API call into the client code.
Don't make me think! Just follow the trend.
Check it out: https://youtu.be/iqXjGiQ_D-A?t=665
Quite an interesting idea, but stating that JS is the true way of creating Web UIs misses the mark by miles. You would be surprised by how far you can get with HTML and CSS alone. You will ofc need JS for more dynamic interactions, but ditching the server entirely and delegating everything to JS will just take us to the SPA mess that most of have been burned with.
Most recent app I worked on used Mantine for a base component library. Having such a large collection of drop-in components made the app come together very quickly. Performance matters but a well built react front-end for a solid MVP is performant enough.
I haven’t seen a vision like this for the stimulus/htmx world. How do you import components?
No.
(I quite like ClojureScript.)
yes, I am THAT guy...
[1] https://turbo.hotwired.dev
[2] https://htmx.org
Can't wait for this to popup on techempower benchmarks! But I would've hoped that there was some proper benchmarks done instead of these unrealistic ones.
Great project either way!
I still love the idea, but I don't foresee a migration path since activerecord is still necessary for a migration path
But it's sooo interesting! I would love to see it merged with Rails core like Merb on its day, one can dream!
Well, the Rage team certainly is opinionated!
It's a really stupid line and whoever wrote it is embarrassing themselves.
Also, a more real/demanding benchmark would be great.
Keep it up!
The API + static versioned self-contained html/css/js asset bundle is the way for anything you would reach for erb for.
I don't mind the opinionated take on JS, each to their own
We couldn't increase the number of threads a lot, since it increased the memory usage a lot which eventually led to OOMs.
I tried to put something together using async-http [0], but it was not very stable.
One question would be, how does scheduling work with existing psql and myself db gems. Should the calling code wrap the database calls with `Fiber.await { Fiber.schedule { ... } }`?
A framework like this would be very useful when the tech-world is moving towards micro-services, for the good or bad. [0](https://github.com/socketry/async-http)
Nope. Scheduling works seamlessly, thanks to Ruby core.
Thank you for all your feedback. I value it a lot!
First off, I have changed the API-only bullet point. I wanted it to be short and clear. I didn't mean to sound arrogant. Sorry for that.
Second, I'm working on a guide explaining how to use the framework alongside an existing Rails project. So stay tuned!
I mean 180+ commits, 3 month old, bold claims and already 8 releases on rubygems?
There ought to be a vetting/voting process for packages, before they are accepted into a public repo and pollute the global namespace. Like in arch repo/AUR.
There are at least 4 languages where it’s more appropriate if you desire a lot of speed.
Tenderlove posted this gist a while ago as proof of concept:
I'm curious though, what's your use case to and HTTP2 up to the app server?
Just the tone of that statement is coming from the wrong angle.
aight bud. do it without html and css. go on.
I appreciate DHHs and his teams attempt at providing an true alternative to front-end frameworks.
While using Rails own templating engine creates all the links and urls for you!
There's still nothing stopping you from jettisoning view support and just using Rails as an API if you want to.
Still looks like a niche language.
I would argue the same is true for the server.
The ecosystem is slowly fading away. Big industrial libs are still good, but a lot of smaller projects are abandonware, last updated in 18-19.
The cool kids moved on to Go, Rust, TS, Elixir etc.
It seems like they just had to publish couple of benchmarks and articles here and there and that could have been it.
As it has good C interop story it could have a good chance riding on AI hype wave few years later in this alternative history.
That and I’ve found that folks often aren’t very receptive to Ruby like syntaxes initially.
I really wanted to like Crystal, and used it for a few projects. But the immaturity and timing was it's kryptonite.
M:N wasn't added until late 2019 :( -- https://github.com/crystal-lang/crystal/pull/8112
Rails has been on a downward trend for the last 6 years.
[1] https://trends.google.co.in/trends/explore?cat=958&date=2017...
Shopify and GitHub uses MySQL heavily.
And so does Youtube and other behemoths.
Where did you get the notion that MySQL doesn't scale?
Sorry but I find this part contradictory.
And the argument that follows sounds like backpedaling.
Twitter ended up ditching Rails anyways despite "fixing" their data storage. So to me their problem was indeed Rails.
Then they started building a lot of things that weren't web applications, like RPC servers (where they created the finagle library) they ended up with a team where Scala and the JVM was more their area of expertise and interest and solution to every issue.
No one thinks you use MySQL to build every kind of data application, no one thinks you use Rails to build every kind of server.