Magas processzorhasználat hibakeresése a .NET Core-ban

Ez a cikk a következőre vonatkozik: ✔️ .NET Core 3.1 SDK és újabb verziók

Ebben az oktatóanyagban megtudhatja, hogyan lehet hibakeresést végezni egy túlzott processzorhasználati forgatókönyvben. A megadott példa ASP.NET Core webalkalmazás forráskód tárházával szándékosan okozhat holtpontot. A végpont nem válaszol, és tapasztalja a szál felhalmozódását. Megtudhatja, hogyan diagnosztizálhatja ezt a forgatókönyvet különböző eszközökkel a diagnosztikai adatok több kulcsfontosságú elemével.

Ebben az oktatóanyagban a következőket fogja megtanulni:

  • Magas processzorhasználat vizsgálata
  • Cpu-használat meghatározása dotnet-counters használatával
  • Dotnet-trace használata nyomkövetési generáláshoz
  • Profilteljesítmény a PerfView-ban
  • A túlzott processzorhasználat diagnosztizálása és megoldása

Előfeltételek

Az oktatóanyag a következőket használja:

CPU-számlálók

Az oktatóanyag megkísérlése előtt telepítse a dotnet-counters legújabb verzióját:

dotnet tool install --global dotnet-counters

Ha az alkalmazás a .NET 9-nél régebbi .NET-verziót futtat, a dotnet-számlálók kimeneti felhasználói felülete kissé eltérő lesz; részletekért lásd: dotnet-counters .

A diagnosztikai adatok gyűjtésének megkísérlése előtt magas CPU-kondíciót kell megfigyelnie. A projekt gyökérkönyvtárából futtassa a mintaalkalmazást a következő parancs segítségével.

dotnet run

Az aktuális processzorhasználat ellenőrzéséhez használja a dotnet-counters eszköz parancsot:

dotnet-counters monitor -n DiagnosticScenarios --showDeltas

A kimenetnek a következőhöz hasonlónak kell lennie:

Press p to pause, r to resume, q to quit.
    Status: Running

Name                                                            Current Value      Last Delta
[System.Runtime]
    dotnet.assembly.count ({assembly})                               111               0
    dotnet.gc.collections ({collection})
        gc.heap.generation
        ------------------
        gen0                                                           8               0
        gen1                                                           1               0
        gen2                                                           0               0
    dotnet.gc.heap.total_allocated (By)                        4,042,656          24,512
    dotnet.gc.last_collection.heap.fragmentation.size (By)
        gc.heap.generation
        ------------------
        gen0                                                     801,728               0
        gen1                                                       6,048               0
        gen2                                                           0               0
        loh                                                            0               0
        poh                                                            0               0
    dotnet.gc.last_collection.heap.size (By)
        gc.heap.generation
        ------------------
        gen0                                                     811,512               0
        gen1                                                     562,024               0
        gen2                                                   1,095,056               0
        loh                                                       98,384               0
        poh                                                       24,528               0
    dotnet.gc.last_collection.memory.committed_size (By)       5,623,808               0
    dotnet.gc.pause.time (s)                                           0.019           0
    dotnet.jit.compilation.time (s)                                    0.582           0
    dotnet.jit.compiled_il.size (By)                             138,895               0
    dotnet.jit.compiled_methods ({method})                         1,470               0
    dotnet.monitor.lock_contentions ({contention})                     4               0
    dotnet.process.cpu.count ({cpu})                                  22               0
    dotnet.process.cpu.time (s)
        cpu.mode
        --------
        system                                                         0.109           0
        user                                                           0.453           0
    dotnet.process.memory.working_set (By)                    65,515,520               0
    dotnet.thread_pool.queue.length ({work_item})                      0               0
    dotnet.thread_pool.thread.count ({thread})                         0               0
    dotnet.thread_pool.work_item.count ({work_item})                   6               0
    dotnet.timer.count ({timer})                                       0               0

A Last Deltadotnet.process.cpu.time értékeire összpontosítva megtudhatjuk, hogy hány másodpercig volt aktív a CPU a frissítési időszak alatt (jelenleg 1 mp az alapértelmezett érték). Amikor a webalkalmazás fut, közvetlenül az indítás után, a CPU egyáltalán nem kerül felhasználásra, és ezek az eltolódások mind 0. Navigáljon az api/diagscenario/highcpu útvonalra, az 60000 útvonalparamétert megadva.

https://localhost:5001/api/diagscenario/highcpu/60000

Most futtassa újra a dotnet-counters parancsot.

dotnet-counters monitor -n DiagnosticScenarios --showDeltas

Az alábbiakban látható módon a processzorhasználat növekedését kell látnia (a gazdagéptől függően eltérő processzorhasználat várható):

Press p to pause, r to resume, q to quit.
    Status: Running

Name                                                            Current Value      Last Delta
[System.Runtime]
    dotnet.assembly.count ({assembly})                               111               0
    dotnet.gc.collections ({collection})
        gc.heap.generation
        ------------------
        gen0                                                           8               0
        gen1                                                           1               0
        gen2                                                           0               0
    dotnet.gc.heap.total_allocated (By)                        4,042,656          24,512
    dotnet.gc.last_collection.heap.fragmentation.size (By)
        gc.heap.generation
        ------------------
        gen0                                                     801,728               0
        gen1                                                       6,048               0
        gen2                                                           0               0
        loh                                                            0               0
        poh                                                            0               0
    dotnet.gc.last_collection.heap.size (By)
        gc.heap.generation
        ------------------
        gen0                                                     811,512               0
        gen1                                                     562,024               0
        gen2                                                   1,095,056               0
        loh                                                       98,384               0
        poh                                                       24,528               0
    dotnet.gc.last_collection.memory.committed_size (By)       5,623,808               0
    dotnet.gc.pause.time (s)                                           0.019           0
    dotnet.jit.compilation.time (s)                                    0.582           0
    dotnet.jit.compiled_il.size (By)                             138,895               0
    dotnet.jit.compiled_methods ({method})                         1,470               0
    dotnet.monitor.lock_contentions ({contention})                     4               0
    dotnet.process.cpu.count ({cpu})                                  22               0
    dotnet.process.cpu.time (s)
        cpu.mode
        --------
        system                                                         0.344           0.013
        user                                                          14.203           0.963
    dotnet.process.memory.working_set (By)                    65,515,520               0
    dotnet.thread_pool.queue.length ({work_item})                      0               0
    dotnet.thread_pool.thread.count ({thread})                         0               0
    dotnet.thread_pool.work_item.count ({work_item})                   6               0
    dotnet.timer.count ({timer})                                       0               0

A kérelem teljes időtartama alatt a processzorhasználat a megnövekedett érték köré kerül.

Jótanács

A még magasabb processzorhasználat megjelenítéséhez ezt a végpontot egyszerre több böngészőlapon is gyakorolhatja.

Ezen a ponton nyugodtan mondhatja, hogy a processzor a vártnál magasabban fut. A probléma hatásainak azonosítása kulcsfontosságú az ok megtalálásához. A probléma okának megtalálásához a diagnosztikai eszközök mellett a magas processzorhasználat hatását is használjuk.

Magas processzorhasználat elemzése a Profilerrel

A magas processzorhasználatú alkalmazások elemzésekor használjon profilkészítőt a kód használatának megértéséhez. dotnet-trace collect Minden operációs rendszeren működik, de a biztonsági pont elfogultság és a csak felügyelt hívásvermek korlátozzák azt általánosabb információkra, mint egy kernelérzékeny profilozó, például a Windowshoz készült ETW vagy perf a Linuxhoz. Az operációs rendszertől és a .NET-verziótól függően továbbfejlesztett profilkészítési képességek érhetők el – részletes útmutatásért tekintse meg a platformspecifikus lapokat.

Használja dotnet-trace collect-linux (.NET 10+)

A .NET 10-en és újabb verziókon dotnet-trace collect-linux ajánlott profilkészítési módszer Linuxon. Az EventPipe és az operációsrendszer-szintű perf_events kombinálva egyetlen egységes nyomkövetést hoz létre, amely a felügyelt és a natív híváshívásokat is magában foglalja, mindezt anélkül, hogy a folyamat újraindítására lenne szükség. Ehhez rendszergazdai jogosultságok szükségesek, valamint a Linux kernel 6.4+ CONFIG_USER_EVENTS=y. Tekintse meg a collect-linux előfeltételeit a teljes követelményekhez.

Győződjön meg arról, hogy a minta hibakeresési cél a .NET 10 vagy újabb verziójára van konfigurálva, majd futtassa, és gyakorolja újra a magas processzorvégpontot (https://localhost:5001/api/diagscenario/highcpu/60000). Miközben az 1 perces kérés folyamatban van, futtassa a dotnet-trace collect-linux parancsot, hogy rögzítsen egy gépszintű nyomkövetést:

sudo dotnet-trace collect-linux

Futtassa körülbelül 20–30 másodpercig, majd nyomja le a Ctrl+C vagy az Enter billentyűt az adatgyűjtés leállításához. Az eredmény egy .nettrace fájl, amely tartalmazza mind a felügyelt, mind a natív hívásveremeket.

Nyissa meg a .nettracePerfView nézetet, és használja azokat a metódusokat, amelyek a legtöbb processzoridőt használják.

A natív futásidejű szimbólumok nyomkövetésben való megoldásáról további információt a szimbólumok lekérése natív futásidejű keretetekhez című témakörben olvashat.

Használja a perf-t

Az perf eszköz .NET Core-alkalmazásprofilok létrehozására is használható. Lépjen ki a hibakeresési mintapéldány előző példányából.

Állítsa be a DOTNET_PerfMapEnabled környezeti változót, hogy a .NET-alkalmazás hozzon létre egy map fájlt a /tmp könyvtárban. Ez a fájl a map a CPU-címek perf által JIT-előállított függvényekkel való név szerinti leképezésére szolgál. További információ: Perf térképek és jit-memóriaképek exportálása.

Futtassa a minta hibakeresési célt ugyanabban a terminál munkamenetben.

export DOTNET_PerfMapEnabled=1
dotnet run

Tesztelje újra a nagy CPU-terhelésű API-végpontot (https://localhost:5001/api/diagscenario/highcpu/60000). Amíg az 1 perces időkorláton belül fut, futtassa a perf parancsot a folyamatazonosítójával:

sudo perf record -p 2266 -g

A perf parancs elindítja a teljesítménygyűjtési folyamatot. Futtassa körülbelül 20–30 másodpercig, majd nyomja le a Ctrl+C billentyűkombinációt a gyűjtési folyamatból való kilépéshez. Ugyanezzel perf a paranccsal megtekintheti a nyomkövetés kimenetét.

sudo perf report -f

A lángdiagramot az alábbi parancsokkal is létrehozhatja:

git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg

Ez a parancs létrehoz egy olyan parancsot flamegraph.svg , amelyet a böngészőben tekinthet meg a teljesítményproblémák kivizsgálásához:

Flame graph SVG-kép

Magas cpu-adatok elemzése a Visual Studióval

Minden *.nettrace-fájl elemezhető a Visual Studióban. Linux *.nettrace-fájl Visual Studióban való elemzéséhez a *.nettrace fájlt a többi szükséges dokumentum mellett át kell vinnie egy Windows-gépre, majd nyissa meg a *.nettrace fájlt a Visual Studióban. További információ: Processzorhasználati adatok elemzése.

Lásd még

Következő lépések