Aracılığıyla paylaş


.NET Core'da yüksek CPU kullanımında hata ayıklama

Bu makale şunlar için geçerlidir: ✔️ .NET Core 3.1 SDK ve sonraki sürümler

Bu öğreticide, aşırı CPU kullanımı senaryosunda hata ayıklamayı öğreneceksiniz. Core web uygulaması kaynak kodu deposu ASP.NET sağlanan örneği kullanarak, kasıtlı olarak kilitlenmeye neden olabilirsiniz. Uç nokta yanıt vermeyi durdurur ve iş parçacığı birikimiyle karşılaşır. Bu senaryoya tanılama verilerinin birkaç önemli parçasıyla tanılamak için çeşitli araçları nasıl kullanabileceğinizi öğreneceksiniz.

Bu öğreticide şunları yapacaksınız:

  • Yüksek CPU kullanımını araştırma
  • dotnet-counters ile CPU kullanımını belirleme
  • İzleme oluşturma için dotnet-trace kullanma
  • PerfView'da profil performansı
  • Aşırı CPU kullanımını tanılama ve çözme

Önkoşullar

Öğreticide aşağıdakiler kullanılır:

CPU sayaçları

Bu öğreticiyi denemeden önce lütfen dotnet-counters'ın en son sürümünü yükleyin:

dotnet tool install --global dotnet-counters

Uygulamanız .NET 9'dan daha eski bir .NET sürümü çalıştırıyorsa dotnet-counters çıkış kullanıcı arabirimi biraz farklı görünür; Ayrıntılar için dotnet-counters bölümüne bakın.

Tanılama verilerini toplamaya çalışmadan önce yüksek BIR CPU koşulu gözlemlemeniz gerekir. Proje kök dizininden aşağıdaki komutu kullanarak örnek uygulamayı çalıştırın.

dotnet run

Geçerli CPU kullanımını denetlemek için dotnet-counters tool komutunu kullanın:

dotnet-counters monitor -n DiagnosticScenarios --showDeltas

Çıkış aşağıdakine benzer olmalıdır:

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

değerlerine Last Deltadotnet.process.cpu.timeodaklanan bu değerler, yenileme süresi içinde (şu anda varsayılan olarak 1 sn olarak ayarlanmıştır) CPU'nun kaç saniye etkin olduğunu gösterir. Web uygulaması çalışırken, başlangıçtan hemen sonra CPU hiç tüketilmiyor ve bu değişimlerin ikisi de 0. api/diagscenario/highcpu yol parametresi olarak ile 60000 yola gidin:

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

Şimdi dotnet-counters komutunu yeniden çalıştırın.

dotnet-counters monitor -n DiagnosticScenarios --showDeltas

Aşağıda gösterildiği gibi CPU kullanımında bir artış görmeniz gerekir (konak makineye bağlı olarak değişen CPU kullanımı beklenmelidir):

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

İsteğin süresi boyunca CPU kullanımı, artan değerin etrafında dolanır.

Tavsiye

Daha da yüksek bir CPU kullanımını görselleştirmek için bu uç noktayı aynı anda birden çok tarayıcı sekmesinde kullanabilirsiniz.

Bu noktada, CPU'nin beklediğinizden daha yüksek çalıştığını güvenle söyleyebilirsiniz. Sorunun etkilerini belirlemek, nedeni bulmanın anahtarıdır. Sorunun nedenini bulmak için tanılama araçlarına ek olarak yüksek CPU tüketiminin etkisini kullanacağız.

Profil Oluşturucu ile Yüksek CPU'ları Analiz Etme

Yüksek CPU kullanımına sahip bir uygulamayı analiz ederken, kodun ne yaptığına ilişkin içgörüler sağlayabilen bir tanılama aracına ihtiyacınız vardır. Her zamanki seçim bir profil oluşturucudur ve aralarından seçim yapabileceğiniz farklı profil oluşturucu seçenekleri vardır. dotnet-trace tüm işletim sistemlerinde kullanılabilir, ancak güvenli nokta sapmaları ve yalnızca yönetilen çağrı yığınları sınırlamaları Linux için 'perf' veya Windows için ETW gibi çekirdek kullanan bir profil oluşturucuya kıyasla daha genel bilgiler sağlar. Performans araştırmanız yalnızca yönetilen kod içeriyorsa, genel olarak dotnet-trace yeterli olacaktır.

Araç perf , .NET Core uygulama profilleri oluşturmak için kullanılabilir. Dotnet-trace de kullanılabilse de bu aracı göstereceğiz. Örnek hata ayıklama hedefinin önceki örneğinden çıkın.

.NET uygulamasının DOTNET_PerfMapEnabled dizinde bir map dosya oluşturmasına neden olacak ortam değişkenini /tmp ayarlayın. Bu map dosya, CPU adreslerini ada göre JIT tarafından oluşturulan işlevlere eşlemek için tarafından perf kullanılır. Daha fazla bilgi için bkz . Performans haritalarını ve jit dökümlerini dışarı aktarma.

Örnek hata ayıklama hedefini aynı terminal oturumunda çalıştırın.

export DOTNET_PerfMapEnabled=1
dotnet run

Yüksek CPU API uç noktasını (https://localhost:5001/api/diagscenario/highcpu/60000) yeniden kullanın. 1 dakikalık istek içinde çalışırken, komutu işlem kimliğiniz ile çalıştırın perf :

sudo perf record -p 2266 -g

komutu perf performans toplama işlemini başlatır. Yaklaşık 20-30 saniye çalışmasına izin verin, ardından toplama işleminden çıkmak için Ctrl+C tuşlarına basın. İzlemenin çıkışını görmek için aynı perf komutu kullanabilirsiniz.

sudo perf report -f

Aşağıdaki komutları kullanarak bir alev grafiği de oluşturabilirsiniz:

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

Bu komut, performans sorununu araştırmak için tarayıcıda görüntüleyebileceğiniz bir flamegraph.svg oluşturur:

Alev grafiği SVG görüntüsü

Visual Studio ile Yüksek CPU Verilerini Çözümleme

Tüm *.nettrace dosyaları Visual Studio'da analiz edilebilir. Visual Studio'da bir Linux *.nettrace dosyasını analiz etmek için, *.nettrace dosyasını, diğer gerekli belgelere ek olarak bir Windows makinesine aktarın ve ardından *.nettrace dosyasını Visual Studio'da açın. Daha fazla bilgi için bkz. CPU Kullanım Verilerini Çözümleme.

Ayrıca bakınız

Sonraki Adımlar