如何估算内存消耗

jopen 10年前

        英文原文:How to Estimate Memory Consumption

        Performance Zone 是由 New RelicAppDynamics 支持的。New RelicAppDynamics 作为 APM 领域的领导者,有着备受瞩目的用户并为用户消减大量成本。

        这个故事至少可以追溯到十年前,当我第一次接触到 PHB,遇到了这样一个问题——“为了产品部署我们应该购买多大的服务器”。这个崭新的系统上线已经九个月了。显然公司已经承诺提供整套的解决方案,包括硬件。

        哦,乖乖,我是陷入麻烦之中了吗?我有几年的经验,我倒是可以试一试。虽然我我完全没有信心,但我还是要解决这个问题。经过在谷歌上四个小时的搜索,我依然坐在那里,摆在我面前的还是那个令我感到困惑的问题:“如何估算计算容量呢?”。

        在这篇文章中我通过给你几个大致的纲领来开展这个主题,这些纲领是关于如何估计你的那个全新的 Java 应用所需的内存。对于性急的人来讲,答案大概约等于 5x(内存通过实时数据消耗量),并从那里开始微调。而对于那些对背后逻辑更感兴趣的人,请随我一起,我会引导你完成推理。

        首先,在没有详细信息之前,我不能用简单的几句话来回答这个问题。你的答案必须是依据性能要求而来的,所以刚开始的时候首先要澄清这点。我并不 是说要用很含糊不清的方式,譬如“这个系统需要在线支持 700 个用户”,但还有很多更具体的关于延迟和吞吐量的细节,还要考虑到大量数据,以及使用模式。预算也不应当被遗忘,我们都幻想着亚毫秒级的延迟,但是没有 HTF 银行那样的雄厚资金支持的话,很不幸,它终将只是一个梦想。

        现在,我们假设你有了一些需求,下一步是创建负载测试脚本来模拟用户的行为。如果你可以同时在线启动这些的脚本,你就已经为获取答案建立基础了。正如你猜想的那样,下一步是测试,而不是瞎猜,但是会有一个警告。

        实时数据的大小

        也就是说,最佳内存配置需要捕获实时数据大小。捕获到这些,我们就有了微调的基础。

        如何定义实时数据的大小?Charlie Hunt 和 Binu John 在他们《Java 性能》一书中给出的定义如下:

        实时数据的大小是由设置在其稳定状态运行应用程序所需的长期消耗对象的堆大小。

        有了这个定义,我们在 GC 日志的打开的情况下就可以对应用程序进行负载测试(-XX:+PrintGCTimeStamps-Xloggc:/tmp/gc.log-XX:+PrintGCDetails)和可视化的日志(例如在 gcviewer 的帮助下)来确定应用程序达到稳定状态的时间。接下来你所看到的类似于下图:

如何估算内存消耗

        我们可以看到,GC 进行了 minor GC 和 full GC,有个熟悉的双锯齿形的图形。在第 21 秒第一次 full GC 完之后,这个特殊的应用程序看起来已经达到一个稳定的状态了。然而,在大多数情况下,观察到变化的趋势需要 10-20 次 full GC 的运行。经过四个 full GC,我们可以估算出实时数据大小约等于 100MB。

        上述《Java 性能》这本书表明在一个经典的 Java EE 应用程序中,实时数据大小和最佳内存配置参数之间有很强的相关性,这个领域的证据也支持他们的建议:

        设置最大堆大小为3-4X (实时数据大小)。

        所以,就我们手中应用程序而言,我们应该将-Xmx 设置为 300M 和 400M 之间进行初始性能测试,并从这里进行调试。

        我们对于书上给出的其他建议,建议设置最大的永久代大小为 1.2-1.5x(永久代中实时数据大小)以及-XX:NewRatio 设置为1-1.5x 的(实时数据大小)。目前,我们正在收集更多的数据来确定正相关关系是否存在,但是在那之前,我建议你在配置生存者空间和伊甸园空间时,需要监视到的分配 率来作决策。

        你可能会问为什么要烦恼这些问题呢?事实上,有两个原因让你不需要考虑这个问题:

        (1)在写这篇文章的时候,8G 内存芯片只售 100 美元

        (2)虚拟化,尤其是大型供应商如亚马逊的 AWS 使得调试变得更为简单

        这两个原因的有效性都是片面的,而且明确地减少了精确调配所需。但是它们仍然能够将你拉入危险区域。

        (1)当有大量内存空间时,你很有可能会对延迟造成重大影响,8G 以上的堆非常容易进行 full GC,这将可能停顿超过数十秒。

        (2)过度配置时总是会有“稍后调整”的心态,而这“稍后”可能永远就不会再调整了。我见过大量的应用只是因为这个原因,运行在过度配置的环境 中。例如,前面所提到的应用程序,我发现在亚马逊 EC2 上 m1.xlarge 实例运行成本是每个实例 4200 美元/年,若将其转换成 m1.small 就只需 520 美元。如果你的部署够大,从业务预算中就可以降低 8 倍成本,这一点上请相信我。

        总结

        不幸的是,我依然看到很多决策同我十年前被迫做的极其相似,这导致了规划不足或者过度,这两者都是很差劲的选择。特别是你甚至不能享受虚拟化带来的好处。

        你可能不能仅凭猜测就获得成功,所以我只能建议你使用这篇文章描述的简单框架之前,要有实际的计划。如果你很喜欢这些内容,我推荐你关注我们在 推ter 上的关于性能调优的建议。

        翻译: ImportNew.com - 范琦琦

        译文链接: http://www.importnew.com/10570.html