[英]Service Fabric Stateful Service in Azure - RAM usage keeps growing. Possible memory leak
我在 Azure 的群集上運行 Service Fabric 應用程序。 集群有兩個規模集:
應用程序中有兩種類型的服務
對於我的測試,我使用 Application Insights 和 Service Fabric Analytics 來跟蹤性能。 我正在觀察以下參數:
有狀態規模集的指標:CPU 百分比、磁盤讀/寫操作數/秒
Applicaiton Insights:服務器響應時間 - 對應於在有狀態的 StatusConsumer 中接收狀態的方法的執行時間。
Service Fabric Analytics:有狀態節點上帶有日志分析代理的性能計數器 - 用於觀察節點的 RAM 使用情況。
每個模擬系統每 30 秒發送一次其狀態。
測試開始時,每個節點的RAM使用率在40%左右,Avg Server Response time在15ms左右,CPU使用率在10%左右,讀/寫操作在100/s以下。
測試開始后,RAM 使用量立即開始緩慢增加,但其他觀察到的指標沒有差異。
在模擬 1000 個系統大約一個小時后,RAM 使用率約為 90-95%,問題開始出現在其他指標中 - 平均服務器響應時間峰值約為 5-10 秒,磁盤讀/寫操作達到約 500/秒.
這會持續 1-3 分鍾,然后 RAM 使用量下降,一切恢復正常。
在圖像上,您可以看到 RAM 峰值對應於服務器響應時間峰值。 在 RAM 圖表的末尾,使用情況是平坦的,以便在不模擬任何系統的情況下顯示行為。
模擬的系統數量只會減少或增加 RAM 達到臨界水平所需的時間 - 在其中一項測試中,模擬了 200 個系統,RAM 使用率上升較慢。
至於代碼:在第一次測試中,代碼更復雜,但為了找到問題的原因,我開始刪除功能。 仍然沒有任何改善。 RAM 使用率沒有上升的唯一一次是當我注釋所有代碼並且在接收狀態的方法主體中只有一個 try/catch 塊和一個返回時。 目前 StatusConsumer 中的代碼是這樣的:
public async Task PostStatus(SystemStatusInfo status){
try{
Stopwatch stopWatch = new Stopwatch();
IReliableDictionary<string, SystemStatusInfo> statusDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, SystemStatusInfo>>("status");
stopWatch.Start();
using (ITransaction tx = this.StateManager.CreateTransaction())
{
await statusDictionary.AddOrUpdateAsync(tx,"lastConsumedStatus",(key) => { return status; },(key, oldvalue) => status);
await tx.CommitAsync();
}
stopWatch.Stop();
if (stopWatch.ElapsedMilliseconds / 1000 > 4) //seconds
{
Telemetry.TrackTrace($"Queue Status Duration: { stopWatch.ElapsedMilliseconds / 1000 } for {status.SystemId}", SeverityLevel.Critical);
}
}
catch (Exception e) {Telemetry.TrackException(e);}
}
我該如何診斷和/或解決這個問題?
PS:通過遠程桌面連接到節點后,在任務管理器中我可以看到,當 RAM 使用率在 85% 左右時,“持有”微服務實例的 SystemStatusConsumer 進程的“內存”不超過 600 MB。 這是最高的消耗,但仍然沒有那么高 - 節點具有 8 GB 的 RAM。 但是我不知道在這種情況下這是否是有用的信息。
在與 Azure 支持人員交談並進行了多次測試后,我大大減少了服務的內存消耗。
我從與支持人員的溝通中學到的主要事情是,擁有大量服務,每個服務都包含少量數據真的不是一個好主意! 應用程序的內存轉儲顯示,每個服務在 Service Fabric 積累的 Reliable Collections 中都有大約 20KB 的實際數據和 700KB 的更改日志。 這可能不是確切的數字,但差異很大。
為了減少服務數量,我通過使用一種分區將多個系統狀態的處理和保存合並到一個服務中。 我也嘗試使用演員。 所有方法都運行良好。
我還使用了其他幾個設置來減少內存消耗,但通過更改服務本身的架構產生了很大的不同:
在服務本身的 Settings.xml 中:
檢查點閾值InMB = 1
LogTruncationIntervalSeconds = 1200(將此值設置為小於 120 實際上不會做任何事情或使事情變得更糟。嘗試使用大於 300 的值)
MaxAccumulatedBackupLogSizeInMB = 1
在服務本身的代碼中:
ServicePointManager.DefaultConnectionLimit = 200
MaxConcurrentCalls = 512(RemotingListener 和客戶端)
集群設置:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.