在写《VMware内存机制初探》之后,原本是计划写一篇《VMware内存机制再探》的,讲一讲VMware内存机制中的另外几个重要内容,比如透明内存共享(TPS, Transparent Page Sharing), Relaim Memory, Ballooning, swapping等等。但有网友反映说前面的文章还是不好懂。于是想,如果如同官方文档那样条条框框地列出来,那还不如大家都去看原版手册呢,所以有了这么一篇东西。

首先,大家要记住,在内存没有过量配置(Memory Overcommitment)的情况下,内存的调度机制完全不会启动,就没有Reclaim内存。很明显嘛,主机总的物理内存(Host Physical Memory)大于所有虚机配置内存的总额的情况下,每台虚机想要多少内存,都能得到满足,当然不需要调度。

所以,以下探讨的VMware的内存机制,都是在内存过量配置的情况下发生的。

我的故事发生在一个有智慧的水池(Host)中,水池有不少水(4GB物理内存),里面还有2个水箱(配置了2台VM),水箱有一定的容量(配置内存是4GB),原本是空的(没有开机)。
snap0049

但是现在水箱1里面要养鱼了,必须放点水进去以便鱼可以存活(开机了)。最少需要1GB内存。于是水箱1(VM1)就向水池(Host)要水(物理内存),水池里面有足够的水,就满足了水箱1的要求。现在水箱1有1GB的活水,而水池里面只剩下3GB的水了。
snap0050
 
现在我们又向水箱1里面多丢了些鱼(启动新的应用),原来1GB的水不够用了,于是水箱1就继续向水池要水,水池里面还有足够的水,就又满足了水箱1的要求。现在水箱1里面有3GB的水,而水池里面只剩下1GB的水了。


解释:要注意的是,此时VM1里面的应用程序都是活动的(active),所以这些内存都属于活跃状态,叫做活动内存(Active Memory)。
snap0051
经过了一段时间以后,水箱1里面的鱼被捕走了,现在水箱1不需要那么多水也足够养活剩下的鱼了。但是水池并不知道水箱1的状况。于是水箱1还是有那么多水。

解释:
VM1的某些应用结束后,释放了部分内存,但是这些内存释放动作是在VM的Guest OS层面释放的,因此Host并不知道有内存被释放了,这些内存没有归还Host,仍然由VM1霸占着。VM1中就有一部分内存属于idle,另外一些正在使用的内存就是active memory。当然,就VM1自己的GOS看起来,有3GB空闲内存(idle memory),1GB的活动内存;而此时就Host看来,只看见有3GB内存是分配给了VM1的。Host通过VMware Tools中的驱动,每隔一定的时间(ESX4中默认是60秒,ESX3中默认是30秒)去扫描一下VM1的内存使用状态,以便了解它到底有多少活动内存(active memory)

snap0052
 
此时,我们开始在水箱2中养鱼了(VM2开机),水箱2也开始从水池中抽水。但是水池里面的水不能枯竭,因此水池有警戒水位,第一条警戒水位是6%,当下降到第一警戒水位以下并仍然在不停下降时,就要开动其他机制从其他水箱反抽水。

解释:
VM2开机时也需要1GB内存,在启动时,它也不断向Host请求内存。Host则将自己的内存源源不断地分配给VM2,直到下降到第一条警戒位6%。Host内存有4种状态,分别是High, Soft, Hard和Low,它们间的分界线分别是6%, 4%, 2%和1%。可用内存高于6%时,不会启动Balloon或Swap机制。当低于6%并往4%逼近的时候(soft状态),Balloon机制就启动了。(关于内存的4种状态的更多解释,请参阅官方文档《Understanding Memory Resource Management in VMware ESX Server》。如何查看这4种状态?可以用esxtop或者resxtop)

image
那到底向哪个水箱抽水呢?谁的水最富裕就向谁抽。

解释:
如何判断呢?刚才我们说过,Host每隔一定时间就会扫描Guest OS的内存使用状况,此时,Host会计算每个VM的份额内存比ρρ和VM的空闲内存还有空闲内存税(IMT, Idel Memory Tax)密切相关,对ρ最小的那台虚机启动气球驱动(balloon driver),气球开始膨胀(inflating)。关于ρ和IMT的算法,请参见本人博文《空闲内存税的算法》。

snap0054
于是,气球开始膨胀,并将多余的水挤出水箱。

解释:Balloon驱动如同普通驱动那样,不断向Guest OS索取内存,Guest OS尽自己可能满足气球驱动,并优先将空闲部分的内存分配给它,注意,此时可能出现Guest OS自己的物理内存不足,并引起Guest OS的paging机制,将一部分内存page out到自己的swap中。这个例子中,VM1还有很多空闲内存,因此足够让主机回收并满足VM2的需求。

主机将比较气球膨胀获得的这部分内存的地址,如果原先是分配给VM1独享的,(也就是没有TPS共享),那么就可以收回。主机将不停的通过气球驱动收回内存,收回的目标是保持至少6%的内存。这个回收内存的过程就叫Reclaim。

注意:此时内存没有出现争用情况,因此shares仍然没有起作用,但是Overcommitment是存在的,所以会有reclaim,会有ballooning。
snap0056
Ballooning回收内存是比较慢的,通常需要几分钟。

如果主机可用内存池的内存减少速度大于气球驱动返还主机的内存,那么可用内存会进一步下降,当突破4%的第2警戒线时,进入到hard状态,主机就会启用第2种reclaim机制——swapping,将VM1的一部分物理内存交换到swap文件中,以加快回收内存的速度。目的是将可用内存保持在4%的警戒线以上。

如果可用内存继续下降到2%以下,进入到low状态的时候,ESX不仅会继续加速Swapping,还会阻止其上所有VM的内存请求。

现在,情况又发生了变化,水箱2中的鱼越来越多了,它不停地向水池要水,而水池也通过气球驱动,不停地将水箱1中的空闲内存挤出来,直到水箱1和2的总需求量大于了水池能供给的水量。水池再也不能提供更多的水了,只能部分满足2个水箱的要求了。不够的部分怎么办?用一些脏水(swap)来满足。脏水虽然脏(swap内存速度很慢),鱼在脏水里面生存的很困难,但毕竟还是有水的,不至于因为没有足够的水而导致鱼死掉。
snap0058

此时,VM1和VM2的active memory由2部分组成,1部分是获得的主机物理内存,另一部分是swap。请注意,Guest OS是不知道自己的一部分物理内存是硬盘上的swap文件的。

当机器内存不足竞争开始的时候,shares开始起作用。但是,请注意,如果IMT是0,对空闲内存不征税,由于4GB的VM1和4GB的VM2的份额都是40960,因此它们最终会拿到相同的物理内存2GB。但是如果IMT是默认值,那么空闲内存的代价更大,那么这2台VM会根据active内存数量的不同,获得不同数量的物理内存。
 
【本文的知识要点回顾】

(1) 在内存没有过量配置(Memory Overcommitment)的情况下,不需要Reclaim内存
(2) 什么时候开始Reclaim内存?当突破6%的警戒线,内存状态从High变成了Soft的时候
(3) Reclaim优先用Ballooning,只有Ballooning不够用的时候,才会用Swapping
(4) 什么时候开始swapping? 当主机可用内存跌破4%警戒线,内存状态变成Hard的时候
(5) Host无法知道VM内的哪些内存块已经处于空闲(idle)状态。必须用Ballooning才能收回空闲内存。
(6) 尽量避免资源争用,否则造成的Chasing-the-tail效应,会导致更严重的性能负面影响。

【参考文档】

(1) Carl, A. Waldspurger, 2002, Memory Resource Management in VMware ESX Server
http://waldspurger.org/carl/papers/esx-mem-osdi02.pdf
(2) VMware Inc.  Understanding Memory Resource Management in VMware ESX Server
http://www.vmware.com/files/pdf/perf-vsphere-memory_management.pdf
(3
) VMware Inc.  Understanding Host & Guest Memory Usage (2007)
http://mylearn.vmware.com/courseware/12400/PS_TA21_288707_166-1_FIN_v3.pdf
(4) Idel memory tax
http://www.boche.net/blog/index.php/2009/01/29/idle-memory-tax/