容器中的Java與內(nèi)存限制:LXC、Docker與OpenVZ
譯文開發(fā)者在使用JVM、內(nèi)存與Docker時(shí)是否遭遇到難題?今天我們將一同利用Jelastic將其解決。最近Matt Willaims提起的Docker內(nèi)Java及其內(nèi)存限制的議題得到了廣泛關(guān)注,而這些在容器使用當(dāng)中無法避免的狀況也在Twitter上引發(fā)一系列討論。
那么在今天的文章中,我們就來共同分析這一問題并嘗試找出解決辦法。
問題
Matt講述了他在Docker容器內(nèi)使用JVM heap時(shí)的探索之旅。他指出,容器對于內(nèi)存的限制未能正確顯示,這導(dǎo)致任意Java或其它應(yīng)用都可分配給該主機(jī)設(shè)備的全部內(nèi)存資源,而JVM卻無法指示其中有多少資源應(yīng)該專門用于其運(yùn)行所在的父容器。如此一來,OutOfMemoryError開始出現(xiàn)。
事實(shí)上,大多數(shù)Linux工具所提供的系統(tǒng)資源指標(biāo)在創(chuàng)建時(shí)間上要早于cgroups(例如free與top,二者皆源自procps)。其通常會從proc文件系統(tǒng):/proc/meminfo,/proc/vmstat, /proc/PID/smaps或者其它位置處讀取內(nèi)存指標(biāo)。
遺憾的是,/proc/meminfo, /proc/vmstat及其它位置無法實(shí)現(xiàn)容器化,也就是其無法為cgroup所識別。其只能顯示主機(jī)系統(tǒng)(物理或虛擬機(jī))的整體內(nèi)存容量,而現(xiàn)代Linux容器技術(shù)無法對其加以利用。容器中的流程無法依靠free、top及其它指標(biāo)確定所能使用的內(nèi)存容量;其必須遵循cgroups提供的約束條件,且無法使用主機(jī)系統(tǒng)中的全部內(nèi)存。
事實(shí)上,實(shí)際內(nèi)存限制條件的可見性非常重要,我們需要利用其實(shí)現(xiàn)應(yīng)用優(yōu)化及故障排查,例如內(nèi)存泄露、交換空間使用、性能下降等等。另外,某些用例還需要利用垂直伸縮以實(shí)現(xiàn)容器內(nèi)的資源使用優(yōu)化,包括自動變更工作程序、進(jìn)程或線程數(shù)量。垂直伸縮往往取決于特定容器的實(shí)際可用內(nèi)存量,因此必須配合容器中的限制可見性方能起效。
解決方案
開放容器倡議配合runC能夠利用文件系統(tǒng)用戶空間覆蓋/proc文件。LXC創(chuàng)建的lxcfs文件系統(tǒng)允許容器擁有虛擬cgroup文件系統(tǒng)及虛擬/proc文件查看方式,這樣上述問題的實(shí)質(zhì)就成了如何對容器進(jìn)行維護(hù)。
我們也遇到過類似的問題,但在Jelastic的幫助下,我們順利為客戶解決了這一障礙。下面來看具體辦法。
首先打開Jelastic向?qū)В瑸闇y試賬戶選定服務(wù)供應(yīng)商并利用預(yù)定義內(nèi)存限制創(chuàng)建一套Java Docker容器——例如8 cloudlets,相當(dāng)于1 GB內(nèi)存。
接下來前往Jelastic SSH gate(1),選定之前創(chuàng)建的測試環(huán)境(2),而后選定該容器(3)。現(xiàn)在我們已經(jīng)可以利用free工具檢查可用內(nèi)存了(4)。
As we can see, the memory limit equals 1GB defined before. Let’s check the top tool.
一切運(yùn)行正常。為了進(jìn)一步檢查,我們重復(fù)Matt之前提到的Java啟發(fā)式行為問題。
現(xiàn)在的MaxHeapSize = 268435546 (~256 MiB),意味著當(dāng)前容器的內(nèi)存容量為默認(rèn)JVM heap的四分之一。
其中的秘訣是什么?當(dāng)然,這是各種“成分”的***結(jié)合。在本示例中,我們將OpenVZ與Docker技術(shù)結(jié)合以提供更出色的安全與隔離控制效果,同時(shí)保證其不會影響到容器實(shí)時(shí)遷移與容器休眠等必要功能。下面,大家可以看到Docker容器在Jelastic當(dāng)中的高級應(yīng)用思路。
在OpenVZ中,每套容器都擁有一套/proc pseudo-filesystem虛擬化視圖。需要強(qiáng)調(diào)的是,容器中的/proc/meminfo為“定制”版本,能夠顯示每容器信息而非直接提取自主機(jī)。如此一來,top與free等工具在運(yùn)行于容器內(nèi)時(shí),就能顯示特定容器中遵循限制條件時(shí)的內(nèi)存與swap使用情況。
值得注意的是,容器中的swap并非真正的swap,而只是一種虛擬機(jī)制(因此其整體技術(shù)被稱為VSwap)。其核心思路在于,一旦啟用了VSwap的某容器超出配置內(nèi)存限制,則其部分內(nèi)存即會轉(zhuǎn)換為所謂swap cache。期間并不會發(fā)生真正的空間交換,意味著不存在I/O——除非整體環(huán)境下出現(xiàn)了全局(而非每容器)內(nèi)存短缺。另外,使用VSwap的容器會通過降低運(yùn)行速度的方式解決內(nèi)存超標(biāo),這種方式從容器內(nèi)部角度來看類似于執(zhí)行真正的空間交換。這項(xiàng)技術(shù)能夠?qū)γ咳萜鲀?nèi)存與swap使用情況加以有效控制。
當(dāng)然,除了Jelastic之外,大家也可以根據(jù)Matt的提示始終為JVM指定heap大小而非依賴于啟發(fā)機(jī)制。如果各位有其它更好的思路,也請?jiān)谠u論中與我們分享。
原文標(biāo)題:Java and Memory Limits in Containers: LXC, Docker and OpenVZ
【51CTO.com獨(dú)家譯文,合作站點(diǎn)轉(zhuǎn)載請注明來源。】