作者PsMonkey (痞子军团团长)
看板Translate-CS
标题[翻译] 如何估算记忆体需求
时间Sun Mar 23 23:49:00 2014
原文网址:
https://plumbr.eu/blog/how-to-estimate-memory-consumption
译文网址:
http://blog.dontcareabout.us/2014/03/blog-post.html
BBS 用 markdown 语法撰写
______________________________________________________________________
这个故事得从十年前开始说起,
那时我第一次接触到一个[尖头老板]的问题:
「我们的产品要布署的时候,需要买多好的 server?」
在产品发表之後,我们花了九个月的时间打造了一个金光闪闪的新系统,
显然公司已经承诺要提供整个解决方案,包含硬体的部份。
囧... 我麻烦大了。
我只有短短几年的经验,回答这问题跟丢骰子没啥两样。
虽然我看起来整个就是缺乏信心,不过我仍然得生出一个答案。
在 google 了四个小时後,眼花撩乱的脑袋里仍然是相同的问题:
「如何估算所需的运算能力?」
在这篇文章中,我先用「如何估算记忆体需求」这个题目,
让你在写 Java application 时有个初步的准则。
如果你没啥耐心看完,答案是先用「即时资料占用的记忆体量」乘上 5 倍,
然後以此作为微调起点。
想知道背後的逻辑,那就继续看下去,我会一步一步推导。
首先,我只能建议在取得详细的资讯之前,避免回答这类的问题。
你必定得根据效能需求来回答这类问题,
所以在厘清这些东西之前甚至不应该开始。
我说的也不是「这个系统要能同时承受 700 个使用者」这种暧昧的内容,
而是大量特定的资讯,例如延迟时间、throughput、
计算资料的数量、使用模式等等。
而且还不要忘记预算这档事。
大家都会梦想有着次 ms 等级的延迟度,
但没有大财团等级的预算,那抱歉,它只会是一个幻想。
现在让我们假设你已经有这些需求了。
下一步是建立负载测试码来模拟使用者行为。
如果你现在能够同时启动这些程式码,这就是你回答问题的基础。
As you might also have guessed,
the next step involves our usual advice of measuring not guessing.
But with caveat.
即时资料的大小
--------------
我们手上的「记忆体理想设定」任务,需要取得即时资料的大小。
取得这个数据,我们就有微调的基准点。
如何定义「即时资料的大小」?
Charlie Hunt 与 Binu John 在他们的《[Java 效能优化指南]》这本书中
给了这样的定义:
即时资料的大小,是 application 在稳定的状态下,
长时间存在的 object 所占用的 heap 大小。
使用这个定义,我们就可以把 GC 的 log 功能开启
(`-XX:+PrintGCTimeStamps -Xloggc:/tmp/gc.log -XX:+PrintGCDetails`)
来执行你的负载测试,
然後把 log 纪录给视觉化(例如用 [gcviewer])
来确定 application 什麽时候达到稳定的状态。
你会看到类似下面这张图:

我们可以看到 minor GC 跟 full GC 都有作用,
造成了一个常见的双锯齿图形。
这个特定的 application 似乎在第 21 秒、
第一次 full GC 後就到达了稳定的状态。
然则在大多数的情况下,需要 10~20 个 full GC 运作之後
才能确定变化的趋势。
在经过 4 个 full GC 运作之後,
我们推算即时资料的大小约为 100MB。
前头提到的那本《[Java 效能优化指南]》指出:
在一个典型的 Java EE application 中,
即时资料大小与记忆体最佳化参数有很强的相关性。
实际的证据也佐证了这个建议:
heap 的极大值设定为即时资料大小的 3~4 倍。
所以,就我们手上的 application 初步测试後,
我们应该将 `-Xmx` 设定在 300m~400m 之间。
我们结合了书上给的其他意见,
建议 permanent generation 的最大值设为
「permanent generation 的即时资料大小」的 1.2~1.5 倍,
而 `-XX:NewRation` 的设定为「即时资料大小」的 1~1.5 倍。
我们正在收集更多的资料以确定是否存在正相关,
但在那之前,我会建议你以目前 survival 与 eden 的设定结果为基础,
监看你的 allocation rate。
你可能会问为什麽要这样?事实上,有两个不是那麽表面的原因:
* 写这篇文章时,8G 的记忆体售价在 $100 左右。
* 虚拟化、尤其是用 Amazon AWS 这种大型供应商的服务,
调整容量是十分容易的。
这两个原因都部份成立,而且绝对会减少配置上的需求。
不过这两点仍然没有让你脱离危险地带:
* 当弄了大量的记忆体,你非常有可能影响延迟时间。
当 heap 有 8G 或更多的时候,full GC 很容易造成几十秒的停顿。
* 当过度配置随之而来的「之後再调整」心态,
常常「之後」就再也没有然後了。
我曾面对许多 application 在远超过配置的环境上执行,
只是因为想「之後再调整」。
例如前面提到的 application,
我发现在 Amazon EC2 m1.xlarge instance 上,
每个 instance 每年要花公司 $4200。
转换到 m1.small,每个 instance 只要 $520。
不要怀疑,当你要布署的环境很大的时候,
你会无法忽视这 1 比 8 的成本差异。
结论
----
不幸的是,我仍然看到许多人做了如同十年前的我被迫做的决定。
这导致了过与不足的规划,两者同样糟糕、尤其当你无法享有虚拟化优点的时候。
对我来说,我很幸运,但你可能没办法逃离你的客户。
所以我只能建议用前面提到的简单 framework 来未雨绸缪。
如果你喜欢这篇,我建议你关注我们在 Twitter 上的[效能调校]建议。
[尖头老板]:
http://en.wikipedia.org/wiki/Pointy-haired_Boss
[Java 效能优化指南]:
http://www.amazon.com/
Java-Performance-Charlie-Hunt/dp/0137142528
[gcviewer]:
http://www.tagtraum.com/gcviewer.html
[效能调校]:
https://twitter.com/intent/follow?
region=follow_link&screen_name=javaplumbr
--
钱锺书:
说出来的话
http://www.psmonkey.org
比不上不说出来的话
Java 版 cookcomic 版
只影射着说不出来的话
and more......
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.129.132.145