您好,登錄后才能下訂單哦!
ASP.NET Core應(yīng)用在Kubernetes上內(nèi)存使用率過高的問題分析,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
在生產(chǎn)環(huán)境中,我們把a(bǔ)sp.net core api應(yīng)用通過Kubernetes 部署在了Google Cloud (GCE—Google Container Engine)。我們發(fā)現(xiàn)大多數(shù)的組件(core應(yīng)用)的內(nèi)存使用率都不合理。我們把應(yīng)用的內(nèi)存限制設(shè)置成了500MB, 并且還發(fā)現(xiàn)了很多api應(yīng)用實(shí)例因?yàn)槌^了內(nèi)存限制而被Kubernetes 不斷的重啟(應(yīng)該docker設(shè)置了--restart)。
下面2張圖是我們其中的2個(gè)api,當(dāng)Kubernetes重啟他們時(shí),你會(huì)發(fā)現(xiàn)他們先是一直增長,然后到達(dá)了內(nèi)存限制的點(diǎn)。
針對于這個(gè)現(xiàn)象我們花了很多時(shí)間來調(diào)查這個(gè)issue,期間嘗試過通過抓dumps來分析,但是并沒有發(fā)現(xiàn)問題所在。
我們也嘗試使用多種方式,在我們的開發(fā)環(huán)境來復(fù)現(xiàn)這個(gè)問題:
in dev configuration in VS
on Windows with a production build
on Ubuntu with a production build
in Docker, using the actual production image
但是上述環(huán)境下,他們都沒有超過500mb的內(nèi)存使用情況,都是增長到100-150mb左右就停止了。
期間,為了減輕容器因?yàn)槌^限制的最大內(nèi)存而頻繁重啟我們將內(nèi)存限制從500mb增加到1000mb,在此之后,有趣的是內(nèi)存的使用情況變得如下圖所示:
測試下來發(fā)現(xiàn)內(nèi)存的使用并不是無限制的增大的,但是也是封頂600mb左右,并且這個(gè)數(shù)字在不同的容器實(shí)例以及實(shí)例重啟之后近乎保持一致。
這個(gè)現(xiàn)象清楚的表明我們的容器中的應(yīng)用并沒有內(nèi)存泄漏,只是有一塊內(nèi)存被分配了而沒有得到釋放。所以我開始把關(guān)注點(diǎn)轉(zhuǎn)移到“運(yùn)行在Kubernetes的.net程序是如何限制內(nèi)存的“。
事實(shí)上Kubernetes最終也是將程序運(yùn)行在docker容器中的,并且docker容器可以通過docker run --memory參數(shù)來限制內(nèi)存的使用。所以我懷疑也許是Kubernetes并沒有傳遞任何有關(guān)內(nèi)存限制的參數(shù)到docker容器實(shí)例中,所以.net程序理所當(dāng)然的認(rèn)為當(dāng)前機(jī)器有好多好多的可用內(nèi)存可以使用。
但是并不是這種情況,我們發(fā)現(xiàn)相反的內(nèi)容(因?yàn)樽髡邞岩墒荎ubernetes沒有傳遞和內(nèi)存相關(guān)的參數(shù))在the documentation.
The spec.containers[].resources.limits.memory is converted to an integer, and used as the value of the --memory flag in the docker run command.
(這句話的意思是Kubernetes的spec.containers[].resources.limits.memory會(huì)自動(dòng)沿用docker run中的--memory參數(shù)所設(shè)置的整數(shù)值)
這似乎又到了另一個(gè)死胡同了。我也嘗試在自己電腦里的docker中運(yùn)行api程序,并且通過--memory參數(shù)傳遞多種內(nèi)存限定值,但是1.我不能復(fù)現(xiàn)上述600mb內(nèi)存使用的場景,內(nèi)存只保持在150mb左右,2.也沒有觀察到容器實(shí)例運(yùn)行的超過它的內(nèi)存限制,即使我通過--memory參數(shù)來指定一個(gè)小于150mb的值,這個(gè)容器實(shí)例依然能夠在這個(gè)更小的內(nèi)存限定值下運(yùn)行的完好。
很早的時(shí)候我也在github上提過一個(gè)關(guān)于內(nèi)存泄漏的issue關(guān)聯(lián)到Kestrel(core的一個(gè)基于libuv的新的服務(wù)器),并且在這一點(diǎn)上,Tim Seaward發(fā)了一個(gè)有趣的suggestion關(guān)于檢查我的應(yīng)用在不同環(huán)境下所打印出的cpu的個(gè)數(shù),因?yàn)閏pu的是影響內(nèi)存使用的一個(gè)巨大因素。
我嘗試在代碼里通過Environment.ProcessorCount在不同的環(huán)境下打印出的數(shù)量如下:
On my machine, just doing dotnet run, the value was 4.
On my machine, with Docker, it was 1.
On Google Cloud Kubernetes it was 8.
這就能最終給我一個(gè)解釋了,因?yàn)閏pu的數(shù)量真的會(huì)影響內(nèi)存的使用數(shù)量。cpu核數(shù)越多,內(nèi)存使用量也就越多(對于作者來說,他還不是確切的了解gc的類型,cpu的核數(shù),與.net程序所使用內(nèi)存的大小之間的關(guān)系,雖然this post這個(gè)鏈接包含了有關(guān)GC的資料)。
最終的建議呢,就是把GC模式從Server GC(服務(wù)器模式)切換到Workstation GC(模式),這樣就能達(dá)到低內(nèi)存使用率的優(yōu)化效果。只需要在csproj項(xiàng)目文件中做如下動(dòng)作:
<PropertyGroup>
<ServerGarbageCollection>false</ServerGarbageCollection></PropertyGroup>
做了這個(gè)改動(dòng)后,重新發(fā)布我的api,結(jié)果就如鄉(xiāng)下所示(藍(lán)色的線):
workstation gc模式使得應(yīng)用對于內(nèi)存的使用變得更加”保守“,并且內(nèi)存的使用從大約600mb降低到了100到150mb之間。假設(shè)工作站模式是通過犧牲一些性能和吞吐量來實(shí)現(xiàn)這個(gè)”600mb到150mb的效果“話(據(jù)官當(dāng)服務(wù)器模式在某些場景下是相對優(yōu)于工作站模式的),但是迄今為止我并沒有發(fā)現(xiàn)任何api速度和吞吐量的衰減,雖然我的這個(gè)api并不是一個(gè)對性能有著及其苛刻的要求。
通過這個(gè)故事總結(jié)到:OS,可用內(nèi)存,cpu核數(shù)都是定位內(nèi)存問題的關(guān)鍵因素,因?yàn)樗麄儠?huì)大量影響想著.net的GC。如果你被問題卡住了,請不要猶豫的把問題拋出來,并且在很多.net 社區(qū)里面有很多極好的人會(huì)很樂于助人。
=============================================分割線
小弟我們公司下的項(xiàng)目也是這個(gè)問題,當(dāng)時(shí)困擾了好久,為什么呢,因?yàn)橹霸趙indows下面,內(nèi)存占用不會(huì)”太明顯“,因?yàn)镚C起到了決定性的作用,但是在core的環(huán)境下,在加之docker+linux,遇到這樣的時(shí)當(dāng)時(shí)一度懷疑是docker的問題,當(dāng)時(shí)也沒有像這位國外友人這樣去分析這個(gè)問題。通過這個(gè)問題我學(xué)到了如下:
1.學(xué)到了這位老哥定位思考問題的步驟,從是否是k8s的問題-》多環(huán)境問題-》github issue-》自己動(dòng)手去類比推測-》最終解決問題。
2.GC的知識點(diǎn)補(bǔ)充:this post
3.除此之外還有很多知識點(diǎn)都隱藏到了:suggestion(希望大家仔細(xì)再看看)
4.我沒記錯(cuò)的之前英文的官檔里,講項(xiàng)目配置文件的一節(jié)中提到了GC的配置
一開始(對GC的2種類型還不了解的情況),正常人看到這個(gè)true指的是激活該應(yīng)用程序的GC垃圾回收,而并沒有注意到老外所調(diào)查的結(jié)果(true其實(shí)是指的激活服務(wù)器GC模式,false不是指不GC,而是指的使用工作站GC模式),我能說微軟是否能夠稍微“貼心點(diǎn)”指出true和false的真正區(qū)別(其實(shí)是我們自己.net研究的還不夠透徹,哈哈哈),這樣就不會(huì)有像我,像這個(gè)老外一樣,對于跑在docker容器里的core應(yīng)用內(nèi)存占用率過高而表示“質(zhì)疑”。
我們生產(chǎn)已改成false,當(dāng)然true也沒問題,只不過服務(wù)器內(nèi)存被“只吃不拉”而已。
看完上述內(nèi)容,你們掌握ASP.NET Core應(yīng)用在Kubernetes上內(nèi)存使用率過高的問題分析的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。