Aracılığıyla paylaş


Laboratuvar 1.3 Kilitlenme sorununu giderme - Createdump aracıyla çekirdek kilitlenme dökümlerini yakalama

Şunlar için geçerlidir: .NET Core 2.1, .NET Core 3.1, .NET 5

Bu makalede, Linux'ta .NET Core kilitlenme dökümü dosyalarını yakalamak için createdump aracının nasıl kullanılacağı ve ardından kilitlenme sorununu tanılamak için lldb'nin nasıl kullanılacağı açıklanır.

Önkoşullar

Bu sorun giderme laboratuvarlarını izlemenin en düşük gereksinimi, düşük CPU ve yüksek CPU performans sorunlarını gösteren bir ASP.NET Core uygulamasına sahip olmaktır.

İnternet'te bu hedefe ulaşmak için birkaç örnek uygulama bulabilirsiniz. Örneğin, istenmeyen davranışları göstermek için Microsoft'un basit webapi örneğini indirip ayarlayabilirsiniz. Alternatif olarak, örnek proje olarak BuggyAmb ASP.NET Core uygulamasını da kullanabilirsiniz.

Bu serinin önceki bölümlerini izlediyseniz, aşağıdaki kurulumun hazır olması gerekir:

  • Nginx, iki web sitesini barındıracak şekilde yapılandırılmıştır:
    • İlki, myfirstwebsite ana bilgisayar üst bilgisini (http://myfirstwebsite) kullanarak istekleri dinler ve istekleri 5000 numaralı bağlantı noktasını dinleyen demo ASP.NET Core uygulamasına yönlendirir.
    • İkincisi, buggyamb ana bilgisayar üst bilgisini (http://buggyamb) kullanarak istekleri dinler ve istekleri 5001 numaralı bağlantı noktasını dinleyen ikinci ASP.NET Core örnek buggy uygulamasına yönlendirir.
  • Her iki ASP.NET Core uygulaması da sunucu yeniden başlatıldığında veya uygulama yanıt vermeyi durdurduğunda otomatik olarak yeniden başlatılan hizmetler olarak çalışıyor olmalıdır.
  • Linux yerel güvenlik duvarı etkinleştirilir ve SSH ve HTTP trafiğine izin verecek şekilde yapılandırılır.

Not

Kurulumunuz hazır değilse "2. Bölüm ASP.NET Core uygulamaları oluşturma ve çalıştırma" bölümüne gidin.

Bu laboratuvara devam etmek için Nginx'in arkasında çalışan en az bir sorunlu ASP.NET Core web uygulamanız olmalıdır.

Bu laboratuvarın hedefi

Otomatik olarak oluşturulan çekirdek döküm dosyaları, yönetilen durum bilgilerinin tümünü içermediğinden kullanışlı değildir. .NET Core çekirdek kilitlenme dökümü dosyalarını yakalamak için önerilen araç oluşturulurump.

Bu bölümde, createdump kullanarak kilitlenme dökümü dosyasını yakalamayı ve kilitlenme sorununu tanılamak için dosyayı lldb'de açmayı öğreneceksiniz.

createdump'u işlem sonlandırma sırasında çalışacak şekilde yapılandırma

Createdump her .NET Core çalışma zamanıyla birlikte otomatik olarak yüklenir.

createdump yapılandırma ilkesi belgelerinde açıklandığı gibi, ortam değişkenleri olan yapılandırma seçeneklerini ayarlayabilirsiniz. Bunlar createdump komutuna parametre olarak geçirilir. Desteklenen ortam değişkenleri şunlardır:

  • COMPlus_DbgEnableMiniDump: 1 olarak ayarlanırsa, sonlandırmadan sonra otomatik çekirdek dökümü oluşturmayı etkinleştirir. Varsayılan değer 0'dır.
  • COMPlus_DbgMiniDumpType: Bu, oluşturulacak mini döküm dosyasının türüdür. Bunun varsayılan değeri 2'dir (veya bir sabit listesi türüdürMiniDumpWithPrivateReadWriteMemory). Bu, oluşturulan döküm dosyasının GC yığınlarını ve bir işlemdeki tüm mevcut iş parçacıklarının yığın izlemelerini yakalamak için gerekli bilgileri içereceği anlamına gelir.
  • COMPlus_DbgMiniDumpName: Ayarlanırsa, döküm dosyası yolunu ve dosya adını oluşturmak için şablon olarak kullanın. PID, parametresi kullanılarak %d ada yerleştirilebilir. Varsayılan şablondur /tmp/coredump.%d. Bu ortam değişkenini kullanarak çıkış dizinini yapılandırabilirsiniz.
  • COMPlus_CreateDumpDiagnostics: 1 olarak ayarlanırsa, createdump aracı tanılama iletilerini (TRACE makro) etkinleştirir. Createdump beklendiği gibi çalışmıyorsa ve bellek dökümü dosyası oluşturmuyorsa bu ayar yararlı olabilir.

Bu değişkenlerle ilgili ayrıntıları createdump yapılandırma ilkesinde bulabilirsiniz.

Buradaki önemli değişken şu şekildedir COMPlus_DbgEnableMiniDump: . Bu ortam değişkenini 1 olarak ayarlamanız gerekir. Bu ortamı ayarlamak için birkaç yöntem vardır:

  • Uygulamanızın yapılandırma dosyasında ayarlayın.
  • export COMPlus_DbgEnableMiniDump=1 Ayarlamak için komutunu kullanın. Bu ayar, işletim sistemi yeniden başlatıldıktan sonra kalıcı olmaz. Bu nedenle, yeniden başlatmadan sonra ayarın etkin kalmasını istiyorsanız kalıcı olarak ayarlamanız gerekir.
  • ASP.NET Core hizmet birimi dosyasında ayarlayın.

Bu değişkenin ASP.NET Core hizmet birimi dosyasında ayarlanması en kolay yöntemdir. Bunun dezavantajı, hizmetin yeniden başlatılması gerektiğidir. Bu sorun giderme bölümünde, bu seçenek gösterilir.

Buggy uygulamasının hizmet dosyasını açın ve ortam değişkenini COMPlus_DbgEnableMiniDump=1 ekleyin. Bu, bu eğitimin önceki bölümlerinde birkaç kez yaptığınızla aynıdır.

Buggy komutunun ekran görüntüsü.

Yapılandırma değiştirildiğinden hizmet yapılandırmasını yeniden yüklemeniz gerekir. Ardından BuggyAmb hizmetini yeniden başlatın.

sudo komutunun ekran görüntüsü.

Bu değişiklikleri yaptıktan sonra kilitlenme sorununu yeniden oluşturun. createdump çalışıyorsa döküm dosyası coredump olarak /tmp/ dizinine yazılmalıdır.<PID>. Sorunu yeniden oluşturmak için aynı adımları izleyin:

  1. Kilitlenme 3'e tıklayın. Sayfa doğru şekilde yüklenir, ancak işlemin kilitlenmesi gerektiğini belirten yanlış bir ileti döndürür.
  2. Yavaş'ı seçin. Bu, ürün tablosu yerine bir "HTTP 502" yanıt kodu (hatalı ağ geçidi hatası) oluşturur.
  3. Sorun oluştuktan sonra sayfaların hiçbiri işlenmez ve 10-15 saniye boyunca aynı hata iletisini alırsınız.
  4. 10-15 saniye sonra uygulama düzgün çalışmaya başlar.

Artık /tmp dizininde bir çekirdek döküm dosyanız olmalıdır.

ll komutunun ekran görüntüsü.

Çekirdek döküm dosyanız yoksa, dosyayı doğru yapılandırdığınızdan buggyamb.service emin olun. Ayrıca hizmet yapılandırmasını yeniden yüklemeniz ve hizmeti yeniden başlatmanız gerekir.

Çekirdek döküm dosyasını lldb'de açma

Döküm dosyasını örnek çözümlemeyle birlikte izlemek üzere klasörünüze taşımanızı ~/dumps/ öneririz. Döküm dosyasını açmak için komutunu çalıştırın lldb --core ~/dumps/coredump.<10354>. Bu komutta , 10354 yer tutucusunu işleminizin PID'iyle değiştirin.

Not

Daha önce bir döküm dosyası açtıysanız ve lldb ile çalıştıysanız, sembolleri zaten ayarlamış ve SOS yüklemişsinizdir. Simgeleri yeniden indirmek zorunda kalmadan aynı .NET Core sürüm döküm dosyasını açabilirsiniz. Ancak, sembollerin henüz indirilmediğiniz farklı bir .NET Core sürüm döküm dosyası açarsanız, çözümlemeyi başlatabilmeniz için önce bu sürüme ait simgeleri indirmeniz gerekir.

Yönetilen çağrı yığınını görüntülemek için SOS clrstack komutunu çalıştırın. Sistem tarafından oluşturulan çekirdek döküm dosyasını kullanarak aynı komutu çalıştırdığınızda bir hatayla karşılaştığınızı unutmayın. Bu kez doğru yönetilen çağrı yığınını görmeniz gerekir.

lldb komutunun ekran görüntüsü.

Bu iyi bir başlangıç. Ancak, görüntülenen çağrı yığını hata ayıklama işlemimizin ana iş parçacığına aittir. Özel durumun oluştuğu iş parçacığı değildir.

Not

Windows üzerinde WinDbg'de bir kilitlenme dökümü dosyası açarsak, WinDbg kilitlenmeye neden olan iş parçacığını doğrudan seçer. Ancak lldb'de durum böyle değildir. lldb'de WinDbg, bellek dökümünü oluşturmak için hata ayıklayıcıyı tetikleyen iş parçacığını otomatik olarak seçmez.

Hata ayıklarken bu WinDbg davranışı yararlı olsa da, lldb'de bu özelliğin olmaması dünyanın sonu değildir. Bunun yerine, özel durumun nerede oluşturulabileceğini belirlemek için tüm iş parçacıklarını inceleyebilirsiniz. komutunu kullanarak thread list yerel iş parçacıklarını inceleyerek başlayın.

Döküm dosyasının oluşturulduğu sırada nelerin çalıştığını anlayabilmek için tüm iş parçacığı çağrı yığınlarını hızlı bir şekilde inceleyerek başlamak her zaman iyi bir fikirdir. İlk olarak komutunu içeren yerel iş parçacığı listesine thread list bakın.

Not

Listedeki (thread #1) ilk iş parçacığının yanındaki yıldız işareti (*) bunun etkin iş parçacığı olduğunu gösterir.

Liste komutunun ekran görüntüsü.

Yerel iş parçacığı incelemesi çok fazla bir şey ortaya koymuyor. Bu bir .NET Core uygulaması olduğundan, SOS clrthreads komutunu çalıştırarak CLR iş parçacıkları listesini inceleyin. Bu komut, uygulamada çalışan yönetilen iş parçacıklarını listeler.

clrthreads komutunun ekran görüntüsü.

Bu ekran görüntüsü tüm yönetilen iş parçacıklarını göstermiyor. Ancak, odaklanmanız gereken ayrıntılar ekran görüntüsünde listelenir. Thread #15 sistem günlüklerimizde gördüğümüz bir özel durum vardır.

İş parçacığı 15 bilgisinin ekran görüntüsü.

bu iş parçacığının çağrı yığınını inceleyin. Bunu yapmak için önce söz konusu yazışmayı seçmeniz gerekir. Çalıştıracağınız bellek dökümü analizinde, iş parçacığı numarası büyük olasılıkla farklı olacaktır. Etkin iş parçacığı olarak başka bir iş parçacığı seçmek için komutunu kullanın thread select ve lldb dbg iş parçacığı kimliğini geçirin. Örneğin, iş parçacığı 15'e geçmek için komutunu çalıştırın thread select 15 . Ardından, çalıştırdığınız her ardışık komut bu iş parçacığının bağlamında olur. Yerel çağrı yığınını görmek için (geri izleme) komutunu çalıştırın bt .

Select komutunun ekran görüntüsü.

Bu ekran görüntüsünde görebileceğiniz gibi, bu iş parçacığı kesinlikle kilitlenmeyi tetikleyen iş parçacığıdır.

  • PROCEndProcess ve PROCAbort() işlenmeyen bir özel durumdan sonra çağrılır.
  • POCCreateCrashDump bir kilitlenme dökümü .NET Core tarafından yazıldığını bildirir.

komutunu çalıştırarak yönetilen çağrı yığınını clrstack inceleyebilirsiniz. Ancak, bu çok fazla ortaya çıkmaz. pe Özel durum ayrıntılarını almak için komutunu çalıştırın.

pe komutunun ekran görüntüsü.

Bu bilgiler şunu gösterir: Yöntemindeki Crash3 sayfanızda LogTheRequest() A System.Net.HttpWebRequest tetikleniyor. Bu, sorunun bulunmasına yardımcı olacak önemli bir bilgidir. Peki HTTP isteğinin URL'sini bulmak istiyorsanız ne olacak? Devam etmek için, bu listeden daha fazla bilgi toplayıp toplayamayacağınızı görmek için yığında başvuruda bulunan nesneleri incelemeyi deneyin. Geçerli yığının sınırları içinde bulunan tüm yönetilen nesneleri görüntülemek için komutunu çalıştırın dso.

dso komutunun ekran görüntüsü.

Bu işe yaramaz. Hiçbir System.Net.HttpWebRequest örneği görmemeniz gerekir. Özel durumun örnekleri vardır ve bunu zaten incelediniz. Bu nedenle, bu komut nedenle ilgili yeni bilgiler sağlamadı.

Tüm yönetilen nesneler yönetilen bir yığında depolanır ve komutunu çalıştırarak dumpheapyönetilen yığına bakabiliriz. Herhangi bir parametre olmadan çalıştırmayın dumpheap çünkü komut yönetilen yığın içindeki tüm nesneleri (büyük bir liste) listeler. Bunun yerine komutunu kullanarak yığının istatistiklerini dumpheap -stat alabilirsiniz.

Komutunu aşağıdaki biçimde çalıştırarak istatistikleri daraltmak için bir taktik daha kullanabilirsiniz:

dumpheap -stat -type System.Net.HttpWebRequest

Aşağıdaki ekran görüntüsü, adında dizeyi System.Net.HttpWebRequest içeren yönetilen nesnelerin istatistiklerini görüntüler.

İstek bilgilerinin ekran görüntüsü.

Örnek uygulamada yönetilen yığında yalnızca bir System.Net.HttpWebRequest nesne vardır. Önceki listede, girdinin yanında görülen adres bu nesnenin HttpWebRequest bellekteki adresi değildir. Bunun yerine, türündeki System.Net.HttpWebRequestnesnelerin "yöntem tablosuna" karşılık gelen adrestir. Nesnelerin gerçek listesini almak için, bu yöntem tablosu (MT) adresini komutuna dumpheap aşağıdaki şekilde geçirebilirsiniz:

dumpheap -mt <address>

Örneğin, nesnesinin adresini bulmak için komutunu çalıştırın dumpheap -mt 00007f53623cb640 .

dumpheap komutunun ekran görüntüsü.

Artık sorunlu nesnenin adresini belirleyebilirsiniz. Bu örnekte, şeklindedir 00007f51300c0868. Bu adresi komutuna geçirerek nesnenin dumpobj özelliklerini araştırabilirsiniz. Bu, söz konusu nesnenin özelliklerini listeler. Bu örnekte, nesnesinin özelliklerini incelemek için komutunu çalıştırın dumpobj 00007f51300c0868 .

dumpobj komutunun ekran görüntüsü.

Not

Bir nesneyi araştırıyorsunuz System.Net.HttpWebRequest ve bu nesnenin özelliklerinden biri._requestUri Bu, türünde bir nesnedir System.Uri . URI'yi belirlemek istiyorsunuz. Bu nedenle, özelliğinin _requestUri adresini komutuna dumpobj geçirin

Nesnesinin adresini System.Uri kopyalayın ve yeniden kullanarak dumpobj araştırın. dumpobj 00007f51300bfbb8'i çalıştırın. Oluşturduğunuz bellek dökümü dosyasındaki nesnenin adresi kesinlikle farklı olacaktır. Listede özelliğini System.Urigörüntüler_string.

dumpobj2 komutunun ekran görüntüsü.

adresini _stringkopyalayın ve komutu buna karşı yeniden çalıştırın dumpobj . dumpobj 00007f51300bfb40'i çalıştırın. Sonuç aşağıdaki ekran görüntüsünde listelenmiştir.

dumpobj3 komutunun ekran görüntüsü.

Son olarak HttpWebRequest'in URL'sini bulabilirsiniz: http://buggyamb/Problem/Api/NotExistingLoggingApi. Adından da anlaşılacağı gibi, bu büyük olasılıkla uygulama içinde mevcut bir sayfa değildir.

Son olarak, kilitlenmenin nasıl meydana geldiğiyle ilgili teori aşağıdaki gibidir:

  • HttpWebRequest, Crash3 web sayfasındaki yönteminde LogTheRequest() var olmayan bir URL'ye yapılır.
  • Gerçek dünyadaki bir uygulamada, bu sorunu düzeltmenin çözümü, yapıldığında hataları HttpWebRequest işlemek olacaktır. Ancak bu durumda çözüm çok daha basittir: Var olmayan bir HttpWebRequest sayfaya istekte bulunmayın.

Bu noktada, kilitlenmeye neyin neden olduğu hakkında daha fazla sorunuz olmalıdır. Örneğin, Yavaş bağlantısını seçtikten sonra kilitlenme neden tetiklendi?

Kendiniz araştırmaya devam etmek için çekinmeyin. Atabileceğiniz bir sonraki önerilen adım, kök dizinin gcroot nerede olduğunu bulmak için nesne adresini kullanarak HttpWebRequest komutu çalıştırmaktır. Bu, kilitlenmenin nasıl oluştuğuna ilişkin bir resim geliştirmenize yardımcı olabilir.

Bu, laboratuvarın sonuca varıyor. Ctrl+C tuşlarına basın veya lldb hata ayıklayıcıdan çıkmak için komutunu kullanınq.

Sonraki adımlar

Lab 2.1 Linux'ta createdump kullanarak performans sorunlarını giderme