热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

awss3client_AWSS3.NETClient高内存使用率

awss3client将AWSS3.NET客户端LOH分配减少98%内容问题发现为什么会出问题呢?引入最佳魔术数—81,920空闲的手还有一件事TLDR

aws s3 client

将AWS S3 .NET客户端LOH分配减少98%

内容

  • 问题发现
  • 为什么会出问题呢?
  • 引入最佳魔术数— 81,920
  • 空闲的手
  • 还有一件事
  • TLDR-给我好东西
  • 脚注

问题发现

我们在Codeweavers所做的一件事就是帮助人们找到他们的下一辆车。 通常,这涉及到客户看到他们要购买的汽车-我的意思是,您会在不看外观的情况下购买汽车吗? 持有这个责任该应用程序是为淫秽金额分配,时间GC上花费的,而像饼干怪兽吃得好...饼干一般吃RAM 最坏的罪犯。

我们不时地希望从生产环境中获取此应用程序的内存转储。 我们已经完成了足够的时间,因此我们已经将最常见的诊断步骤自动化了,并将其捆绑到一个称为ADA(自动转储分析)的小工具中。 如果你有兴趣,你可以找到的工具, 在这里 ,所有谈到本文中的代码在这里 。

我们运行的分析器之一是转储在大对象堆(LOH)上找到的所有byte []数组。 针对我们的8 GB内存转储运行该分析器后,我们发现了数百个byte []数组,长度为131,096或131,186。 好吧,这很奇怪。 在Notepad ++中打开某些文件只会给我们带来很多随机字符。

我把科学方法丢到窗外一秒钟,我决定将所有转储的byte []数组重命名为* .jpg-嘿,现在有些文件现在显示缩略图! 经过仔细检查,大约50%的文件是图像。 其余50%都无法完全打开为图像。 在Notepad ++中打开少​​数非图像文件显示,它们在文件开头都有一行类似于此的行:-

0;chunk-signature=48ebf1394fcc452801d4ccebf0598177c7b31876e3fbcb7f6156213f931b261d

好的,这开始变得更有意义了。 长度为131,096的byte []数组是纯图像。 不是图像的byte []数组的长度为131,186,并且在其余内容之前具有块签名行。 我签名是内容的SHA256哈希。

在继续进行之前,值得确定该应用程序在图像处理方面的繁忙程度。 我们使用AWS SNS和SQS在我们的服务器场中分布了所有图像处理。 使用CloudWatch指标,我们可以轻松看到:

好了,所以相当繁忙。 值得注意的是,在进行任何以性能为中心的工作之前,请务必确定执行代码的频率和当前成本。 如果代码路径的成本很高(例如,花费二十秒钟),但每天只命中一次,则不值得研究。 但是,如果相同的代码路径被击中很多(例如一天一百万次),那么绝对值得研究。

此时,我想到了两个罪魁祸首。 我们已经建立了有问题的应用程序来做很多图像处理。 但是有一些移动的部分和两种启动图像处理的方式:-

  1. 图片被推送给我们
  2. 我们从SFTP提取图像

之后,我们转换图像,然后将其上传到AWS S3 。 在此阶段,我倾向于使用SFTP,因为它可能需要验证从服务器接收到的每个块。 但是,随着我的预感,我开始追逐野鹅,于是我无视我的直觉,便将大块签名插入Google并粉碎了输入。 谷歌指出AWS S3是罪魁祸首 。 但这仅仅是理论,我们需要证明这一点。

如果我们上传相同的图像十次并使用dotTrace来查看LOH,则会看到一个有趣的模式:

每次我们在AWS S3 .NET客户端上调用PutObject时,看起来固定的成本为0.3 MB。 这是一个问题,因为这意味着每次使用PutObject时,每次上载都要付出0.3 MB的高额费用。 只想确认一下; 如果将上传次数从十次增加到一百次会发生什么?

是的,我们可以肯定地说,每次调用PutObject都会产生0.3 MB的昂贵分配。 更进一步,并使用ProcDump转储该过程:-

procdump64.exe -ma -64 AWS-S3.exe

通过ADA运行转储文件,我们看到有两组byte []数组具有完全相同的特性; 50%的长度为131,096,其他50%的长度为131,186。 重命名时,文件的一半是图像,文件的一半具有块签名起始行。 至此,我们可以确定AWS S3 .NET客户端正在将byte []数组直接分配到LOH上。 那个问题。

为什么会出问题呢?

LOH是一个已收集但从未压缩的内存区域,尽管从现在开始可以进行.NET v4.5.1 压缩 ,但警告字眼的LOH压缩代价很高。 每兆字节大约2.3毫秒 。 一条很好的经验法则是,短暂的物体不能进入LOH。

等于或大于85,000字节的对象直接进入LOH。 LOH的操作与其他内存区域大不相同。 会定期收集和压缩其他内存区域,这意味着您可以在垃圾收集器运行后将新对象添加到末尾。 而LOH尝试将新分配的对象放入废弃对象遗留的剩余空间中。 如果新分配的对象的大小与可用空间完全相同或较小,则此方法很好用。 如果找不到空间,则LOH必须增长以容纳该对象。

它有助于像书架一样思考它; 在内存的其他区域中,不再使用的书籍被简单地扔掉,剩余的书籍被推到一起,任何新书都放在书架的末端。

在不可能的LOH内,将丢弃书籍(对象),并记录该空间中以前的页数(字节),并在下次将书分配到该书架时(LOH)它试图找到一个可以容纳那么多页面(字节)的空白空间。 如果书架不能容纳新分配的书(对象),则必须扩展书架以容纳新书(对象)。

垃圾收集器将从LOH收集死对象,与此同时,将新对象分配给LOH。 这可能导致长时间运行的应用程序出现生命周期的情况,其中LOH大小已增加到几GB(因为新对象无法容纳到现有的空白空间中),但实际上仅包含几个活动对象。 这称为LOH碎片。 在这种情况下,我们非常幸运,因为将其放入LOH的byte []数组有两个大小; 131,186和131,096。 这意味着,无论哪种大小的旧对象死亡并被收集,新分配的对象都恰好适合将其放入空白空间的大小。

好吧,回到有趣的东西。

引入最佳魔术数— 81,920

多亏了dotTrace,我们才能够准确地确定导致LOH碎片的原因。 它也向我们显示,每次调用PutObject的固定成本0.3 MB发生在ChunkedUploadWrapperStream的构造函数内部:

快速访问该文件在AWS-SDK-网库。 显示创建的两个byte []数组的长度至少为131,072:-

这就是为什么将这些byte []数组直接分配给LOH的原因,它们高于LOH阈值(85,000个字节)。 此时,有几种可能的解决方案:

  1. 使用System.Buffers从byte []数组池中租用两个byte []数组
  2. 使用Microsoft.IO.RecycableMemoryStream并使用Stream的池直接对传入流进行操作
  3. 公开DefaultChunkSize,以便API的使用者可以自行设置
  4. 将DefaultChunkSize降低到低于LOH阈值的数字(85,000字节)

第一个和第二个解决方案可能是获得最大胜利的解决方案,但这将需要大量的请求,并引入了库维护人员可能不希望的依赖项²。 第三种解决方案意味着图书馆的使用者必须了解该问题并将其设置为合理的数目,以避免分配LOH。 不,似乎第四个解决方案最有可能被接受,破坏现有功能的可能性也最小。

我们所需要的只是一个低于85,000的数字,通常像84,000这样的数字非常合适。 但是,在发现此问题之前几周,当我偶然发现这个宝石时,我正在四处寻找参考源 (正在研究另一个问题):

Windows内存页的大小为4,096字节 ,因此,选择低于LOH阈值(85,000字节)的内存页是很有意义的。 是时候分叉,分支, 创建问题并提出拉取请求了 。

幸运的是,我们可以在本地进行更改³,看看有什么好处。 通过PutObject上传同一图像的一百次统计:-

空闲的手

在等待对我的请求请求进行审核的同时,我决定去查阅AWS S3文档,偶然发现了预签名URL的概念。 听起来很有趣! 创建上传器的V2:-

上载相同文件一百次时,我们看到它具有以下统计信息:-

那真是太棒了,而我们实际上要做的就是阅读文档! 好吧,这是不对的,您的好处是可以阅读包含所有内容的摘要文章。 您在此处看到的工作是在一周的时间内完成的,介于两次客户工作之间。

使用GetPreSignedURL的一个小缺点是,如果修改了GetPreSignedUrlRequest并且未相应地修改WebRequest,则AWS将返回HTTP 403 Forbidden (例如,删除WebRequest上的XAmzAclHeader)。 这是因为客户端哈希和服务器哈希不再匹配。

还有一件事

感谢我的上一篇文章,我了解了什么是书呆子狙击 -我对自己做了很多事情。 在此阶段,我感到对其他东西可以省掉有点头晕,我一直在看着LOH上还剩下0.4 MB。 同样,dotTrace将我们指向代码路径的方向,导致向LOH分配了0.4 MB:-

耶克斯, 那看起来很严肃 。 安静地退后一步,尝试另一种策略; 我们知道一个预签名的URL看起来像这样:

https://##bucket_name##.s3.##region_name##.amazonaws.com/##path##/##file_name##?X-Amz-Expires=300&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=##access_key##/20180613/##region_name##/s3/aws4_request&X-Amz-Date=20180613T233349Z&X-Amz-SignedHeaders=host;x-amz-acl&X-Amz-Signature=6bbcb0f802ad86022674e827d574b7a34a00ba76cd1411016c3581ba27fa5450

由于AWS非常友好地发布了他们的签名过程 ,因此我们应该能够自行生成该URL。 在这一点上,我承认我已经准备好接受失败,只留下0.4 MB的内存在LOH上。 我真的不喜欢的代码里姆斯我正要写可能消除剩余的0.4 MB将是值得的。

直到我发现我想要的例子为止。 我的工作量大大减少了; V3诞生了:-

V3只是一个实验,旨在了解可能的情况,因为所获得的收益和维护的代码量不大,这并不是我们在生产代码中实际使用的东西。 预签名URL的发现是这里的主要优势:-

同时,我的拉取请求已合并并发布到AWSSDK.Core的3.3.21.19版本中。 时间轴快速概述:-

  1. 2018–03–07 —在aws-sdk-net存储库上创建的问题
  2. 2018年3月13日-发送拉取请求
  3. 2018-03-29 —合并请求请求
  4. 2018–03–29 —新版本的AWSSDK.Core已发布到NuGet

我喜欢开源。

TLDR-给我好东西

低于3.3.21.19的AWSSDK.Core版本导致在AWS S3 .NET客户端上每次PutObject调用的固定成本为0.3 MB。 在3.3.21.19及更高版本中已对此进行了纠正。 对于特别热的代码路径,值得探索在AWS S3 .NET客户端上使用GetPreSignedURL,因为在我们的上下文和用例中,LOH分配减少了98%。

找到我Twitter , LinkedIn或GitHub 。

脚注

¹另一个原因可能是WinDbg仍然吓到我了。

²话虽如此, 最近的一次对话已经开始利用.NET Core的优点。

³确保不像某些人那样发布版本-好的,是我

本来在发表 dev.to

翻译自: https://hackernoon.com/its-not-your-code-vol-i-c06fac8784df

aws s3 client



推荐阅读
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在使用USB接口的二维条码扫描器时,发现其无法正确识别条码中的中文字符。然而,采用串口连接的方式则能够成功识别。目前面临的问题是如何将通过串口获取的数据在网页中进行实时展示,希望各位专家能提供解决方案,不胜感激。 ... [详细]
  • 基于Dubbo与Zipkin的微服务调用链路监控解决方案
    本文提出了一种基于Dubbo与Zipkin的微服务调用链路监控解决方案。通过抽象配置层,支持HTTP和Kafka两种数据上报方式,实现了灵活且高效的调用链路追踪。该方案不仅提升了系统的可维护性和扩展性,还为故障排查提供了强大的支持。 ... [详细]
  • 如何将PHP文件上传至服务器及正确配置服务器地址 ... [详细]
  • 深入解析Gradle中的Project核心组件
    在Gradle构建系统中,`Project` 是一个核心组件,扮演着至关重要的角色。通过使用 `./gradlew projects` 命令,可以清晰地列出当前项目结构中包含的所有子项目,这有助于开发者更好地理解和管理复杂的多模块项目。此外,`Project` 对象还提供了丰富的配置选项和生命周期管理功能,使得构建过程更加灵活高效。 ... [详细]
  • 本文详细介绍了如何在微信小程序中使用JavaScript实现图片上传至PHP服务器的方法。通过具体的代码示例,帮助开发者掌握从客户端选择图片、处理图片数据到服务器端接收并保存图片的完整流程。同时,文章还提供了常见问题的解决方案和优化建议,确保上传过程的高效性和稳定性。 ... [详细]
  • 通过Apache Commons FileUpload组件,可以根据具体应用需求实现多样化的文件上传功能。在基本应用场景中,开发者可以通过调用单一方法来解析Servlet请求,从而轻松处理文件上传任务。此外,该组件还提供了丰富的配置选项和高级功能,支持大文件上传、多文件并发处理等复杂场景,显著提升了文件上传的效率和可靠性。 ... [详细]
  • 在优化Nginx与PHP的高效配置过程中,许多教程提供的配置方法存在诸多问题或不良实践。本文将深入探讨这些常见错误,并详细介绍如何正确配置Nginx和PHP,以实现更高的性能和稳定性。我们将从Nginx配置文件的基本指令入手,逐步解析每个关键参数的最优设置,帮助读者理解其背后的原理和实际应用效果。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
  • 在 Vue 项目中,为了提高页面加载速度和优化用户体验,实现图片上传前的压缩处理至关重要。本文介绍了如何通过集成第三方库和自定义组件,有效减小图片文件大小,确保在不影响图像质量的前提下,提升应用性能。 ... [详细]
  • 在处理大图片时,PHP 常常会遇到内存溢出的问题。为了避免这种情况,建议避免使用 `setImageBitmap`、`setImageResource` 或 `BitmapFactory.decodeResource` 等方法直接加载大图。这些函数在处理大图片时会消耗大量内存,导致应用崩溃。推荐采用分块处理、图像压缩和缓存机制等策略,以优化内存使用并提高处理效率。此外,可以考虑使用第三方库如 ImageMagick 或 GD 库来处理大图片,这些库提供了更高效的内存管理和图像处理功能。 ... [详细]
  • AppFog 是一个基于 CloudFoundry 的多语言 PaaS(平台即服务)提供商,允许用户在其平台上轻松构建和部署 Web 应用程序。本文将通过详细的图文步骤,指导读者如何在 AppFog 免费云平台上成功部署 WordPress,帮助用户快速搭建个人博客或网站。 ... [详细]
author-avatar
I-1ove-Y0u
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有