.NET Core Performans İpuçları

.NET Core projelerinde sıkça kullanılan performans teknikleri, caching stratejileri ve memory yönetimi.

Bir ASP.NET Core uç noktası yük altında yavaşladığında işe ölçümle başlayın. İş parçacığı kuyruğunda bekleyen bir istek, SQL Server’da yavaş çalışan bir sorgu ve büyük bir JSON yanıtı kullanıcıya benzer biçimde yansıyabilir. Her birini düzeltmek için farklı bir değişiklik gerekir. Bu yazı, bir liste uç noktası üzerinden darboğazı bulmayı ve yaptığınız değişikliğin etkisini doğrulamayı anlatıyor.

Ölçülecek bir istek seçin

Örneğin ilk 25 ürünü gösteren bir katalog uç noktasını, üretime benzer veri hacmiyle çalıştırın. Isınma tamamlandıktan sonra aynı yük profiliyle p50 ve p95 yanıt sürelerini, hata oranını ve saniyede tamamlanan istek sayısını kaydedin. p95, isteklerin yüzde 95’inin hangi sürenin altında tamamlandığını gösterir. Ortalama sabit görünürken yavaş isteklerdeki artışı fark etmeye yardımcı olur.

API çalışırken dotnet-counters ile işlemci, GC ve ThreadPool sayaçlarını birlikte izleyin. ThreadPool kuyruğu büyüyor ve işlemci kullanımı düşük kalıyorsa, istek yolundaki senkron beklemeleri araştırın. Tahsis hızı ve GC sıklığı artıyorsa, örneğin yanıtı hazırlarken aynı verinin birden çok koleksiyona kopyalanıp kopyalanmadığına bakın. Sayaçlar sonraki incelemeyi yönlendirir. Darboğazı doğrulamak için ilgili kodu veya sorguyu ayrıca izleyin.

dotnet-counters ps
dotnet-counters monitor --process-id <PID> --counters System.Runtime

Giriş ve çıkış işlemlerini asenkron yürütün

Veritabanı ve HTTP çağrıları için sağlayıcının asenkron API’lerini kullanın. .Result ve .Wait() gibi senkron beklemeler, işlem bitene kadar istek iş parçacığını meşgul eder. Uç noktadan veri erişimine kadar asenkron ilerlemek ve isteğin CancellationToken değerini aşağıya geçirmek, yoğun yük ve iptal edilen isteklerde gereksiz çalışmayı azaltmaya yardımcı olur.

SQL’den dönen veri miktarını azaltın

Liste ekranı yalnızca kimlik, ad ve fiyat gösteriyorsa, EF Core sorgusunu bu alanlara projekte edin. Filtre ve sıralama tamamlanmadan ToListAsync çağırmak sorguyu erken çalıştırır ve sonraki işlemleri belleğe taşır. Aşağıdaki sorgu, sonuçları sabit bir sırayla sınırlar ve entity yerine ekranın ihtiyaç duyduğu alanları döndürür.

var products = await db.Products
    .Where(p => p.IsActive)
    .OrderBy(p => p.Id)
    .Select(p => new ProductListItem(p.Id, p.Name, p.Price))
    .Take(25)
    .ToListAsync(cancellationToken);

Sorgu hâlâ yavaşsa yürütme planını ve okunan satır sayısını inceleyin. İndeks seçimini gerçek filtre, sıralama ve veri dağılımına göre değerlendirin. DbContext havuzu ile SQL bağlantı havuzu ayrı mekanizmalardır. İlki bağlam örneklerini yeniden kullanır, ikincisi veritabanı sağlayıcısı düzeyinde fiziksel bağlantıları yeniden kullanır.

Önbelleği ölçtüğünüz iş yüküne göre seçin

Sık okunan ve kısa süre eski kalması kabul edilebilir veriler önbelleğe adaydır. Tek uygulama örneğinde IMemoryCache, birden fazla örneğin aynı kopyayı kullanması gereken akışta dağıtık önbellek düşünülebilir. Süreyi ve geçersizleştirme kuralını birlikte belirleyin. Önbellek eklendikten sonra isabet oranını, kaynak sorgu sayısını ve p95’i yeniden ölçün. Aynı yükte önce ve sonra karşılaştırması, sonraki değişikliğin nereye odaklanacağını gösterir.

Kaynaklar