Jean Boussier Profile
Jean Boussier

@_byroot

3,761
Followers
205
Following
81
Media
1,219
Statuses

Rails core, Ruby committer, Senior Staff Engineer on @ShopifyEng 's Ruby and Rails infrastructure team. Mastodon: @byroot @ruby .social

Toulouse
Joined April 2022
Don't wanna be here? Send us removal request.
Pinned Tweet
@_byroot
Jean Boussier
1 year
After several months of work, we finally enabled Pitchfork reforking on 100% of Shopify's monolith. ~30% reduction in memory usage, ~9% better latency and more!
6
37
175
@_byroot
Jean Boussier
2 years
Just finished upgrading Shopify's monolith to Ruby 3.2.0 today. Average latency: -6.6% Median latency: -5.1% p99 latency: -6.7% And that's without YJIT.
11
58
615
@_byroot
Jean Boussier
10 months
As of this morning Shopify's monolith is running Ruby 3.3.0-dev in production. In the process we fixed over 20 bugs that weren't discovered before. I like to say that this app is the true last boss of Ruby testing.
Tweet media one
12
37
462
@_byroot
Jean Boussier
10 months
3 hours later, Shopify's monolith is running Ruby 3.3.0 in production! In case anyone needed any more proof of how solid this release is.
@nalsh
成瀬
10 months
Ruby 3.3 adds a new parser named Prism, uses Lrama as a parser generator, adds a new pure-Ruby JIT compiler named RJIT, and many performance improvements especially YJIT. Merry Christmas, Happy Holidays, and enjoy programming with Ruby 3.3!
1
88
187
4
55
434
@_byroot
Jean Boussier
2 years
I finally released the first (pre)version of pitchfork A new Ruby HTTP Server optimized for latency and memory usage 🧵
Tweet media one
22
73
381
@_byroot
Jean Boussier
2 years
I merged a third String#<< optimization. Overall it's now 65% faster for UTF-8. Unfortunately my profiler is no longer showing any more low hanging fruits, so that may be the last one 😞
Tweet media one
5
13
188
@_byroot
Jean Boussier
2 years
I'm always pissed when I read people calling Rails or Ruby "magic". But given that "any sufficiently advanced technology is indistinguishable from magic", I guess that makes Ruby a sufficiently advanced technology, which is nice.
7
14
149
@_byroot
Jean Boussier
2 years
We just shaved ~2ms from our median response time, ~10ms from the p99. With just a super simple patch Hopefully that will make it to Ruby 3.3
5
13
139
@_byroot
Jean Boussier
1 year
I wrote an article on the practical implications of object shapes in Ruby 3.2 and their consequence on performance, notably on the performance of the very common "memoization" pattern:
5
26
132
@_byroot
Jean Boussier
2 years
I just had a lovely chat with ⁦ @yukihiro_matz ⁩ at #RubyWorld
Tweet media one
1
0
109
@_byroot
Jean Boussier
2 years
I accidentally hit the "translate page" button in Chrome while looking at some Ruby code, and now I just can't stop laughing.
Tweet media one
11
3
85
@_byroot
Jean Boussier
2 years
If you enjoy looking at latency graphs do down, this post if for you Teaser:
Tweet media one
4
20
86
@_byroot
Jean Boussier
11 months
When you find a 6 month old daft PR your forgot about that makes almost twice as fast 😂 Featuring @peterzhu2118
Tweet media one
1
7
78
@_byroot
Jean Boussier
11 months
Today I learned about the `Performance/UnfreezeString` rubocop rule, and it made me angry We probably should go over all these cops that advocate for unobvious micro-optimizations of this sort.
5
8
72
@_byroot
Jean Boussier
2 years
Queue #pop (timeout:) was just accepted by @yukihiro_matz . A feature so obvious I always assumed it was left out on purpose, so did many others. Turns out nobody thought about formally requesting it 😂
1
5
69
@_byroot
Jean Boussier
11 months
Did you know that Ruby supports Python's triple quotes? 😂
Tweet media one
7
8
67
@_byroot
Jean Boussier
11 months
We just spent 3 days tracking down a memory corruption issue in Ruby 3.3.0-preview3. It turned out to be triggered by a single, very specific Regexp: That's why community testing preview releases is so important.
1
11
65
@_byroot
Jean Boussier
10 months
Congrats to @KJTsanaktsidis for becoming the latest Ruby committer 🎉
1
3
50
@_byroot
Jean Boussier
2 years
There was indeed no age limit. Thank you @ko1 !
Tweet media one
0
3
50
@_byroot
Jean Boussier
2 years
In short it's basically Unicorn, but with a MUCH lower memory usage. No more RAM vs latency tradeoff, you can have your cake and eat it too.
1
3
49
@_byroot
Jean Boussier
11 months
If you have the chance please try it on your app, e.g. run CI against it.The more people test this preview the more solid the final release will be.
@nalsh
成瀬
11 months
We are pleased to announce the release of Ruby 3.3.0-preview3. Ruby 3.3 adds a new parser named Prism, uses Lrama as a parser generator, adds a new pure-Ruby JIT compiler named RJIT, and many performance improvements especially YJIT.
0
45
96
0
10
47
@_byroot
Jean Boussier
2 years
I just ran a load test against one of our small apps with GVL Instrumentation enabled. The app uses 4 threads per worker. The graph is in nano-seconds, so that's over 300ms wasted waiting on the GVL per request on average 😱
Tweet media one
4
2
43
@_byroot
Jean Boussier
2 years
Now that Ruby 3.2.0 is out, I published gvltools 0.1.0. Feedback welcome.
@_byroot
Jean Boussier
2 years
Playing with the GVL instrumentation API
Tweet media one
1
5
32
1
5
36
@_byroot
Jean Boussier
2 years
I just merged the GVL instrumentation API I mentioned in the article. I'm super excited to start collecting production metrics with this. Thanks to @_ko1 and others for the reviews and directions❤️
@_byroot
Jean Boussier
2 years
An article I wrote on the tradeoffs between forking and threaded Ruby servers.
0
39
135
1
7
33
@_byroot
Jean Boussier
2 years
Playing with the GVL instrumentation API
Tweet media one
1
5
32
@_byroot
Jean Boussier
2 years
No offence, but I'm kinda wishing Matz was born in Barcelona or something right now😭
Tweet media one
2
0
31
@_byroot
Jean Boussier
2 years
The String #dedup alias just got accepted too. It's barely a one line change but will make code much more readable.
0
5
29
@_byroot
Jean Boussier
2 years
How would you call a method that works like Hash #dig , but raises an error when a key is missing? The feature is acceptable, but blocked until we find a good name
45
8
30
@_byroot
Jean Boussier
2 years
Ok, so I have a bit of time to look at this today. 🧵
@_byroot
Jean Boussier
2 years
@kddnewton @joeldrapper I have on my personal todo list to look at interpolation performance. On paper you'd think it would be almost always faster than concatenation, but most of the time it's slower. It has one big advantage by being able to right size the string.
1
0
3
1
6
28
@_byroot
Jean Boussier
2 years
About to leave Tokyo. Thank you ⁦ @davidstosik ⁩ for the visit of Asakusa!
Tweet media one
Tweet media two
Tweet media three
Tweet media four
0
1
28
@_byroot
Jean Boussier
2 years
But most of these tend to stabilize quite fast after the associated code path have been executed a few times. So Pitchfork's answer to this is to periodically take a warmed up worker out of rotation and use it to fork a new generation of workers.
3
2
27
@_byroot
Jean Boussier
2 years
I'm trying to schedule an unpaid day off to answer to the nationwide call for strike next week. But because the company has an unlimited paid time off policy, it seems like there's just no way to do it. 🤦 #FirstWorldProblems
2
0
27
@_byroot
Jean Boussier
2 years
@nateberkopec I don't have actual numbers on hand, but from what I see only a small minority of Shopify new hires are actually experienced Ruby devs. Most of them barely did any Ruby prior to joining. And that's not anything new, it's been like that for years. We just train them.
4
1
27
@_byroot
Jean Boussier
2 years
@tenderlove Major GC definitely play a big role in p95/p99 latency. I'll try to backport the patch and see if we can notice its effect in production.
2
0
26
@_byroot
Jean Boussier
2 years
I was hoping for some cool stuff to eventually come out of the GVL instrumentation API, but I must say I wasn't expecting it to happen this fast. ❤️ @KnuX
@KnuX
Ivo Anjo
2 years
I've just posted about my new #ruby gem: gvl-tracing. With this gem you can generate a timeline of Ruby Global VM Lock ("GVL") use in a Ruby application:
2
15
67
0
1
25
@_byroot
Jean Boussier
2 years
It started as a fork of Unicorn, and took some inspiration from Puma, so I'd like to first thanks them all.
2
0
26
@_byroot
Jean Boussier
2 years
Within 10 seconds of disabling airplane mode: - data is 9.70€ / MB - you’ve used 40€ of data - you’ve used 60€ of data, your data plan is disabled
4
0
26
@_byroot
Jean Boussier
2 years
@joeldrapper This is fine for small needs, but explicitly defining jobs is useful for having different queues with different SLAs, different error handling/retry policy, dealing with backward compatibility when changing a job argument, etc etc
0
0
24
@_byroot
Jean Boussier
2 years
Since this comes up often: IMO the rule of thumb for whether or not you should yank a gem release is: don't. Two exceptions: - The gem was pushed by an attacker who took over your account. - Legal reasons (e.g. copyright, etc). 1/4
2
6
24
@_byroot
Jean Boussier
2 years
Since we've been debating the merits of forking servers, I think it's appropriate to start teasing pitchfork 😈
Tweet media one
3
5
22
@_byroot
Jean Boussier
2 years
@mscccc The funny part is that when you make them talk you realize they don't understand anything about the challenge of running such a service.
1
0
23
@_byroot
Jean Boussier
2 years
More details here:
3
0
20
@_byroot
Jean Boussier
2 years
Here we're benchmarking Puma with two processes and 2 threads VS Pitchfork with 4 processes. And pitchfork end up using half the memory.
Tweet media one
1
3
19
@_byroot
Jean Boussier
2 years
As a result, after the initial warm-up period, it is able to share much more memory than traditional pre-forking servers would, as demonstrated on the screenshot.
1
0
19
@_byroot
Jean Boussier
2 years
@nganpham That’s why testing ruby-head is very beneficial. 3.0 to 3.1 took us, 1 engineer, about 2.5 hours (post release). And we got to help ensure a very stable 3.1.0 release by reporting bugs early.
1
0
18
@_byroot
Jean Boussier
2 years
What's funny is that I opened this code assuming String#<< would already be super optimized, given how much Ruby is used for HTML templating and such, but it seems that there are quite a few low hanging fruits left in there.
0
0
18
@_byroot
Jean Boussier
2 years
> There was a problem saving your gem: Name 'rediscluster' is too similar to an existing gem named 'redis-cluster'
4
0
18
@_byroot
Jean Boussier
2 years
Tweet media one
0
0
18
@_byroot
Jean Boussier
2 years
I found a nice name for my next project 😈, and as usual it was taken. But @paydro was kind enough to let me take the name over. Thank you❤️❤️
Tweet media one
1
0
16
@_byroot
Jean Boussier
2 years
“Show me on the doll where did SQL hurt you”
Tweet media one
0
0
16
@_byroot
Jean Boussier
2 years
Adding or changing opcodes is way more involved though, so I'm not gonna try that today. Still got a 1.40x improvement in less than two hours, I think I'm happy with that for now:
2
0
16
@_byroot
Jean Boussier
2 years
Ok, redis-rb 5.0.0 first beta is finally out. I'll likely release another 4.x to help migrate by emitting some more deprecations.
0
1
16
@_byroot
Jean Boussier
2 years
For fun I tried to port the buffered IO implementation @BiHi and I developed for redis-client to net-http. The main perf gain is when reading line by line, in a large buffer, which Redis does a lot, and HTTP a bit less
0
0
15
@_byroot
Jean Boussier
1 year
Note that I had to choose a size, but didn’t have much datapoints. So I settled on 100 by default but I’m open to change it if some people provide some datapoint by instrumenting their app in production
@nateberkopec
Nate Berkopec
1 year
ActiveRecord::QueryCache is no longer of unbounded size! I predict a lot of "my memory usage went way down!" posts after the next Rails release...
2
19
132
0
2
15
@_byroot
Jean Boussier
2 years
@nateberkopec I start Stackprof in `config/boot.rb`, and then run `bin/rails runner 'StackProf.stop; ...'`. If doing this in production env, that should catch all boot.
3
1
15
@_byroot
Jean Boussier
2 years
All this to say that Rails apps using ERB views should hopefully notice a nice perf improvement with Rails 7.1 and Ruby 3.2. I'd love to give an actual figure but thats' heavily dependent on the templates, so your mileage may vary.
1
2
13
@_byroot
Jean Boussier
2 years
I guess next step is to check if we can also apply that optimization when the right hand side is valid UTF-8, not just ASCII.
1
0
13
@_byroot
Jean Boussier
2 years
The key feature of Pitchfork is its reduced memory usage thanks to reforking. When you fork a process, at first all its memory is shared between the parent and the child, that's called Copy-on-Write or CoW for short.
1
0
13
@_byroot
Jean Boussier
2 years
Here’s the sunset
Tweet media one
@tenderlove
Aaron Patterson
2 years
Beautiful sunrise in Matsue!
Tweet media one
3
0
34
0
0
13
@_byroot
Jean Boussier
2 years
So in theory, subprocesses should be pretty much free, but in practice lots of shared memory gets invalidated when you start executing Ruby code. This is due in large part of the Ruby VM inline caches and JITed code.
1
1
13
@_byroot
Jean Boussier
2 years
@nateberkopec @samsaffron @tenderlove @kellabyte Twitter takes 18 times longer to send my timeline data. Does that means Scala doesn't scale?
Tweet media one
0
0
13
@_byroot
Jean Boussier
2 years
Do you use Active Record's `extending` API? I'd like to replace it by another API because it has some nasty performance implications and can cause leaks on current Rubies. But I'm not sure I understand all the use cases for it. Ref:
6
8
12
@_byroot
Jean Boussier
2 years
Went for my first Japanese breakfast. There was ratatouille, pot-au-feu and some kind of choucroute o_0 The local food was surprisingly delicious though.
1
0
12
@_byroot
Jean Boussier
2 years
@peterzhu2118 Sames, this gets rid of my number one gripe with MRI's codebase. It was a constant annoyance with my editor. ❤️❤️ @k0kubun
1
0
12
@_byroot
Jean Boussier
2 years
😂 Just as I'm about to release redis-rb 5.0.0 first beta, I realize that both `redis_cluster` and `redis-cluster` gem already exist... I'll need to find another name for my cluster support extraction...
9
0
12
@_byroot
Jean Boussier
1 year
@bruckmayer There is a special place in hell for people who ship code that use eval without a file indicator.
1
0
12
@_byroot
Jean Boussier
2 years
@nateberkopec Whereas frozen string literals are interned yes, but other non interned strings may be equivalent. So you have to to a full string comparison regardless.
1
0
12
@_byroot
Jean Boussier
10 months
@smlpth Not sure what you mean. You can do the same in Ruby. Anything that implements `hash` and `eql?` can be a Hash key.
3
0
12
@_byroot
Jean Boussier
2 years
@_st0012 @peterzhu2118 @brightonruby Pairing on MRI with @peterzhu2118 is the best. ❤️
1
0
11
@_byroot
Jean Boussier
2 years
@eregontp This gem is the bane of my existence. Any time I try to do anything cool it somehow manage to be in the way.
1
0
10
@_byroot
Jean Boussier
2 years
@getajobmike @kaokun No worries, I dealt with that same issue several time before.
1
0
10
@_byroot
Jean Boussier
2 years
Went to the « park » thinking I’d chill on a bench looking at ducks or something. Turns out it’s a hiking trail, I even had to go over a fallen tree 🥲
Tweet media one
Tweet media two
Tweet media three
Tweet media four
3
0
11
@_byroot
Jean Boussier
2 years
@palkan_tula Meh, Eileen's post was about monkey patches to change a dependency behavior or API. Here's it's adding a method that didn't exist before. Could have happened just the same in ruby-core. And as mentioned on the issue, I think the RSpec code is far from perfect here.
2
0
10
@_byroot
Jean Boussier
2 years
@getajobmike That would require to mutate the Integer, which isn't possible since they are immediate. You'd need a wrapper object like concurrent-ruby's AtomicFixnum. Would definitely be nice to have something like that in the stdlib though.
1
0
10
@_byroot
Jean Boussier
1 year
@nateberkopec Depends how it’s configured. If you use it purely in memory you save having to write to disk, which for write heavy workloads does make a difference. Latency of SSDs improved tremendously, but are still 3-4 orders of magnitude slower.
1
0
10
@_byroot
Jean Boussier
1 year
I'm getting real tired of this guy. He keeps commenting an opening issues all across GitHub and reporting it for spam to GitHub doesn't stop it. @github don't you have a spam filter on public repos?
Tweet media one
2
0
9
@_byroot
Jean Boussier
1 year
@paracycle @fxn I actually didn't scale it down, so we're still running ruby-head builds every 4 hours 😅
0
0
10
@_byroot
Jean Boussier
11 months
@smlpth This isn't about dynamic vs static typing, but about strong vs weak typing. C (statically typed): 1 + '5' == 54
2
0
10
@_byroot
Jean Boussier
2 years
@keithpitt please give all my thanks and praise to whoever is the genius that shipped this new UI feature. This saves me an incredible number of clicks when digging into CI failures.
Tweet media one
1
0
10
@_byroot
Jean Boussier
2 years
@nateberkopec Maybe PR it to ?
0
0
8
@_byroot
Jean Boussier
2 years
@katafrakt_pl 🙄 that’s not what @rafaelfranca said. YOU are entitled to have an opinion. WE have no obligation to suffer it nor to convince you.
1
0
8
@_byroot
Jean Boussier
2 years
@nateberkopec > The costs are high memory use Hold my beer 😉
0
0
8
@_byroot
Jean Boussier
2 years
@fxn A big difference to me is that constants are namespaced. Whereas with global variable if they were as popular you’d mite easily run into conflicts.
2
0
9
@_byroot
Jean Boussier
11 months
@jnunemaker For all the complaints about net/http, I think this one is it's only really major flaw.
2
0
9
@_byroot
Jean Boussier
8 months
@fxn Got some 1989 Batman vibes.
0
0
9
@_byroot
Jean Boussier
2 years
@fxn @fatkodima Yeah, we've been using a similar strategy for uniqueness validation We should definitely try to upstream that. The annoying par it that it's hard to make 100% reliable because you have to parse error messages which may change easily or be localized...
1
0
9
@_byroot
Jean Boussier
2 years
@bruckmayer That being said, that `gsub` is unnecessary, `sub` would do /o\
3
0
9