Hacker News new | ask | show | jobs
by ciconia 908 days ago
I believe with version 3.3 Ruby is back in a big way! The language focused on developer happiness and derided for its slowness is slow no more.

YJIT is an amazing technology, and together with other innovations like object shapes and various GC optimizations, Ruby is becoming seriously fast! Big Ruby shops such as Shopify [1] have been running 3.3 pre-release with YJIT and reporting double digit percentage performance improvements.

Personally I'm really excited about Ruby and its future. I can't wait to start working with Ruby 3.3 and using it on my client's production sites...

[1] https://railsatscale.com/2023-09-18-ruby-3-3-s-yjit-runs-sho...

Edit: add percentage to performance improvements.

7 comments

I don't know if a slight performance increase is going to sell anyone on ruby but I'm glad they're making incremental improvements on things. Being overly concerned about performance is almost always premature optimization, and ruby is more than fast enough for everything I've ever asked of it (including the binding glue between our redis DNS record storage and PowerDNS, where the entire stack serves half a billion queries a month across 14 tiny VPSes without even a blip on htop). I probably could have just used ruby instead of PowerDNS but it's generally not great to roll-your-own on public facing encryption, HTTP, DNS, etc. It wasn't really a performance consideration for me.

The recent irony of the web is anyone that implemented a web app with "slow" ruby and backend rendering now has the fastest page loads compared to bloated front-end web apps backed by actually slow eventually consistent databases that take seconds to load even the tiniest bits of information. I see the spinner GIF far too often while doing menial things on the "modern" web.

> half a billion queries a month across 14 tiny VPSes

For reference:

  $ units -1v '1|2 billion reqs/month / 14 servers' 'req/sec/server'
        1|2 billion reqs/month / 14 servers = 13.580899 req/sec/server
I always do this when I see large-sounding query counts; a month has a lot of seconds in it, and it’s easier to visualize only one at a time: I can imagine hooking a speaker up to the server and getting a 14Hz buzz, or do a quick mental arithmetic and conclude that we have ~70ms to serve each request. (Though peak RPS is usually more relevant when calculating perf numbers; traffic tends to be lumpy so we need overhead to spare at all other times which makes the average much less impressive-sounding.)
Indeed it's just the most performance-critical part of the stack that happens to involve ruby because I needed a shim between redis and powerdns. I write it as a quick hack years ago and have never had to make any changes to it.

I think that shim still uses ruby 2.6, I may try to upgrade it to 3.3 with yjit and see what the latency drop is, which is probably a more interesting number anyways, but again only really matters for a single caching request that only happens once in a while.

The real reason I continue to use ruby is because it's a quick way to get things done on business logic heavy web apps, but I continue to be impressed how much I can get away with using it for things it's really not known for being good at. I run into people often that refuse to use it for absolutely anything because there's a perception that it's "too slow", but when pressed I learn that they're not really working on anything that requires high performance provided by more esoteric languages with stricter memory management that is very likely nerfing their productivity unnecessarily. My goal here was to push back on that perception a bit, not to make the dns shim sound impressive.

The reverse is good also. 0.00005 vs 0.005 cents/request seems very close as a human. But considering that times the seconds in a day or month results in very different values.
I also like to double check these kind of numbers and basically agree with your take. Although, I like to use a 28 day month and an 8-10 hour day rather than assuming smooth traffic over 24 hours. Even with all that, 1/2 a billion is well under 50 req/sec which is not a big deal for the rendering servers. All that traffic coming together on a database server might be a bottleneck though.
TIL there is units command line tool.
Yea 14 qps isn’t high performance. I think the parent comment is right that most people don’t work on high performance software and so Ruby will work fine.

But something to keep in mind. I’ve seen servers before that could serve in the 100,000 QPS range on a single instance! They weren’t written in Ruby.

Ruby the language may be fast but the whole ecosystem is painfully slow. Try writing a server that serves 1mb of json per request out of some db query and some calls to other services. I get 100 requests per second in Rails. Same service rewritten in go serves 100k requests/s.
Why Rails, instead of a lighter-weight framework, if performance is such a priority? Obviously that wouldn't get you to [anywhere near] the performance of compiled Go code, but Rails has a lot of overhead.

What database is on the backend, and is that db serving cached content? What happens if you cache it with e.g. redis to avoid the heavyweight rails ORM stuff?

Do you have granular benchmarks for the db query, requests to other services, and the web processing itself (using artificially pre-cached responses from db and those other services)?

First implementation was in Rails because the company is a Rails shop and the monolith was the easiest place to get something that works.

If you rewrite it anyway, might as well use something else than ruby.

The db (mysql) is not the problem in the scenario I described.

> If you rewrite it anyway, might as well use something else than ruby.

You just said the company is a rails shop, why would you force a new language on everyone who already invested in understanding ruby?

Because people know Ruby well, including use cases that it's not a good fit for. We use Go in other places, too.
Why not something like Sinatra so it’s easy to prototype and move on from there if it’s still not good enough? What you’re describing isn’t that complex and the base Ruby language is so much better than Go.
Why does that matter?

You’re likely in one of two situations as a businesss:

* You’re a struggling startup. Development velocity trumps literally everything. Your server costs are trivial, just turn them up.

* You’re a successful business (maybe in part because you moved fast with Ruby), you can pay down the debt on that absurdly large response. Chunk it, paginate it, remove unnecessary attributes.

1MB is "absurdly large"? This is not the Todo app industry sorry.

This is paginated (page size of 1000) and the caller chooses only the attribute they need already, thanks.

Even successful companies care whether they need to run 1000 servers or one for something.

You're pushing 100Gb/s of JSON (1Mb*100k/s)? AND your calling other services + a DB per request on a single server? I'm skeptical.
The test was local, ie using the loopback interface on a large server.
Are you actually going to the DB or is that json synthetically generated? Is it the same json? What exactly are we testing here?
Sorry I was oversimplifying. Most of the data for the response comes from the db with some API calls for authorization and some auxiliary data. Benchmark was actually hitting the DB. Quite a bit of the 1mb response size is redundant (json-api format).
In my experience, you get 10x to 100x gains easily switching to something lighter than Rails, like Roda.
But, like, why do you need a 1MB json response? That’s probably either a bad design or a use-case Rails is not designed for.
It's a paginated list of 1000 objects of 1kb size each. Any nontrivial API will have responses like that.

My entire point was that Rails is not designed for this.

But you could return the 1000 objects (or less? 1000 records sounds like a lot for any UI to show at once) of 1kb size and allow the clients to request specific pages with a request parameter. There may be applications where you need to ship the full 1M records I guess, but that seems like very much an edge case as far as web apps go.
True, you would not return 1000 objects at once to the frontend.

I first thought it's just a backend use-case, where processing 1000 records in a paginated result is common, but the parent mentions "rails", so it sounds like a frontend use-case.

It's a backend use case.
1,000 records is absolutely not a lot on modern computers or connections. On a business LAN, this request should take well under a second full latency.

On an average mobile connection, it’s maybe a second or so.

You’re right. It’s not a lot for a machine. The point isn’t the speed capability. It’s why? What UI has 1,000 rows in, e.g., a table all at once (much less 1M)?
The better question is

“Why would I pointlessly accept this clear case of massive technical debt for literally no reason what-so-ever?”

Rails does not present any sort of promise that go does not also present, so just saying “yeah, I’ll handcuff my app like this cause I feel like using Ruby” is, frankly, absurd.

When you ask the right questions, you never land on Ruby, and that’s why Ruby continues to decline.

It depends on the metrics you care about.

Ruby is concise compared to Go though. I like Go and but when I use it I have to accept that I'll write (and debug) at twice as much code as I would do in Ruby.

If you're mostly just loading data into a large fast cache, lines of code may be a more critical dimension than execution speed.

That's how well designed Rails projects work and you get most of what you need straight out of the box.

> double digit performance improvements

You mean like 10% faster, or 10x faster?

Edit: clicked the link; it's 10%. I don't think that's going to make any difference to the perception of Ruby's slowness given that it's on the order of 50-200x slower than "fast" languages like Rust, Java, Go and C++.

Note this is for a Ruby on Rails application. The slowness is I believe more due to the framework than the language runtime. In any case, it's still early to determine the impact on performance from upgrading to Ruby 3.3. I guess we'll be able to tell more in the coming months.
> Note this is for a Ruby on Rails application. The slowness is I believe more due to the framework than the language runtime.

Hardly relevant, I'd think at least 80% of all Ruby usage everywhere is in Ruby on Rails applications.

How much of the time in a given request is even spent in Ruby code? The majority of web apps that were slow and I got a chance to analyze were spending much of the time in DB queries and slowness was usually due to unoptimized DB queries. Even endpoints that were fast, still spent a large percentage of their time not in Ruby but in DB and service requests
That is true, yes, but still comparing e.g. Rust vs. Ruby I'd think Rust spends anywhere from 10ns to 100ns (outside of waiting on DB) and Ruby no less than 10 ms. Still pretty significant and can add up during times of big load.

Also I remember Rails' ActiveRecord having some pretty egregious performance footprint (we're talking 10ms to 100ms on top of DB waiting) but I hear that was fixed a while ago.

My point was that if we look at Rails performance going up 10%, what does that mean for time spent in Ruby. I'd believe anything from a 15% to a 80% reduction of time spent in Ruby code
It is relevant if the cause of the slowness is due to the framework rather than the language itself.

The performance can vary drastically depending on which Ruby framework you use, so it's not due to the language but the upper layer instead.

Note, even if Rails is the most popular framework, there is still other alternatives which makes it even more relevant to the performance impact.

I suspect there's not just one cause of slowness here. Pure language benchmarks also tend to rank Ruby very low. So I'd wager that a fast Ruby framework would still lose to a fast Go framework.
Absolutely, I should maybe clarify that I did not mean to say that we can fully rule out the language itself as a cause of the poor performance, Ruby always perform worse than Go in this example for obvious reasons.

But, saying that the frameworks using the language under the hood has almost no relevancy is wrong in my opinion! And that is what I was trying to point out.

Apples to oranges again. A more relevant comparison would be Ruby to Python and in recent years Ruby has edged ahead in performance if you factor-out Python's C-based libraries such as Numpy.
If you compare pure Ruby without Rails to fast language like Rust, Go and Java. It is probably closer to 10-20x.

The 100x to 200x mainly comes from Rails.

Can we stop with these useless comparisons? 10x-20x, 100x, 200x out of context means absolutely nothing.

All these micro-benchmarks shootouts means nothing either. Is anyone running a mandelbrot or pi-digits SaaS company? I'd think not.

Similarly saying Rails is slow out of context, means nothing, Rails is "slower" than Ruby micro-frameworks X because it does useful things the other doesn't like CSRF protection etc. If you don't need these features, turn them off and Rails will be about as fast as these frameworks.

If anything annoys me more than clueless people shitting on Ruby for bad reasons it's Rubyists spreading FUD about Rails.

Perhaps it's misleading to throw around specific numbers like 100x, but Ruby is certainly orders of magnitude slower than languages like Go or Java. Both of which are not exactly known for their speed (compared to C++ or Julia, for example).
"speed" thrown without context is meaningless. It's one property of a tool among many others you generally have to trade for.

Some use cases with small margins call for the utmost efficiency to be viable business. Some use cases just need decent efficiency and are happy to trade some efficiency for some other properties.

Many successful people and companies are happy with Ruby, can we just give them a break? Or is there somehow some moral duty to use the "fastest" language available regardless of whether it makes any kind of business sense that nobody told me about?

On the other hand, why is it wrong to say Ruby or Rails is slow? Especially in the context of Java or Go? What is wrong with accepting a simple ground truth that is compiled language is and will always be faster than an interrupted language, even with JIT.

For Rails I often compare to it another CRUD app, StackExchange [1] using ASP.net And the easiest real world comparison with Rails App would be Cookpad. Are we not seeing at least 10x difference if not more.

Is Rails fast enough? That depends on the context. Everyone's business model is different. It is almost definitely fast enough for most SaaS cases.

[1] https://stackexchange.com/performance

> What is wrong with accepting a simple ground truth

Where am I denying that? Saying that one of the most dynamic language is slower than Java or Go it's such a truism it's pointless.

What annoys me is the figures quoted. I can craft you benchmarks were Ruby is barely any slower than these two, or benchmark where it's 1000x slower. So which is the correct number to quote?

> For Rails I often compare to it another CRUD app, StackExchange [1] using ASP.net

This makes zero sense. You said:

> If you compare pure Ruby without Rails to fast language like Rust, Go and Java. It is probably closer to 10-20x.

> The 100x to 200x mainly comes from Rails.

So somehow you are blaming Rails for making Ruby 10 times slower whatever that means. That is a stupid statement that you took out of your hats and that doesn't reflect any reality. Please stop doing that, it's really unnerving for the people who maintain these projects.

>So somehow you are blaming Rails for making Ruby 10 times slower whatever that means.

>That is a stupid statement that you took out of your hats and that doesn't reflect any reality.

I will leave it at that.

Apples to oranges, no?
I seriously don’t think it’s worth comparing Ruby to languages like C++ and the rest.

One is scripting language, the other compiled, the difference is huge already there.

> I seriously don’t think it’s worth comparing Ruby to languages like C++ and the rest.

It is worth comparing any two languages and ecosystems if they are used for the same things, in this case -- web backends.

Anything and everything that has a web backend is a fair game for comparison.

Building a web backend with C++ is a very dangerous and complex ordeal, you're extremely likely to expose memory based vulnerabilities to the entire world.
Yes, but I haven't argued that. Let's not shift goal posts.
Google, Facebook, Amazon and Twitter beg to differ (not completely C++, but for services where it makes sense). Also nginx, passenger and other parts of your Ruby app.
shrug the companies you mentioned do not use C++ for web-app.

Amazon is a huge Java shop.

Twitter used to be huge Rails app with Java/Scala services.

NGINX and Passenger are infrastructure pieces just like Memcached so I think you need to understand the context here...

I agree but people are doing it anyway. So technically Ruby on Rails and C++ are competitors in the web backend space.
RoR and whatever C++ based web backend there is count as a valid comparison in my book. But comparing the languages itself is maybe a bit off.

On a side note, you can actually compare their performance here if you’re really curious. But take it with a grain of salt since these are synthetic benchmarks.

https://www.techempower.com/benchmarks

Who builds web backend in C++?
Web backends in Rust and C++? Not saying web frameworks in these languages don't exist but to claim they're anything other than curiosities is misleading. In any case, good luck with the fraction of a millisecond such languages gain you while waiting on database i/o. There are use cases for switching to a compiled language like Rust or C++. Web back-ends isn't one of them.
Nah. One rust based server can power the same number of connections as 10-100 ruby based servers.

This is not just “pretend database IO” problem. This is actual cost that no business should accept on the basis of “but but but database IO (that I’ve never actually measured, but it’s an easy cop out because I read it on medium once).

But you factored-out developer productivity. What you gain in reduced server costs is lost many times over in developer productivity. Companies who chose Rails for decades knew it was slower and more memory-hungry than rolling everything yourself in Rust or C++. They did the math and the business case for Rails was more compelling.
Yes and no, some languages like Python and Ruby do introduce overhead even in conditions where waiting for the DB is 80-90% of the time spent on a web request -- that much is true. But the database I/O problem is definitely not pretend. It's very real.
I'd choose Go and Java any given day before Rust.

That language with C++ mindset is just... horrible.

I would agree with C++, but not Rust. Describing Rust web backends as a curiousity is inaccurate.
I am not interested in being put in a corner where I have to defend web backend creation that I don't even practice. I only said it's being done by people. Feel free to reject it or degrade it as being "a curiosity", from where I am standing reality disagrees with you though.
> It is worth comparing any two languages and ecosystems if they are used for the same things, in this case -- web backends.

Right I see your point, but in this case it’s about Ruby, the language itself, not RoR.

Not denying it, I just struggle to find any non-RoR usage of Ruby out there except maybe for Homebrew.
You're right about that, and that's something I believe the Ruby team is struggling with, to show where Ruby is useful outside the Web field. Everyones picture of Ruby is web related thanks to Rails, there is no question about it.

And I find that bit sad because Ruby is also good at other things like building cli apps (have a look at Metasploit for example) & gluing different moving parts together, creating your own DSL thanks to its flexible language structure.

I wouldn't say Ruby is better than any other languge though, all general purpose language could probably achieve the same result, it's just a matter of taste.

Metasploit? Logstash? Docker-sync? Vagrant? Jekyll?
Chef? Puppet?
It may be worth comparing this new JIT to fast implementations of dynamic languages, like LuaJIT or SBCL for Common Lisp (SBCL is an AOT compiler and not a JIT though).
I'm so glad that you said this and weren't downvoted into the ground. Honestly, Ruby needs to die. It performs like a go cart in a Formula 1 race. I'm actually just exhausted watching smart people tell me this is a language and toolchain worth dedicating brain cells to.
What a bizarre take. Ruby is primarily used in web applications, where round-trip http requests, database queries, and other 10s-of-ms things are commonplace. Ruby is very rarely the bottleneck in these applications. Choosing to make your job significantly more challenging in order to maximize the performance of a small portion of the total response time of a web application is not, in my estimation, a smart decision.
There's always this rift between the "language is slow" crowd and the "but it's not the bottleneck" crowd. I think this comes from the types of applications you work on and their scale.

I work at what a company that's not particularly large. Our original API is a Django monolith that serves about 1000req/s.

While you could argue Python isn't the bottleneck, Django often is. I hear the same feedback from colleagues that work in Rails. Not only do we run into issues with latency per request but we have to run a significant number of Kubernetes pods to serve this workload. With c#, golang, java or a similar language we would only require a handful of pods and drastically cut our compute costs.

Even for web workloads, these slow interpreted languages and their developer experience optimized frameworks absolutely do become a bottleneck and claiming they don't (or that you need to be at Google/Facebook scale before they do) is false.

Everything is a tradeoff but the way I think of it: speed is a feature.

Further, with a lot of the batteries-included web frameworks you end up with a ton of suboptimal database queries (e.g. unintentional query-in-loop). Some would argue that you can just profile your code and optimize the hot spots, but I would tend to think it still slows you down quite a bit overall.
One of the biggest breaking changes that EF Core did was to explicitly disallow such generated queries that required application-side evaluation and could not get compiled to pure SQL (you can get other behavior back with a toggle but it is discouraged).

I strongly believe it is wrong to do otherwise and is a source of numerous footguns unless you invest in tracking them down.

So common that apps like sentry have special logic to detect these "N+1" queries. We find DRF is awful for this.
It's 'resource usage' rather than 'speed'
You're literally the exact person I'm talking about. No serious application developer who's interested in speed is working in Ruby. This isn't my opinion. I don't care personally, it's just a fact if you care about reality. When Netflix announces that they use Ruby because it performs faster than Node.js, I'll change my opinion, because my opinion is based on facts and not feelings. I didn't make Ruby, so whether it does well or fails isn't personally important to me. If Ruby was the fastest interpreter, I'd be pro-Ruby but it absolutely isn't and pretending it is is depressing and shows you are making political or selfish decisions, not practical ones.
I don't think you can argue that you personally don't care about ruby.

You wouldn't spend so much of your time reading and writing about ruby if you didn't care about it. You'd move to things you do care about.

Ruby, and scripting languages in general, are fast enough for the jobs they get used for. When they're not they get replaced.

Most of your comment is about what you think I think, and not a lot about metrics, data or examples where Ruby performs beyond my interpretation. I think that says a lot right there.
Nobody is pretending Ruby is the fastest interpreter. Who are you arguing against? Rubyists generally consider Ruby “fast enough”. Which it is, for many applications.

For every engineer insisting Ruby is fast enough in a situation where it is not, there are 1000s in environments where Ruby absolutely is more than sufficient, insisting it’s too slow.

It doesn't answer the question of why you would choose Ruby. Honestly, you all sound like you got a Sega Genesis for Christmas, while everyone else got a SNES. You can tell other kids on the playground that Genesis has better graphics, but the spec sheets don't lie.

You're trying to make it seem like it's a wash, because "scripted" but it's not. Node.js outperforms Ruby in every department. And it's based on one of the slowest scripting languages of all time. Ruby is a dead language in many countries.

In Canada, you would have to travel the country to find a Ruby job. And if you don't think in American-centric terms, that is meaningful.

Ruby and Python are the only two ecosystems that seem to prioritize developer happiness. They're a pleasure to work with. So they're not going to die anytime soon.
Python might be popular but developer happiness isn't a concept I'd associate with the language. There's no joy in being limited to single statements in lambdas, for example.
Python is somewhat pleasure. Ruby might as well be sandscript as far as I'm concerned. The use of pipes is gross, uncoordinated and lacking direction.
One area where Ruby could help improve developer experience is by providing a better debugging experience. I feel incredibly spoiled with Chrome Dev Tools. Meanwhile the last time I tried debugging heavy metaprogramming Ruby code it was a pain to figure out what was happening.
Meta programming is my largest complaint with Ruby. It creates huge surprises that are very difficult to inspect and debug.
We ban most meta programming in our own code. While the meta programming solutions are fun and clever they are often more code than a functional version and hard to maintain.

We do allow the occasional use of “send” but try to avoid it. Dynamic method definitions are strictly banned.

what is ruby debug not able to do that you want it to do?

https://github.com/ruby/debug

a nice ide integrated experience:

https://code.visualstudio.com/docs/languages/ruby#_debugging...

https://github.com/ruby/vscode-rdbg

https://code.visualstudio.com/docs/editor/debugging

heavy metaprogramming in any language is going to be a pain to debug so i'm not sure what you're expecting but there are tools to help. you can also call source_location on some method to figure out where things exist.

Ruby 3.3 has made major improvements to the debugging experience: https://railsatscale.com/2023-12-19-irb-for-ruby-3-3/
that's surprising considering `pry`[1] is such an amazing debugger IMO.

[1] https://github.com/pry/pry

I was pretty excited hearing “double digit” thinking 50 or 80%.

The link shows 13-15%.

Unless those “double digits” are 98+%, ruby is still going to be quadruple digit percentage points behind strong competitors in terms of performance.

If I’m going to give it even a second glance, I can’t be seeing “ruby 10,000% slower than Java” for measured use cases.

I’ve never met literally anyone who saw ruby and was happy. It’s always “but it’s written in ruby”
Pleasure to meet you.
I have to write awful primitively-obsessed Python at work. I LOVE Ruby.