TFS Dataserver記憶體問題分析

2022-05-02 20:51:09 字數 1772 閱讀 7108

12月03日03:50左右,有多台dataserver(ds)記憶體占用飆公升,如10.246.70.71 dataserver 3,常駐記憶體突然飆公升到21g,並且一直沒有釋放。

檢視dataserver的日誌,發現大量的read v2失敗 ,返回值主要是-8025(block不存在), -8016(檔案被刪除或隱藏)。但這些失敗資訊從0點開始一直很多,而且這兩種失敗不會導致ds分配很多記憶體,所以應該跟記憶體問題沒關係。

在3:50左右5分鐘內,發現readv2 success的日誌很多,主要集中在3:48,3:49,3:50這3分鐘內,3分鐘的readv2請求超過4w,平均每秒200+,每個檔案請求都是同乙個檔案的0-1m部分,請求**是imgsrc,每個imgsrc都請求多次。檢視被訪問的檔案,是乙個3m+的;同時明儼從imgsrc的日誌上發現,imgsrc多次從cdn節點接收到該檔案請求,最開始幾次讀取整個檔案成功,接下來在讀取0-1m的時候就超時了,於是imgsrc重試多次。從dataserver日誌上也發現網路佇列已經滿了,很多請求被丟棄了,由於排隊時間較長,很多請求在佇列中等待也超時了(5s);還有少量請求dataserver服務完了,但回給imgsrc時,imgsrc本地已經超時了(3s)。

在測試環境, 用了7臺機器,對同乙個1.4m左右的檔案使用readv2進行讀取,不斷加大每個機器上的程序數,加到50個程序時,ds的記憶體**比較明顯,第一次測試時,記憶體漲到48.1%(約4g)時停止客戶端,ds占用記憶體沒有下降,一直維持在48%左右。接下來準備用valgrind跑,查是否有記憶體洩露問題,但valgrind跑起來後,ds服務請求非常慢,每秒服務讀請求不到10個,壓力上不去,記憶體基本沒漲。

繼續壓測了幾次,觀察到如下現象:

把客戶端的readv2換成read,現象跟readv2類似; 對readv2裡分配、釋放的點加log,發現分配和釋放是完全正確配對的。把ptmalloc庫換成google的tcmalloc,現象也差不多。

向華庭請教了下,發現我們的場景很可能造成這個問題;ptmalloc收縮記憶體是從top chunk開始,如果與top chunk相鄰的chunk不能釋放,top chunk以下的chunk都無法釋放。

簡單的說,在乙個64m的記憶體單元裡,假設ds分配先後分配了記憶體1、2、3、4(假設1、2、3、4代表位址遞增的記憶體區間),然後1、2、3都釋放了,但4是一塊生命週期很長的記憶體,一直沒有釋放,這時1、2、3雖然被ds釋放了,但由於4沒有釋放(top chunk相鄰的),glibc不會把它們還給作業系統。

ds在服務讀請求時,分配的內存在請求服務完成後都會釋放記憶體,這些記憶體的生命週期都不會很長。但有些記憶體,比如logicblock,physicalblock等結構,一旦分配,只有block被刪除才會釋放記憶體,生命週期很長;所以在服務讀請求的過程中,一旦又分配了一塊生命週期很長的記憶體,就會導致前面分配的記憶體都無法歸還給作業系統。

把ptmalloc引數改動下,一旦分配超過default_mmap_threshold的記憶體,分配就直接mmap,釋放就直接munmap。把如下語句加到main函式的開始處

再壓測ds,發現ds的記憶體也一直公升高,但一旦停止客戶端或減小壓力,記憶體就會迅速降下來。至此,可以確定ds占用很多記憶體的確是由於ptmalloc沒有歸還給作業系統的原因。由於我們一台機器上要跑10+個ds,一旦壓力大,出現上述問題,勢必影響到所有ds的服務。

進一步測試了jemalloc庫,在大壓力下,ds記憶體也會迅速**,但壓力降下來後,jemalloc會將記憶體歸還給作業系統;簡單測試對比了jemalloc和glibc的ptmalloc,發現在多執行緒環境下,jemalloc的表現更勝一籌,後期我們會考慮在ds上使用jemalloc替代ptmalloc作為記憶體分配器。

TFS Dataserver常見問題總結

core檔案對問題查詢非常有幫助,大部分時候我們能根據core檔案直接定位到問題,但當出現記憶體亂掉的情況時,core的backtrace可能也不能指出問題源頭。最近線上問題較多,針對dataserver出現的問題做個總結 1.如果在read write時coredump,則多是因為磁碟故障 或是檔...

還是記憶體 記憶體

對於記憶體一點都不了解到現在感覺上已經蠻了解的,可是事實上又遇到麻煩了 實在是想不通,怎麼會出現問題呢?重新審視一下動態開闢記憶體的操作 1.對於函式以及函式內的臨時變數我們不需要考慮它們的記憶體空間,因為在函式執行結束的時候會自動釋放掉.真的是這樣的嗎?如果是這樣的話,對於固定陣列我若開闢乙個足夠...

《記憶體管理》 記憶體

1.c c 記憶體分布 我們先來看下面的一段 和相關問題 int globalvar 1 static int staticglobalvar 1 void test char char2 abcd char pchar3 abcd int ptr1 int malloc sizeof int 4 ...