【问题标题】:Why does S3 retrieve speed increase after subsequent calls using StreamReader?为什么 S3 在使用 StreamReader 进行后续调用后检索速度会提高?
【发布时间】:2021-12-01 13:07:38
【问题描述】:

我正在使用 Visual Studio 通过 SDK 访问 AWS S3。

我试图弄清楚为什么在几次连续调用后 GetObjectSync 对象检索时间显着减少。

例如 - 我正在从 ap-southeast-2 的 eu-west-2 访问我的数据,并启用了传输加速。如果我连续打几个电话,(3 或 4 个电话,在 3-5 秒内)。我记录的 GetObjectAsync 时间如下所示:

1.91s
1.82s
1.93s
.3s
.29s
.32s

在这些最初的 3-4 次调用之后会发生什么,然后启用超快速访问,无论如何我可以让后者调用现状吗?

在这种情况下,我从很远的地方获取数据,但如果我访问位于同一大陆 (AU) 上的本地计算机,也会发生同样的事情。

我的 GetObjectAsync 调用响应时间可能如下所示:

.29s
.32s
.27s
.03s
.04s
.05s

所以它似乎是相同的症状,只是明显地由于地理原因而减少了延迟。如果然后我再次停止拨打电话几分钟,它会“重置”并再次从高延迟开始。

我对延迟非常敏感,因此需要它始终在低端执行。我在这里也遇到的问题是,用户可能只会间歇性地对我的服务进行 1 次调用,因此在这种情况下,他们永远不会享受到减少延迟的好处。

我通过以下代码获取我的 S3 文件:

using (var response = await _s3.GetObjectAsync(request))
{
    sw.Stop();
    Console.WriteLine($"S3 GetObjectAsync: {sw.Elapsed}");
    sw.Reset();
    sw.Start();
    using (var responseStream = response.ResponseStream)
    {
        sw.Stop();
        Console.WriteLine($"S3 ResponseStream: {sw.Elapsed}");
        sw.Reset();
        sw.Start();
        using (var reader = new StreamReader(responseStream))
        {
            result = reader.ReadToEnd();
            sw.Stop();
            Console.WriteLine($"S3 ReadToEnd: {sw.Elapsed}");
        }
    }
}

【问题讨论】:

  • 你所有的流操作都是阻塞的,你应该使用它的xxxasync 版本。我的猜测是你的线程池已经耗尽,新线程被注入,然后恢复它。

标签: c# amazon-web-services amazon-s3 aws-sdk


【解决方案1】:

您使用的是_s3.GetObjectAsync(...),它比_s3.GetObject 要好得多,因为它是异步的,但是您使用的是reader.ReadToEnd();,它是同步的,并且阻塞

它加速的原因与 AWS 无关,正如您通过从不同位置运行代码所证明的那样,而且 Amazon S3 Transfer Acceleration 的工作原理本质上是通过在边缘位置“缓存”您的数据来工作的。

我假设您的应用程序正在加速,因为 .NET CLR 缓存了某种形式的 StreamReader 对象,但这只能通过查看您在代码中提到的特定时序输出来证明。

无论如何,我都会坚持使用同步或异步,最好是后者,以便使用StreamReader.ReadToEndAsync 从流中读取。

这应该会产生一致的结果:

using (var response = await _s3.GetObjectAsync(request))
{
    sw.Stop();
    Console.WriteLine($"S3 GetObjectAsync: {sw.Elapsed}");
    sw.Reset();
    sw.Start();
    using (var responseStream = response.ResponseStream)
    {
        sw.Stop();
        Console.WriteLine($"S3 ResponseStream: {sw.Elapsed}");
        sw.Reset();
        sw.Start();
        using (var reader = new StreamReader(responseStream))
        {
            result = await reader.ReadToEndAsync();
            sw.Stop();
            Console.WriteLine($"S3 ReadToEnd: {sw.Elapsed}");
        }
    }
}

另外,如果您正在阅读以最终写入文件,请注意GetObjectResponse.WriteResponseStreamToFileAsync,它将为您封装此逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2019-07-22
    • 2011-12-05
    相关资源
    最近更新 更多