【问题标题】:AmazonS3Client Single connection Vs new connection for each call C#AmazonS3Client 单个连接与每次调用的新连接 C#
【发布时间】:2021-01-29 18:24:58
【问题描述】:

我正在使用 AmazonS3Client 将数据读/写到 S3 对象存储。在我的代码中,每次执行读取、列出存储桶、上传、重命名、删除等操作时,我都会创建一个新连接。将我的应用程序部署到生产环境后,我遇到了一些性能问题。在浏览了几个博客之后,建议使用单个 amazonS3 客户端连接。我的代码如下-> 对于下面的每个 CRUD 操作,如果您看到我正在创建一个新连接,然后使用块处理它。我计划进行单一连接并使用它而不在每次呼叫时使用块。保持单一连接是个好选择吗?我有大约 400 个用户同时访问应用程序。

public ObjectFileInfo(string path)
{
    StorageClient = ObjectFileManager.GetClient();
    objectFileInfo = ObjectFileManager.getFileInfo(StorageClient, path);
}

public class ObjectFileManager
{
    public static Amazon.S3.AmazonS3Client GetClient()
    {
    AmazonS3Config Config = new AmazonS3Config();
    AmazonS3Client StorageClient;

    Config.RegionEndpoint = null;
    Config.ServiceURL = ConfigurationManager.NGDMSobjECSEndPoint;
    Config.AllowAutoRedirect = true;
    Config.ForcePathStyle = true;
    Config.Timeout = TimeSpan.FromMinutes(30);
            
    StorageClient = new AmazonS3Client(ConfigurationManager.NGDMSobjECSUser, ConfigurationManager.NGDMSobjECSKey, Config);
    return StorageClient;
    }
    
    
     public static string[] ListBuckets()
        {
            ListBucketsResponse Response;
            //Creating AmazonS3Client and disposing it in using
            using (AmazonS3Client StorageClient = GetClient())
            {
                Response = StorageClient.ListBuckets();
            }

            var BucketNames = from Bucket in Response.Buckets select Bucket.BucketName;
            return BucketNames.ToArray();
        }
        
        public static bool DeleteFile(string keyName)
        {
            var delRequest = new DeleteObjectRequest
            {
                BucketName = bucketName,
                Key = keyName
            };
            //Creating AmazonS3Client and disposing it in using
            using (AmazonS3Client StorageClient = GetClient())
            {
                StorageClient.DeleteObject(delRequest);
            }
            return true;
        }
}

计划使用下面的单例并使用块删除 ->

class S3ObjectStorageClient
    {
        /// <summary>
        /// Singleton implementation of Object Storage Client
        /// </summary>
        private S3ObjectStorageClient()
        {
            
        }    

        public static AmazonS3Client Client
        {
            get
            {
                return S3Client.clientInstance;
            }
        }

        /// <summary>
        /// Nested private class to ensure Singleton
        /// </summary>
        private class S3Client
        {
            static S3Client()
            {

            }

            internal static readonly AmazonS3Client clientInstance = ObjectFileManager.GetClient();
        }
    }

 public ObjectFileInfo(string path)
{
    StorageClient = S3ObjectStorageClient.Client; //Singleton
    objectFileInfo = ObjectFileManager.getFileInfo(StorageClient, path);
}
    
    
     public static string[] ListBuckets()
        {
            ListBucketsResponse Response;
            
            //Singleton and removed using block
           AmazonS3Client StorageClient = S3ObjectStorageClient.Client;
           Response = StorageClient.ListBuckets();
            

            var BucketNames = from Bucket in Response.Buckets select Bucket.BucketName;
            return BucketNames.ToArray();
        }
        
        public static bool DeleteFile(string keyName)
        {
            var delRequest = new DeleteObjectRequest
            {
                BucketName = bucketName,
                Key = keyName
            };
            //Singleton and removed using block
            AmazonS3Client StorageClient = S3ObjectStorageClient.Client;
            StorageClient.DeleteObject(delRequest);            
            return true;
        }
}

【问题讨论】:

  • 根据亚马逊的说法,AmazonS3Client 对象是线程安全的,旨在同时跨多个请求使用:stackoverflow.com/a/7746922/1204153
  • @Andy:所以 AWS 建议它是线程安全的,我可以使用单例连接,但我的问题是每次都创建新连接并处理它与维护单例连接相比有性能优势吗?
  • 是的,当然它有很大的好处。没有理由每次都创建新连接。这样做非常耗费资源。您必须每次都进行身份验证。只需像使用单身人士一样使用它,它就会将你的日常工作速度提高十倍。
  • 重用,其他 cmets 已经解释过的好处,我同意这些。辛格尔顿很好。尽管 DI 在您的情况下是更好的选择(测试能力、处置等),但您也可以在 DI 中指定单例服务。有关概述,请在此处阅读 enterprisecraftsmanship.com/posts/…。简单示例 services.AddSingleton();

标签: c# amazon-s3


【解决方案1】:

作为 AWS .NET SDK 的作者之一,我可以提供更多背景信息。在 AmazonS3Client 以及 SDK 中的所有其他服务客户端的掩护下,它管理着一个 HttpClients 池,这是要创建的昂贵对象。因此,当您创建新的 AmazonS3Client 时,开发工具包正在重用开发工具包管理的池中的 HttpClient。

如果您使用具有代理凭据的代理,那么 SDK 必须在每次创建服务客户端时创建一个新的 HttpClient。

在创建服务客户端时可能存在潜在性能问题的一个领域是确定当 AWSCredentials 对象未传递到构造函数时要使用的 AWS 凭证。这意味着每个服务客户端都必须解析凭据,如果您使用代入角色配置文件,这可能会导致大量额外调用来执行代入角色。从实例元数据获取凭据经过优化,每个进程只有一个线程刷新这些凭据。

【讨论】:

  • 听起来瓶颈是凭据解析。也就是说,我认为该方法是将凭据保存在内存中并将它们传递给客户端的新实例。换句话说:凭据是单例的,客户端对于每个请求都是新的。
【解决方案2】:

实际上,您可以安全地重用它,根据the docs,创建和重用客户端并不是一个坏主意。但是创建一个新客户端并不是很昂贵:

适用于 .NET 的 AWS 开发工具包最著名的方面是您可以用来与 AWS 交互的各种服务客户端。客户端对象是线程安全的、一次性的并且可以重用。 (客户端对象很便宜,因此构建多个实例不会产生很大的开销,但创建和重用客户端也不错。)

因此,根据这一点,性能优势可能不会那么大。但由于创建新客户端的成本很小,我总是会重用客户端。也就是说,根据您的代码的文档

            using (AmazonS3Client StorageClient = GetClient())
            {
                Response = StorageClient.ListBuckets();
            }

并不是很糟糕,但比使用单例的效率要低一些。如果你认为它以明显的方式损害了你的性能,最好的办法是测量它,如果它确实是使用单例的原因重构。

【讨论】:

  • 我每次都在 using 块内创建一个新客户端,我觉得应该避免使用块??
  • 嗯,最好是使用单个客户端并在退出应用程序时处理它,但是根据文档,创建新客户端并使用 using 块处理它们在性能方面并没有太大成本
【解决方案3】:

两者都是有效的方法,但使用单例肯定会提高代码效率。

此外,AWS 提倡依赖注入作为使用客户端的正确模式。例如,新的 AWS 服务 CodeGuru 分析器突出显示多个客户端实例作为优化源。

另请参阅:https://aws.amazon.com/fr/blogs/developer/working-with-dependency-injection-in-net-standard-inject-your-aws-clients-part-1/

【讨论】:

  • 这并不能回答您仍然可以选择为每个请求注入单例或新实例的问题
猜你喜欢
  • 1970-01-01
  • 2021-03-18
  • 2015-11-18
  • 2015-09-23
  • 1970-01-01
  • 2021-07-25
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多