-
Notifications
You must be signed in to change notification settings - Fork 879
docker client times out pulling large fs layer from S3-backed registry #956
Comments
Ok, that sounds bad enough. Given the effort is now on https://github.com/docker/distribution (new golang implementation), little effort is going to be put in the python-registry here. My suggestion is either remove the parallel key code entirely, or better, make it configurable (and disable it by default). If you are willing to PR this, that would be awesome... |
Thanks for the quick response, Olivier! I also noticed issues with tmp files not being cleaned up, and saw that others had already reported similar problems (like issue #954). It seems like the best thing to do at this point is to simplify the code by removing the ParallelKey class, rather than tracking down the corner cases that lead to orphaned tmpfiles. I'll take care of removing the code and submit a pull request. |
Here's a draft of the code, which passes flake8 and seems to work on my test instance: I'll do a bit more testing, and then submit the pull request. |
Fantastic. |
I'm moving my performance test results into this document... https://docs.google.com/spreadsheets/d/1VbdtRL8w8eAf0sKse1qk7vLmd-J10tIiyeUqCTjSfL4/edit?usp=sharing tl;dr: The pull request fixes the problem and doesn't change performance otherwise. As expected, STORAGE_REDIRECT provides better bandwidth and therefore better latency for multiple simultaneous clients. For access by a single client, performance mostly depends on the networking between the client and the registry, rather than the code running on the registry. |
Thanks a lot for your work on this! |
At Altiscale, we have been running a standalone docker registry backed by S3. The registry works fine with STORAGE_REDIRECT=true. We're tightening up registry security and bandwidth usage by setting STORAGE_REDIRECT=false, but our docker clients now time out when fetching large fs layers.
Here's the scenario:
depends/docker-registry-core/docker_registry/core/boto.py:Base.stream_read
decides to fetch the layer using the ParallelKey class.depends/docker-registry-core/docker_registry/core/boto.py:ParallelKey.__init__
opens a temporary file:depends/docker-registry-core/docker_registry/core/boto.py:ParallelKey._fetch_part
starts transferring 1/5 of the object at the corresponding offset in the temporary file:boto_key.get_contents_to_file
and callsParallelKey._refresh_max_completed_byte
, which emits the messagebuffering complete at 20.0% of the total transfer; now serving straight from the tempfile
. At this point, the client has already timed out on its original request, so the initial fetch of the S3 object into the temporary file was not useful work.I have confirmed this same behavior using curl directly on the docker registry host. This curl command demonstrates the same behavior, except that curl doesn't time out so that the initial download eventually works. When running the curl command, curl does not download the first byte of the file until the first of the 5 docker registry threads calls
ParallelKey._refresh_max_completed_byte
. Once the first thread completes, curl starts downloading the layer.This curl command uses the Range header to disable ParallelKey. This header makes the
if not bytes_range
conditional in the code above false, so that ParallelKey does not run. In this case, curl starts downloading bytes immediately.Here are some potential solutions for the problem that I would be happy to contribute as code:
boto.py:ParallelKey._fetch_part
so that it limits the size of any individual transfer, and therefore callsParallelKey._refresh_max_completed_byte
faster. This change would be pretty easy, but each thread would still work on its own segment of the file. The result is that the streaming transfer of the client would be rate limited by single thread transfer performance.boto.py:ParallelKey
so that each thread picks up a new range of bytes to transfer as close to the beginning of the object as possible, but not overlapping with the ranges being transferred by other threads. This change would be more substantial (and harder to get right), but the all of the threads would contribute to the rate that the client would be able to transfer.ParallelKey
entirely, or if an S3 object is over a configured size.ParallelKey
code fromboto.py
.ParallelKey
by passing the Range HTTP header to the docker registry. This approach would work with the current docker registry code, but seems like it's too much of a hack because it depends on the internal implementation ofboto.py:Base.stream_read
.Any thoughts on the best way to proceed?
...or maybe I missed some obvious way to fix this issue? Please let me know if there is some obvious way to get a standalone registry working with STORAGE_REDIRECT=false and large fs layers stored as S3 objects!
The text was updated successfully, but these errors were encountered: