【问题标题】:AWS S3 AmazonServiceException A WebException with status SecureChannelFailureAWS S3 AmazonServiceException 状态为 SecureChannelFailure 的 WebException
【发布时间】:2017-06-16 10:20:38
【问题描述】:

拥有接收请求、生成数据并将其以文件形式保存到 AWS S3 的服务。 如果服务收到许多请求,则可以尝试并行保存多达 20 个文件(2 个服务器 x 10 个工作人员)。 请求生成并保存到 S3 的数据可以从几 KB 到大约 400MB

问题是有时(似乎是当服务很忙/要保存大文件时)S3 失败,但以下异常: 我们讨论了 2 个解决方案:

1) 如果保存失败,则重试 S3.UploadAsync()。 不确定是否会有所作为。假设 S3 已经在内部重试,所以可能没有必要重试。如果问题是文件太大/保存时间过长,这将无法解决问题,可能会使问题变得更糟。

2) 将 TransferUtilityConfig.DefaultTimeout 增加到 10 分钟(默认为 5 分钟)。 如果问题是保存时间超过 5 分钟,这将解决问题,但 S3 抛出的异常并不表示是超时异常,所以也许这可以解决任何问题。

3) 这是 AWS 基础设施中的间歇性问题吗?重试可以帮忙吗?

发生此异常时,是否有人有经验/解决方案?还有其他想法吗?

更新: 如果使用 NET 4.5,则 TransferUtilityConfig() 不包含 DefaultTimeout。该功能已移至 AmazonS3Config。这提供了更多参数来控制上传:Timeout、ReadWriteTimeout、MaxErrorRetry AmazonS3Config Class 设置在这里解释 AWS Retries and Timeouts

这是服务用来保存的代码:

using (var amazonS3Client = new AmazonS3Client(RegionEndpoint.GetBySystemName(_iAwsS3Settings.RegionEndpoint)))
using (var fileTransferUtility = new TransferUtility(amazonS3Client))
using (var memoryStream = new MemoryStream(data))
{
    var fileTransferUtilityRequest = new TransferUtilityUploadRequest
    {
        BucketName = _iAwsS3Settings.BucketName,
        InputStream = memoryStream,
        StorageClass = S3StorageClass.ReducedRedundancy,
        PartSize = 6291456, // 6 MB.
        Key = fileLocation,
        CannedACL = S3CannedACL.BucketOwnerFullControl
    };

    await fileTransferUtility.UploadAsync(fileTransferUtilityRequest, ct);
}

这是 S3 保存失败时给出的异常:

System.AggregateException:发生一个或多个错误。 ---> Amazon.Runtime.AmazonServiceException:带有状态的 WebException SecureChannelFailure 被抛出。 ---> System.Net.WebException: 请求被中止:无法创建 SSL/TLS 安全通道。在 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult、TransportContext& 上下文)在 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult) 在 System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization) --- 上一个堆栈跟踪的结束 抛出异常的位置---在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Amazon.Runtime.Internal.HttpHandler1.&lt;InvokeAsync&gt;d__91.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Amazon.Runtime.Internal.HttpHandler1.&lt;InvokeAsync&gt;d__91.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Amazon.Runtime.Internal.RedirectHandler.d__11.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.Unmarshaller.<InvokeAsync>d__31.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Amazon.S3.Internal.AmazonS3ResponseHandler.d__11.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.ErrorHandler.<InvokeAsync>d__51.MoveNext() --- 内部异常堆栈跟踪结束 --- 在 Amazon.Runtime.Internal.WebExceptionHandler.HandleException(IExecutionContext executionContext,WebException 异常)在 Amazon.Runtime.Internal.ErrorHandler.ProcessException(IExecutionContext executionContext,异常异常)在 Amazon.Runtime.Internal.ErrorHandler.d__51.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.CallbackHandler.<InvokeAsync>d__91.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Amazon.Runtime.Internal.CredentialsRetriever.d__71.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.RetryHandler.<InvokeAsync>d__101.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Amazon.Runtime.Internal.RetryHandler.d__10`1.MoveNext()

【问题讨论】:

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


    【解决方案1】:

    S3 SDK 已经实现retry logic

    默认情况下,上传是retried 4 times

    创建了一个控制台应用程序来尝试重现错误。控制台应用程序尝试异步上传 10-30 个文件。更改 AmazonS3Config 中 Timeout、ReadWriteTimeout、MaxErrorRetry 的值会产生异常(System.Net.WebException:操作已超时),但与我们的不同(无法创建 SSL/TLS 安全通道)。

    我们假设问题可能是服务太忙而无法创建连接,这就是为什么得到“无法创建 SSL/TLS 安全通道”

    【讨论】:

      【解决方案2】:

      这是一个老问题,但我刚刚遇到了一个非常相似的问题,因为我无法在 Google 上找到合适的答案,所以我想贡献我的解决方案。

      我已经开始实施具有以下行的旧 API:

      ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
      

      我能够通过将 SecurityProtocolType.Ssl3 更改为 SecurityProtocolType.Tls12 来解决此问题


      进一步说明:

      由于 Poodle 漏洞,一般不支持 SSL3:

      https://security.stackexchange.com/questions/70719/ssl3-poodle-vulnerability/70724#70724

      我自己没有添加这行代码,因此我很难找到问题的根源。然而,在研究过程中,我发现了这篇关于类似问题的帖子:https://github.com/aws/aws-sdk-net/issues/86

      在此讨论的底部附近,有人建议添加以下行:

      ServicePointManager.CheckCertificateRevocationList = true;
      

      此修复无法纠正我的问题,但它确实引导我走上正确的道路。在搜索了对 ServicePointManager 的其他引用后,我能够找到前面提到的有关 SecurityProtocolType 的行并进行更正。

      【讨论】:

        【解决方案3】:

        我的例外是:

        A WebException with status ConnectFailure was thrown
        

        对我来说,ServiceUrl 是 http 而不是 https,也不需要端口号。端口号被防火墙阻止。

        之前:

        http://s3ws.MyDomain.com:80
        

        之后:

        https://s3ws.MyDomain.com
        
        var s3Config = new AmazonS3Config
        {
            RegionEndpoint = Amazon.RegionEndpoint.EUNorth1,
            ServiceURL = "https://s3ws.MyDomain.com",
            ForcePathStyle = true
        };
        return new AmazonS3Client(accessKey, secretKey, s3Config);
        

        【讨论】:

          猜你喜欢
          • 2021-02-09
          • 2017-10-19
          • 2018-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-06
          相关资源
          最近更新 更多