IIS'de barındırılan ServiceStack kullanılarak uygulanan bir API'miz var. API'nın yük testini gerçekleştirirken, yanıt sürelerinin iyi olduğunu, ancak sunucu başına yaklaşık 3.500 eşzamanlı kullanıcıyı vurduğumuzda hızla kötüleştiğini keşfettik. İki sunucumuz var ve bunları 7.000 kullanıcıyla vururken ortalama yanıt süreleri tüm uç noktalar için 500ms'nin altındadır. Kutular bir yük dengeleyicinin arkasındadır, bu yüzden sunucu başına 3.500 eşzamanlılık elde ederiz. Ancak toplam eşzamanlı kullanıcı sayısını artırdığımız anda yanıt sürelerinde önemli bir artış görüyoruz. Eşzamanlı kullanıcıları sunucu başına 5.000'e yükseltmek, uç nokta başına ortalama 7 saniyelik ortalama yanıt süresi sağlar.
Sunuculardaki bellek ve CPU oldukça düşüktür, hem yanıt süreleri iyi hem de kötüleştikten sonra. 10.000 eşzamanlı kullanıcıyla zirvede CPU ortalama% 50'nin hemen altındadır ve RAM 16'dan 3-4 GB civarındadır. Aşağıdaki ekran görüntüsü, toplam 10.000 eşzamanlı kullanıcıyla bir yük testi sırasında perfmondaki bazı anahtar sayaçları göstermektedir. Vurgulanan sayaç istek / saniyedir. Ekran görüntüsünün sağında, saniyedeki grafik başına isteklerin gerçekten düzensizleştiğini görebilirsiniz. Bu yavaş yanıt süreleri için ana göstergedir. Bu paterni görür görmez, yük testinde yavaş tepki süreleri görüyoruz.
Bu performans sorununu nasıl gideririz? Bunun bir kodlama sorunu mu yoksa yapılandırma sorunu mu olduğunu belirlemeye çalışıyoruz. Web.config veya IIS'de bu davranışı açıklayabilecek herhangi bir ayar var mı? Uygulama havuzu .NET v4.0 çalıştırıyor ve IIS sürümü 7.5. Varsayılan ayarlardan yaptığımız tek değişiklik, uygulama havuzu Kuyruk Uzunluğu değerini 1.000'den 5.000'e güncellemektir. Aspnet.config dosyasına aşağıdaki yapılandırma ayarlarını da ekledik:
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="5000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="5000" />
</system.web>
Daha fazla detay:
API'nın amacı, çeşitli harici kaynaklardan gelen verileri birleştirmek ve JSON olarak döndürmektir. Şu anda veri katmanındaki harici çağrıları önbelleğe almak için bir InMemory önbellek uygulaması kullanıyor. Bir kaynağa yapılan ilk istek, gerekli tüm verileri getirir ve aynı kaynak için sonraki istekler önbellekten sonuç alır. Önbellekteki bilgileri belirli aralıklarla güncelleyen bir arka plan işlemi olarak uygulanan bir 'önbellek çalıştırıcısı' var. Harici kaynaklardan veri alan kodun etrafına kilitleme ekledik. Dış kaynaklardan gelen verileri eşzamansız bir şekilde almak için hizmetleri de uyguladık, böylece uç nokta yalnızca en yavaş harici çağrı kadar yavaş olmalıdır (elbette önbellekte veri yoksa). Bu, System.Threading.Tasks.Task sınıfı kullanılarak yapılır.İşlem için mevcut iş parçacığı sayısı açısından bir sınırlama getirebilir miyiz?