-
-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Investigating performance hit around building action URLs #1827
Comments
I noticed the Here's a basic action with the require "lucky"
Lucky::RouteHelper.configure do |settings|
settings.base_uri = "http://localhost:3000"
end
class Products::Show < Lucky::Action
get "/products/:id" do
plain_text "testing"
end
def self.route(id, anchor : String? = nil) : Lucky::RouteHelper
path = path_from_parts(id)
query_params = {} of String => String
unless query_params.empty?
path += "?#{HTTP::Params.encode(query_params)}"
end
anchor.try do |value|
path += "##{URI.encode_www_form(value)}"
end
Lucky::RouteHelper.new :get, path
end
end
Products::Show.with(1).url |
I think we want to switch from |
Link to where I'm talking about: Lines 350 to 365 in 3f15bc8
Also, after looking at it again, we don't build the full url in that function so ignore the part about adding it to the base url. Switching to the new method and calling it at the end should just work. I did see differences in the docs around what it does with spaces. It seems like we want the default of |
I actually thought about that too, but when I tried comparing the two, the main difference is Now, I'm sure no matter what we do, it'll never be as fast as doing a raw string, and that's ok. I'm just hoping we can find some spot that gets us a bit closer than the 30% reduction we have now (according to those findings). |
looks like |
Try using the |
Hi, sorry for my delay, I forgot to check out this issue. Just to report on what happened. I was analysing code from a challenge from our local dev community and I participated using Crystal/Lucky. It performs super well, as expected. But there was a small problem. It is this line of code:
If I use #url the performance goes down dramatically in the stress test. For the context, this is the Gatling simulation we have been using: https://github.com/zanfranceschi/rinha-de-backend-2023-q3/tree/main/stress-test (you have to download gatling and change run-test.sh to adjust the paths) If I use simple string concatenation such as "/pessoas/#{pessoa.id}", I can easily reach the 46k inserts at the end of the simulation. If I use the #url method it can go down in half of that total. The simulation ramps up from 3 to 600 sessions doing POSTs to create and then GET the Location from the header to check. One semantic mistake I made is that the Location header don't need the #url, just the #path is sufficient. And in that case, I don't see a performance hit. What made this even more curious is that I was previously trying this:
And for some weird reason, this one line also drops the number of inserts in the end. I tried to make a benchmark to isolate #url, #path, string concatenation, here: https://github.com/akitaonrails/rinhabackend-lucky-crystal-api/blob/master/spec/actions/benchmark_bug_spec.cr And although, of course, #url is a bit slower because it does more. I don't see why that difference would drop performance so much in the end. I am still not sure if this is a bug or if there's something wrong in the test scenario. I hope those details help a bit. |
@akitaonrails it would be interesting to see if my PR #1829 makes a difference in this at all. |
@jwoertink will do, but a noob question. In my shard.yml if I change version: ~> 0.1.0 to branch: issues/1827 to get that branch, then dependency resolution breaks for lucky_task. how can I fetch from your branch without breaking shards? |
You can add a new file |
I'm sorry, I know I'm doing something very stupid but I created a shard.override.yml with: dependencies:
lucky:
path: ../../crystal/lucky also tried dependencies:
lucky:
github: luckyframework/lucky
branch: issues/1827 I run shards update but I always end up with:
it only passes this if I do:
but then it fails with:
|
cc @jwoertink Ok, I decided to change my docker-compose to COPY your routable.cr directly over lib/lucky/src/lucky after shards install.
Then, I made sure I created the Location header like this:
This is semantically incorrect; it should be #path() instead, but this was causing problems in the stress test. Since my initial report, I did some other tweaks, but still, this is the Gatling results after the 3 minutes of stress. This is the baseline:
The last item, "consulta" are "GET" requests for the Location URL. It misses quite a few. 637 knockouts. Now, WITH your patch 1827 I have this result:
It DID make a measurable difference. It's not constant. I tested a couple of times and another time, it was 7 KOs, but the order of magnitude is staggering, from 600 down to 10, so it makes a huge difference under stress. As I said, using the correct In any case, your patch seems to make a positive impact and I didn´t see any regressions in the scope of my test. Thanks! |
Sweet! Thanks for testing that @akitaonrails. Sorry I missed your first response, but I'm glad you were able to test it. I think we're in a good spot to get a new release up, so I'll start working towards that. |
Ref: https://twitter.com/AkitaOnRails/status/1697651647273427429?s=20
TL:DR; It seems that just using
SomeAction.url
causes a pretty significant hit to performance when doing a stress test.Here's a snippet of code from a source repo where this was tested.
https://github.com/akitaonrails/rinhabackend-lucky-crystal-api/blob/000a86d0e1d9bdee245c7873f2f0440ed44c7cf8/src/actions/api/pessoas/create.cr#L19-L20
There's a lot of significant moving parts in this area, so it's possible the root cause could be located in some other shard, but we will use this issue to drop any notes or discoveries.
/cc. @akitaonrails
The text was updated successfully, but these errors were encountered: