私は、Kubernetesが最終的にそれを殺すまで、日中メモリを蓄えるwebsocketサーバーを持っています。 prometheous-net を使用して監視します。
# dotnet --info
Host (useful for support):
Version: 2.1.6
Commit: 3f4f8eebd8
.NET Core SDKs installed:
No SDKs were found.
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.6 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.6 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.6 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
しかし、リモートで接続して(createdump
を使用して)メモリダンプを取得すると、突然サービスが停止します...サービスを停止、再起動、または接続しているユーザーを失うことなく。写真の緑の線を見てください。
グラフを見ると、GCがすべての世代で定期的に収集されていることがわかります。
以下を使用してGCサーバーを無効にします。
<PropertyGroup>
<ServerGarbageCollection>false</ServerGarbageCollection>
</PropertyGroup>
GC Serverを無効にする前は、サービスはメモリをより高速に拡張するために使用されていました。現在、512Mbになるまで2週間かかります。
要求/応答方式でASP.NET Coreを使用する他のサービスでは、この問題は発生しません。これは、各接続が通常約10分間続くWebsocketを使用します...したがって、接続に関連するすべてのものは、Gen 2まで簡単に存続すると思います。
2つのポッドがあり、同じ動作を示していることに注意してください。その後、メモリダンプの取得により、メモリ使用量が1つ(緑)で突然減少します。
接続が失われたり、再起動したりすることはありません。
ヒープ:
(lldb) eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00007F8481C8D0B0
generation 1 starts at 0x00007F8481C7E820
generation 2 starts at 0x00007F852A1D7000
ephemeral segment allocation context: none
segment begin allocated size
00007F852A1D6000 00007F852A1D7000 00007F853A1D5E90 0xfffee90(268430992)
00007F84807D0000 00007F84807D1000 00007F8482278000 0x1aa7000(27947008)
Large object heap starts at 0x00007F853A1D7000
segment begin allocated size
00007F853A1D6000 00007F853A1D7000 00007F853A7C60F8 0x5ef0f8(6222072)
Total Size: Size: 0x12094f88 (302600072) bytes.
------------------------------
GC Heap Size: Size: 0x12094f88 (302600072) bytes.
(lldb)
無料のオブジェクト:
(lldb) dumpheap -type Free -stat
Statistics:
MT Count TotalSize Class Name
00000000010c52b0 219774 10740482 Free
Total 219774 objects
この動作についての説明はありますか?
問題は、RabbitMQへの接続でした。ライブのソートチャネルを使用していたため、RabbitMQ.Clientの「自動再接続」機能は、デッドチャネルに関する多くの状態を保持していました。 「自動再接続」機能の「特典」は必要なく、すべてが正常に動作するため、この構成をオフにしました。苦痛でしたが、基本的にはWindows展開をセットアップし、Windowsツール(この場合はJetbrains dotMemory)を使用して通常のメモリ分析プロセスを実行する必要がありました。 lldbの使用はまったく生産的ではありません。
免責事項:私は.NETウィザードではありません。
ただし、Kubernetesのベストプラクティスを実行するには、次の2つのことを行う必要があります。
アプリの適切なリソース制限を定義します。アプリが200MBを超えるメモリを必要としない場合は、リソース制限を定義して、アプリが利用可能なすべてのホストメモリを消費しないようにします。ただし、使用可能なメモリを取得するためのUnix APIは、プロセスが持つcgroupを処理できず、cgroupの内容に関係なく常にホストメモリを出力することに注意してください。
このリソース制限とは何かをアプリに伝えます。十分にメモリがあるため、アプリがメモリを解放する必要性を「感じない」ようです。ほとんどすべてのアプリケーションとフレームワークにも、消費される最大メモリを定義するスイッチがあります。アプリにこの制限を伝えると、メモリの負荷が「確認」され、フルGCが実行されます(ここで問題になる可能性があります)。