Yüksek CPU problemi ve Exception'lar
Merhabalar,
Bugünki yazımda genelde load test esnasında yada canlı’ya alınmış sistemlerde yüksek yük altında kendini gösteren yüksek Cpu probleminin en önemli sebeplerinden birinden bahsetmek istiyorum.Yüksek Cpu probleminin elbette bir çok sebebi olabilir, fakat bunlardan en yaygın olanı belkide fırlatılan ‘Exception’ sayısının yüksek olmasıdır. Bu söylem, gerek web uygulaması gerek servis uygulaması olsun tüm .Net uygulamaları için geçerlidir diyebiliriz. Çünkü Exceptionlar genel olarak pahalı işlemlerdir.
Biz özellikle örneğimizi ASP.NET uygulaması üzerinden veriyor olacağız. Bir Asp.Net uygulamasını Performans açısından izlerken en azından aşağıdaki Counter’ların dikkate en alınmasını tavsiye ediyoruz:
- Processor(_Total)\% Processor Time
- Process(w3wp.exe)\% Processor Time
- Process(w3wp.exe)\Private Bytes
- Process(w3wp.exe)\Virtual Bytes
- Process(w3wp.exe)\Handle Count
- Microsoft® .NET CLR Exceptions\# Exceps thrown / sec
- ASP.NET\Application Restarts
- ASP.NET\Requests Rejected
- ASP.NET\Worker Process Restarts (not applicable to IIS 6.0)
- Memory\Available Mbytes
- Web Service\Current Connections
- Web Service\ISAPI Extension Requests/sec
Yukarıda belirttiğim Performans Counter’ları ile ilgili detaylı bilgi için, bu makaleyi referans alabilirsiniz. Makalede özellikle ASP.NET performans Counter’larının ‘Memory / CPU bound’ senaryolar için eşik değerleri belirtilmekte.
Şimdi tekrar Exception’lara dönelim. Eğer task manager’dan bir .net uygulamasının Cpu kullanım değerini yüksek görüyorsanız, öncelikle ‘.NET CLR Exceptions\# Exceps thrown / sec’ performans counter’ını gözden geçirmenizi tavsiye ediyorum. Bunun için belirlenmiş eşik değeri uygulamaya yapılan istek sayısının %5 ‘idir. Yani bir ASP.NET uygulamasında örneğin saniyede 5 Exception fırlatılıyorsa, yapılan istek sayısının yani "ASP.NET Applications\Requests/sec" counter değerinin 100 ‘den az olmamasını bekleriz.
Örneğin eğer yüksek CPU durumunda bu değerin 20 civarlarında seyrettiğini görüyorsak, Yüksek CPU’nun nedeninin fırlatılan Exception’lar dan kaynaklanma olasılığı oldukça yüksektir. Bu saptamayı yaptıktan sonra yapmamız gereken fırlatılan Exceptionlardan hangilerinin diğerlerine oranla daha sıklıkla fırlatıldığını belirlemektir. Bunun için yüksek CPU anını kapsayacak şekilde birer dakika aralıklarla 3-4 adet dump alabiliriz.
Dump almak için ‘Debugging Tools For Windows’ kurulumu yapabileceğiniz gibi vista ve sonrası (win 7, 2008, ...) işletim sistemlerinde Task mamanger’dan da ilgili process üzerine tıklayıp Context menüsünden ‘Create Full Userdump’ diyerek de dump alabilirsiniz.
Devamında, ardışıl dumpları windbg.exe ile açıp psscor eklentisini yükledikten sonra, en sık alınan exceptionları incelemek için !dae (Dump All Exceptions) komutunu kullanabiliriz. Şanslı isek aşağıdaki gibi belirli bir Exception’ın diğerlerin göre çok daha fazla sayıda fırlatıldığını görebiliriz. (yada daha da şanslı isek belki Şirinleri bile görebiliriz :) )
Örneğin aşağıdaki Sharepoint uygulaması dump’ında an itibari ile memory’de bulunan 400 adet 'ThreadAbortException’ı belirledikten sonra bu Exception’ın sebebine yoğunlaşabiliriz. Buradaki temel sebep 400 defa istemcilerin bağlantıyı kapatmasından dolayı Worker Thread’in abort edilmesi.
0:044> !dae
Going to dump the .NET Exceptions found in the heap.
…
Number of exceptions of this type: 400
Exception MethodTable: 000007fef3498210
Exception object: 00000001c46fb9a8
Exception type: System.Threading.ThreadAbortException
Message: Thread was being aborted.
InnerException: <none>
StackTrace (generated):
SP IP Function
000000001DF9D960 0000000000000001 System.Threading.Thread.AbortInternal()
000000001DF9D960 000007FEF33A441A System.Threading.Thread.Abort(System.Object)
000000001DF9D9B0 000007FEEB8F4B76 System.Web.HttpResponse.End()
000000001DF9DA00 000007FEEEADA9F1 Microsoft.SharePoint.Utilities.SPUtility.StopRequestIfClientIsNotValid(System.Web.UI.Page)
000000001DF9DA50 000007FEEF75551F Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase.OnInit(System.EventArgs)
000000001DF9DAA0 000007FEEB8FE5B0 System.Web.UI.Control.InitRecursive(System.Web.UI.Control)
000000001DF9DB00 000007FEEB8FAE96 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
StackTraceString: <none>
HResult: 80131530
-----------------
Total 570 exceptions
Yada ASP.NET uygulamalarında ThreadAbortException’ları Response.Redirect fonksiyonunu kullandığımız durumlarda da görebiliriz. Buda bizim sıklıkla karşılaştığımız durumlardan biri. Burada çözüm olarak HttpResponse.Redirect metodunun iki parametreli olan versiyonunu ‘HttpResponse.Redirect (String, Boolean)’ kullanarak aynı thread içerisinde thread abort edilmeden process işlenebilir. Fakat unutulmaması gereken istek işletildikten sonra Response.Redirect çağırılan kısımdan sonraki kod bloğununda işlenecek olmasıdır. (Devamında ‘return’ koyarak fonksiyonu sonlandırmak faydalı olabilir)
Farklı durumlarda yüksek CPU probleminin farklı Exception’lardan kaynaklandığını görebilirsiniz. Yukarıdaki örnekler bunlardan sadece ikisi. İlerleyen günlerde karşılaşabileceğimiz daha farklı Exceptionlar la ilgili örnekler vermeye çalışacağız.
İyi çalışmalar,
Mert Öztürk