最近公司在搞降本的事,出于好奇,查看了很多服務(wù)的Pod,資源實(shí)際使用率都是非常低的,但是資源申請(qǐng)又非常高,于是就開始思考一些問題,今天把我認(rèn)為的常見問題分享下。
個(gè)人見解,如有不對(duì),請(qǐng)糾正。
K8s環(huán)境下,unused committed memory 可以被共享嗎?
一般從JVM的Prometheus采集的metric里會(huì)看到有不同的memory定義,主要由Max Memory,Used Memory,Committed Memory。其中前兩個(gè)比較好理解,這里主要說下Committed Memory。
Java 文檔中對(duì)已提交內(nèi)存的定義
represents the amount of memory (in bytes) that is guaranteed to be available for use by the Java virtual machine. The amount of committed memory may change over time (increase or decrease). The Java virtual machine may release memory to the system and committed could be less than init. committed will always be greater than or equal to used.
大意:用于保證JVM正常運(yùn)行的可用內(nèi)存。已提交的內(nèi)存會(huì)隨時(shí)發(fā)生變化(升高或降低)。JVM會(huì)釋放已提交但未使用的內(nèi)存給OS,同時(shí)已提交的內(nèi)存可能會(huì)小于-Xms,但已提交的內(nèi)存總是大于等于已使用的內(nèi)存。
根據(jù)定義,基本可以知道committed memory屬于Java進(jìn)程獨(dú)占的,不可以被其他進(jìn)程使用,所以也就不存在共享。
但再使用Java 11 G1 時(shí),常常會(huì)看到metric里committed memory 久久不能被釋放,盡管文檔說GC會(huì)嘗試方式committed memory。
查閱相關(guān)文檔,在Java 11 中G1對(duì)unused committed memory 釋放的條件,在一般情況下比較難以達(dá)到
條件
- Full GC;(G1的設(shè)計(jì)之初,就是想通過分散成多次小GC等盡量避免觸發(fā)Full GC)
- 執(zhí)行concurrent cycle;
這情況在k8s下,其實(shí)更是不友好,因?yàn)檫@些unused committed memory依然會(huì)產(chǎn)生費(fèi)用,導(dǎo)致資源使用率下降。
所以,日常我們選擇Pod型號(hào)時(shí),在滿足應(yīng)用正常啟動(dòng)及運(yùn)行中產(chǎn)生對(duì)象的情況下,多冗余部分(小于50%,視成本和性能而定)的內(nèi)存。
K8s里的資源配置requests與limits
K8s里這兩個(gè)參數(shù)很關(guān)鍵,是Pod被快速schedule的關(guān)鍵因素之一。
requests:Pod(Container) 里進(jìn)程啟動(dòng)所需要的最小的資源配置,它是k8s承諾給到使用者的資源(CPU和Memory);
limits:Pod(Container) 里進(jìn)程運(yùn)行時(shí)可向OS申請(qǐng)的最大資源配置,它不是k8s承諾的資源,言外之意是被schedule到的node節(jié)點(diǎn)可能沒有l(wèi)imits的資源。
limits的這種設(shè)計(jì),主要是考慮到pod在啟動(dòng)時(shí)應(yīng)該能夠被很容易的schedule,而不是因?yàn)閚ode上的可用資源不夠,導(dǎo)致創(chuàng)建新的node階段,從而導(dǎo)致跟多的小塊資源未被使用。
在日常配置時(shí),可以將requests配置成 JVM的 -Xms ,而limits配置成大于-Xmx的配比值,因?yàn)橐WC非堆及其他的內(nèi)存使用。
K8s環(huán)境下如何合理配置JVM heap?
根據(jù)上面requests和limits的說明,理論上 requests >= -Xms,而 limits > -Xmx ,可根據(jù)實(shí)際實(shí)際的調(diào)優(yōu)結(jié)果,選擇更合適的資源配比。
配置合理的JVM
- 需要分析應(yīng)用的類型
比如有些應(yīng)用啟動(dòng)時(shí)會(huì)加載大量的數(shù)據(jù)到內(nèi)存中,那啟動(dòng)就需要更多的內(nèi)存,一般屬于內(nèi)存型應(yīng)用,該種應(yīng)用應(yīng)該配置更多的內(nèi)存,以避免發(fā)生fault page,甚至是OOM;
比如有些應(yīng)用運(yùn)行時(shí),會(huì)發(fā)生大量的運(yùn)算,所以需要配置更合理CPU及內(nèi)存,一般屬于CPU型應(yīng)用,這種應(yīng)用內(nèi)存也不能太?。?/li> - 思考K8s下heap與資源配置
可以將-Xms 與-Xmx 配置相同,即requests = -Xms = -Xmx ,思路是
(1) 能夠保證Java應(yīng)用在k8s應(yīng)用上的安全運(yùn)行,即不會(huì)因?yàn)閮?nèi)存不夠問題發(fā)生OOM;
(2)一般應(yīng)用運(yùn)行,會(huì)出現(xiàn)很快出現(xiàn)Committed Memory達(dá)到了-Xmx的情況,我們知道GC在向OS申請(qǐng)內(nèi)存,會(huì)發(fā)生抖動(dòng),影響性能;
以上只是一些個(gè)人參考的思路,歡迎討論。
K8s環(huán)境下如何看待OOM?
K8s里核心的設(shè)計(jì)理念之一 —— 容錯(cuò)性,就是說當(dāng)發(fā)生意外后,Pod能夠被快速?gòu)闹谢謴?fù)。
也就是說,我們應(yīng)該用新的視角來看到Pod的宕機(jī)等問題,而非像使用物理機(jī),EC2等一樣,發(fā)生問題,可以快速重啟恢復(fù),這是一種思路上的轉(zhuǎn)變。
但這不意味著,OOM就變得正常了,OOM對(duì)于Java應(yīng)用來說,依然是比較關(guān)鍵的問題。一個(gè)應(yīng)用經(jīng)常發(fā)生OOM,可能是因?yàn)閮?nèi)存使用不對(duì),或者程序內(nèi)代碼有問題等等,我們依然需要去關(guān)注,去定位。但OOM在K8s下變得更不可控,也就是說概率變大了,因?yàn)閘imits無法保證,所以有時(shí)候,就需要重新思考這個(gè)問題。
K8s環(huán)境下是否適合使用大資源的pod?
是否可以使用大資源的Pod?當(dāng)然沒有問題,但是否合適,可曾想過?
我有見過8CPU_32GB,10CPU_20GB的應(yīng)用跑在k8s上,資源使用率實(shí)際上不是很高,幸好這樣的應(yīng)用不會(huì)很多。
從K8s的schedule的角度考慮,我們應(yīng)該使用小Pod,因?yàn)楸阌诒籹chedule。
從服務(wù)拆分的角度考慮,當(dāng)一個(gè)服務(wù)復(fù)雜到不得不用大資源運(yùn)行時(shí),應(yīng)該可以考慮拆分了。
從應(yīng)用運(yùn)行的角度考慮,不是采用一個(gè)大資源的Pod處理所有請(qǐng)求,而是將大資源的Pod拆分成多個(gè)小資源Pod均衡運(yùn)行。
Reference
https://openjdk.org/jeps/346
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/