【问题标题】:Upload an image file takes too long on AWS S3 c++ SDK在 AWS S3 c++ SDK 上上传图像文件花费的时间太长
【发布时间】:2019-07-11 12:53:54
【问题描述】:

使用 AWS S3 C++ SDK 将 .jpg 图像上传到某个 IAM 用户会引入巨大的时间延迟,无论如何这都是由于网络流量和延迟问题造成的。我正在为我的应用程序使用免费层 S3 版本和 MSVC 2017 64 位(在 Windows 10 PC 上)。这是一个示例代码:

Aws::SDKOptions options;
Aws::InitAPI(options);

Aws::Client::ClientConfiguration config;
config.region = Aws::Region::US_EAST_2;

Aws::S3::S3Client s3_client(Aws::Auth::AWSCredentials(KEY,ACCESS_KEY), config);

const Aws::String bucket_name = BUCKET;
const Aws::String object_name = "image.jpg";

Aws::S3::Model::PutObjectRequest put_object_request;

put_object_request.SetBucket(bucket_name);
put_object_request.SetKey(object_name);

std::shared_ptr<Aws::IOStream> input_data =
        Aws::MakeShared<Aws::FStream>("PutObjectInputStream",
                                      "../image.jpg",
                                      std::ios_base::in | std::ios::binary);

put_object_request.SetBody(input_data);
put_object_request.SetContentType("image/jpeg");

input_data->seekg(0LL, input_data->end);
put_object_request.SetContentLength(static_cast<long>(input_data->tellg()));

auto put_object_outcome = s3_client.PutObject(put_object_request);

当我上传的图片总大小超过 100KB 时

PutObject(put_object_request);

520KB 图像的执行时间超过 2 分钟。

我使用 Python boto3 尝试了相同的示例,并且相同图像的总上传时间约为 25 秒。

有人遇到过同样的问题吗?

【问题讨论】:

  • 我认为有一些SDK方法可以打破图像并同时上传所有部分
  • 有 UploadPartAsync (我认为它指的是大于 5MB 的对象)。尽管如此,这样一个小文件的总时间以及 Python 和 C++ 实现之间的时间差异对我来说毫无意义。
  • 我不认为跨语言比较是个好主意。
  • 试着写一个程序来计算1000个素数。 python 和 CPP 程序所花费的时间可能会完全不同。有些语言只是比其他语言慢。这是一个简单的事实。
  • 分段上传对象 API 为 available,仅适用于 Java、PHP、.NET。这些函数似乎在 C++ API 上可用,但没有这样使用的例子。

标签: c++ amazon-web-services amazon-s3


【解决方案1】:

在更好地查看 AWS github repo 后,我发现了问题。

问题在于 WinHttpSyncHttpClient 正在内部进行超时和重置上传活动,因此没有退出上传线程并最终中止事务。通过添加自定义超时值,问题解决了。

我使用 multipart Upload 来重新实现示例,因为它看起来更健壮且易于管理。虽然我认为它不适用于 C++ SDK,但情况并非如此,因为 TransferManager 对 C++ 执行相同的工作(而不是像 Java、.NET 和 PHP 那样使用 S3 标头)。

感谢来自 AWS github 存储库的 KaibaLopezSCalwas,他们帮助我解决了这些问题(issue1issue2)。我正在粘贴示例代码以防万一有人遇到同样的问题:

#include "pch.h"
#include <iostream>
#include <fstream>
#include <filesystem>

#include <aws/core/Aws.h>
#include <aws/core/auth/AWSCredentials.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/Bucket.h>
#include <aws/transfer/TransferManager.h>
#include <aws/transfer/TransferHandle.h>

static const char* KEY = "KEY";
static const char* BUCKET = "BUCKET_NAME";
static const char* ACCESS_KEY = "AKEY";
static const char* OBJ_NAME = "img.jpg";
static const char* const ALLOCATION_TAG = "S3_SINGLE_OBJ_TEST";

int main()
{
    Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        Aws::Client::ClientConfiguration config;
        config.region = Aws::Region::US_EAST_2;
        config.requestTimeoutMs = 20000;

        auto s3_client = std::make_shared<Aws::S3::S3Client>(Aws::Auth::AWSCredentials(KEY, ACCESS_KEY), config);

        const Aws::String bucket_name = BUCKET;
        const Aws::String object_name = OBJ_NAME;
        const Aws::String key_name = OBJ_NAME;

        auto s3_client_executor = Aws::MakeShared<Aws::Utils::Threading::DefaultExecutor>(ALLOCATION_TAG);
        Aws::Transfer::TransferManagerConfiguration trConfig(s3_client_executor.get());
        trConfig.s3Client = s3_client;


        trConfig.uploadProgressCallback =
            [](const Aws::Transfer::TransferManager*, const std::shared_ptr<const Aws::Transfer::TransferHandle>&transferHandle)
        { std::cout << "Upload Progress: " << transferHandle->GetBytesTransferred() <<
            " of " << transferHandle->GetBytesTotalSize() << " bytes" << std::endl;};

        std::cout << "File start upload" << std::endl;

        auto tranfer_manager = Aws::Transfer::TransferManager::Create(trConfig);
        auto transferHandle = tranfer_manager->UploadFile(object_name.c_str(),
            bucket_name.c_str(), key_name.c_str(), "multipart/form-data", Aws::Map<Aws::String, Aws::String>());

        transferHandle->WaitUntilFinished();

        if(transferHandle->GetStatus() == Aws::Transfer::TransferStatus::COMPLETED)
            std::cout << "File up" << std::endl;
        else
            std::cout << "Error uploading: " << transferHandle->GetLastError() << std::endl;
    }
    Aws::ShutdownAPI(options);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2019-10-23
    • 2020-05-02
    • 1970-01-01
    相关资源
    最近更新 更多