-
Notifications
You must be signed in to change notification settings - Fork 554
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
Google::Cloud::Storage is about twice slower than gsutil cp for downloading files #1897
Comments
Are you disabling the verification check when downloading? You pass |
I'll try this, thanks! |
Ugh, the app I use for GitHub notifications didn’t show the benchmark code in the issue description. Now that I’m reading this in a browser I see that you were not disabling the verify check. It is possible that this verification stuff is the cause for the difference. Calculating MD5 on a 500 MB file will take some time, but we think we are doing this as efficiently as possible. |
I ran the benchmark twice with
So I'm afraid disabling the check only improve things marginally :/ |
K, I'll look into this. FWIW, google-cloud-storage uses google-api-client to access the API, which uses httpclient for the HTTP calls. So it will take a bit to dive through all the dependencies to see where we can pick up performance. |
@casperisfine Oh! One more thing! Your benchmark includes creating the File object, which also makes an API call. Can you update it to something like the following? puts bucket.file(file_name, skip_lookup: true).download("/tmp/random-500M.bin.#{rand}", verify: :none) |
Good point, but still no sensible change (~
Yeah my hunch says the performance difference is more likely to be at that layer. Either some non-optimal buffering, or different compression, etc What is interesting too is that it impacts only the download performance, the upload performance is fine. I'll do some more benchmark to see if the perf diff is linear, let me know if there is anything else I can do to help you figure this out. Also maybe |
I did 3 more runs, this time with 100M, 500M and 1G (speadsheet) There is a lot of variance obviously, but is does appear to be a fairly linear progression: |
Hi @casperisfine, what is this line for? bucket = Buildkite::FSCache.send(:bucket) Can you share your entire configuration somewhere so that I can run this script in my own GKE deployment? I'm just trying to reproduce your results first, then I'll try to debug. |
[context: I work with @casperisfine] You can ignore that line I think @quartzmo , it looks like some leftover cruft as a result of extracting this code from the project we're using it in. The result is the same as the code immediately above, it returns a |
@DazWorrall, OK, sounds like maybe it isn't easy to share your deployment configuration. @casperisfine I know my home workstation isn't your deployment target, but here's what I get locally: --- Upload with gsutil
- [1 files][500.0 MiB/500.0 MiB] 8.7 MiB/s
Operation completed over 1 objects/500.0 MiB.
took: 65.2s
--- Download with gsutil
Copying gs://downloadtest_978004358714/test/random-500M.bin.0.5400586331450901...
\ [1 files][500.0 MiB/500.0 MiB] 6.7 MiB/s
Operation completed over 1 objects/500.0 MiB.
took: 75.3s
--- Upload with GCS-ruby
#<Google::Cloud::Storage::File:0x00007fd63a70d588>
took: 57.4s
--- Download with GCS-ruby
#<File:0x00007fd63a5c7368>
took: 61.9s |
[context: I am @casperisfine alias]
It's entirely my bad. I used this in my initial benchmark, but that method simply contain what I copy pasted above: bucket = Google::Cloud::Storage.new(
project: '<my-test-project>',
keyfile: ENV['GOOGLE_APPLICATION_CREDENTIALS'],
timeout: 5,
retries: 0,
).bucket('<my-test-bucket>', skip_lookup: true)
If it can help, I'm benchmarking from a GKE cluster. |
I'm still looking into this. |
I've tried to reproduce this on several different systems, with several different network connections, and for the vast majority i've found google-cloud-storage to be faster than the gcloud CLI. The fastest connection has been (not surprising) using a Google Compute Engine virtual machine, the same platform the GKE runs on. After installing the gcloud CLI, ruby, the google-cloud-storage gem, and run several attempts I've collected the following measurements. (The full output log and modified benchmark script can be found here: https://gist.github.com/blowmage/b9e89cd710fcc73117cbc8a2c3ac2cce) 10MB File
100MB File
250MB File
500MB File
750MB File
1GB File
I have not found an appreciable difference between these two libraries, and I am unaware of any low hanging fruit in how HTTPClient is used. Is there more information you can share to help us continue looking into this, or can this response close this issue? |
Could the bucket configuration have an impact here? If so I'm benchmarking with the I can't think of any other information that could help pinpoint the issue. So if you think it's not it I'll close and look for issues elsewhere in the stack. |
I don’t know if bucket configuration would affect this, or why it would affect the gem only and not the cli. But I’m also not a Google employee and have no insight into the Storage service beyond the public documentation. Is there a support channel you can ask that question to? |
Well, thanks for all the time you spent on this. I'll indeed try to go through support with this. |
I’m sorry we couldn’t repro the download speed you are seeing. If you discover the cause we would love to know so we can change the Ruby client to avoid it if possible. |
No need to be sorry, that's actually helpful. And I'll make sure to report any further findings here even if there is no modifications to do to the library. |
Sounds good. Best of luck! |
I received an update from Google support, they were able to reproduce the issue:
🤞 |
Thanks for the update! |
Another update:
The CPU part is interesting. Maybe the API used for HTTP end up using |
So I reran the download benchmark with a (very dirty) patch to For 500M, the bench went down from The shitty patch: https://gist.github.com/casperisfine/f7830c20718813a570927f07d6357bfe There's an open issue in @quartzmo / @blowmage I'd be willing to put time into this if there is interest, but I'd need to know to what lengths a patch could go. Is there a specific reason for using I see |
The Around the same time that All authentication for the google-cloud-* gems use the Okay, history over. I would not expect
There are other options, such as maintaining the "shitty patch" somewhere in our code, but they don't seem to be as realistic or viable as the three above. @geigerj, can you offer any guidance on how to proceed? The tl;dr is downloads are CPU-intensive for very large files compared to other implementations. |
Thanks for the history :), much appreciated. I didn't try very hard to make that patch maintainable. We could certainly do much better. Another possibility would be to expose a specific API for this in |
Yes, I listed that in my first option. I think adding a new API is a better solution that breaking backwards compatibility, most of the time. But I also think your solution of yielding block arguments of |
Yeah my bad. It was late -_-. I'll try to see what's possible in term of API, and submit a PR to |
I submitted a PR to httpclient: nahi/httpclient#383 |
Hi, I ran the following benchmark from a GKE container:
In short, upload an then download a random 500MB file, with the following results:
7.1s
6.1s
4.8s
13.9s
There obviously a bit of variance between the runs, but
G::C::S#download
is constantly twice slower than the rest.Also note that
gsutil
doesn't usecrcmod
here (it's printing warnings about it).I tired looking at
gsutil
's source to see what it's doing differently, but it's a bit like looking for a needle in a haystack.Any ideas?
cc @DazWorrall @wvanbergen
The text was updated successfully, but these errors were encountered: