Megosztás:


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ódtárá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 elkönyvelni:

  • 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. Futtassa a mintaalkalmazást a projekt gyökérkönyvtárának következő parancsával.

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

Az értékekre összpontosítva Last Delta ezekből megtudhatjuk dotnet.process.cpu.time, hogy a frissítési időszakon belül (jelenleg 1 s alapértelmezett értékre) hány másodperc volt aktív a PROCESSZOR. A webalkalmazás futtatása után közvetlenül az indítás után a processzor egyáltalán nem lesz felhasználva, és ezek a különbözetek mindkettő 0. Navigáljon az api/diagscenario/highcpu útvonalhoz 60000 útvonalparaméterként:

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 növelnie kell a processzorhasználatot (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álattal rendelkező alkalmazások elemzésekor egy diagnosztikai eszközre van szükség, amely betekintést nyújt a kód tevékenységébe. A szokásos választás egy profilkészítő, és különböző profilkészítő lehetőségek közül választhat. dotnet-trace minden operációs rendszeren használható, azonban a biztonságos és a csak felügyelt hívások korlátozásai általánosabb információkat eredményeznek, mint a kernelérzékeny profilkészítők, például a Linux esetében a "perf" vagy a Windows ETW. Ha a teljesítményvizsgálat csak felügyelt kódot tartalmaz, általában dotnet-trace elegendő lesz.

Az perf eszköz használható .NET Core-alkalmazásprofilok létrehozásához. Bemutatjuk ezt az eszközt, bár a dotnet-trace 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 map a fájl a CPU-címek JIT által létrehozott függvények név szerinti leképezésére szolgál perf . 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

Gyakorolja újra a magas CPU API-végpontot (https://localhost:5001/api/diagscenario/highcpu/60000). Amíg az 1 perces kérelemben fut, futtassa a parancsot a perf folyamatazonosító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