GCS 从 kubernetes GKE 中的 pod 缓慢上传

GCS slow upload from pod inside kubernetes GKE

从 GKE 中的 pod 上传到 GCE 需要很长时间。我希望升级到 kubernetes 1.1 会有所帮助,但没有。它更快,但没有达到应有的速度。我做了一些基准测试,上传了一个 100MiB 的文件:

正如您所见,kubernetes 1.1.2 的吞吐量翻了一番,但速度仍然很慢。如果我想上传 1GB,我必须等待大约 5 个小时,这不是预期的行为。 GKE 在 Google 基础架构内运行,因此我希望它应该更快或至少与从本地上传一样快。

我还注意到上传时 CPU 负载非常高 (70%)。它使用 n1-highmem-4 机器类型和一个 RC/pod 进行了测试,后者在上传时什么都不做。

我正在使用 java 客户端和 GAV 坐标 com.google.appengine.tools:appengine-gcs-client:0.5

相关代码如下:

InputStream inputStream = ...; // 100MB RandomData from RAM
StorageObject so = new StorageObject().setContentType("text/plain").setName(objectName);
AbstractInputStreamContent content = new InputStreamContent("text/plain", inputStream);
Stopwatch watch = Stopwatch.createStarted();
storage.objects().insert(bucket.getName(), so, content).execute();
watch.stop();

使用 gsutil cp 手动安装的 gcloud 复制一个 100MB 的文件几乎没有花费任何时间(3 秒)。所以这可能是 java-library 的问题?问题仍然存在,如何使用 java-library 缩短上传时间?

您看到高 CPU 负载并且缓慢仅影响 Java 而不是 Python gsutil 这一事实与 slow AES GCM issue in Java 8. The issue is fixed in Java 9 using appropriate specialized CPU instructions.

如果您可以控制它,那么使用 Java 7 或将 jdk.tls.disabledAlgorithms=SSLv3,GCM 添加到传递给 java -Djava.security.properties 的文件应该可以解决速度慢的问题,如 this answer 中所述一般慢速 AES GCM 问题。

解决办法是启用"DirectUpload",所以不用写

storage.objects().insert(bucket.getName(), so, content).execute();

你必须写:

    Storage.Objects.Insert insert = storage.objects().insert(bucket.getName(), so, content);
    insert.getMediaHttpUploader().setDirectUploadEnabled(true);
    insert.execute();

我使用此解决方案获得的性能:

  • 花了 {13s515ms},大约是 ~{7.6923076923076925}MB/s

JavaDoc setDirectUploadEnabled:

Sets whether direct media upload is enabled or disabled.

If value is set to true then a direct upload will be done where the whole media content is uploaded in a single request. If value is set to false then the upload uses the resumable media upload protocol to upload in data chunks.

Direct upload is recommended if the content size falls below a certain minimum limit. This is because there's minimum block write size for some Google APIs, so if the resumable request fails in the space of that first block, the client will have to restart from the beginning anyway.

Defaults to false.