WCF Hizmeti Performans Ayarları

speed

    WCF serisi makalelerimde şimdiye kadar sizlerle sunucu hizmetinin ve bu hizmeti kullanacak bir istemcinin nasıl oluşturabileceğinizi paylaşmış, bir WCF hizmetinde örnek yönetiminin nasıl yapılabileceğini ve eşzamanlı veri gönderen bir istemcinin performansının nasıl arttırılabileceğini paylaşmıştım. Bu makalemde ise WCF hizmetimizi mercek altına alarak performansını/throughput’unu nasıl arttırabileceğimizi göreceğiz.

   Sunucu kaynaklarının etkin kullanımını sağlamak adına WCF hizmetleri varsayılan olarak 16 isteği/mesajı eşzamanlı işleyecek şekilde tasarlanmıştır. Bu durum, WCF hizmetinin bu değerin üzerinde gelen istekleri geri çevireceği anlamına gelmemekle birlikte bu değerin üzerindeki istekler hemen işlenmek yerine bir sırada bekletileceklerdir. Bu sayede uygulama sunucu kaynaklarını aşırı tüketerek sistemi tamamen yanıt veremez duruma düşürmezken, gelen istekleri de en uygun şekilde işleyebilecektir. Bu yapılandırma aynı zamanda da sisteme aşırı istek göndererek yanıt veremez duruma düşürülmeye çalışılan Denial of Service Error, DoS saldırılarına karşı sisteminizin korunmasını da sağlayacaktır.

   WCF hizmetinin ne kadar geniş bir yelpazedeki donanımlara sahip sunucularda çalışabileceği düşünülecek olursa varsayılan 16 isteği eşzamanlı işlemek kimi sunucularda sistem kaynaklarının verimli kullanımına engel olacaktır. İyi bir donanım ve ağ altyapısı olan sistemlerde yeterli kaynak olmasına karşın istemciler/son kullanıcılar sürekli bir yavaşlıktan, hatta zaman aşımından şikayet ediyor olabilir. HTTP üzerinden sunulan WCF hizmetlerinde, asenkron bir yapıya sahip olan web servis çağrılarında istemciler varsayılan olarak 60 saniye içerisinde gönderdikleri isteklere yanıt alamamaları durumunda istek kanalının kapatarak kullanıcıya zaman aşım hatası (TimeoutException) dönmektedirler. Bu durumda aşırı istek geldiği durumlarda sıraya alınan istek sayıları da hızla artarak yanıt verme süresini önemli oranda düşürecek, sıraya alınan istekler işlenip yanıt dönmeye fırsat bulamadan istemciler bağlantıları kapatarak zaman aşım hatası oluşturacaklardır. İşin daha da kötü yanı; sistem tamamen asenkron işlemesi nedeniyle istemcinin bağlantıyı kapatması süreci sunucu tarafında sonlandığı anlamına gelmeyeceğinden veri tutarsızlıkları oluşacaktır.

   Yukarıdaki gibi bir senaryoda WCF hizmetinin performans ayarlarına müdahale ederek sistemimize ve iş mantığımıza en uygun yapılandırmayı gerçekleştirmeliyiz. WCF hizmetlerinin performansı/throughput’u aşağıda yer alan üç noktaya müdahale edilerek düzenlenebilmektedir;

  • Maksimum eşzamanlı oturum sayısı (maxConcurrentSessions) : Transport seviyesinde (TCP, IPC v.b.) desteklenen maksimum oturum sayısıdır. Framework 3.0/3.5sp1’de varsayılan olarak 10, framework 4’te ise (100 * işlemci sayısı) değeri ile tanımlanmıştır. BasicHttpBinding gibi oturumun desteklenmediği binding’lerde bu değeri hiç bir etkisi olmayacaktır.

  • Maksimum eşzamanlı çağrı sayısı (maxConcurrentCalls) : Tüm hizmet örneklerinin toplamda kabul edeceği/işleyeceği maksimum eşzamanlı çağrı sayısıdır. Framework 3.0/3.5sp1’de varsayılan olarak 16, framework 4’te ise (16 * işlemci sayısı) değeri ile tanımlanmıştır. Bu değerin üzerindeki çağrılar sıraya alınarak bekletileceklerdir. Bu değeri yükselterek eşzamanlı olarak işleyebileceğiniz çağrıları/mesajları arttırabilirsiniz. Mesaj işlemenin önemli işlemci ve/veya hafıza kaynağı tükettiği sistemlerde gelen mesajların sisteminizde oluşturduğu yük ve sunucu yapılandırması göz önüne alınarak değiştirilmesi doğru olacaktır.

  • Maksimum eşzamanlı örnek sayısı (maxConcurrentInstances) : Hizmet içerisinde bulunabilecek maksimum InstanceContext nesne sayısıdır. Varsayılan olarak sınırsız (gerçekte ise bu değerin bir tam sayı olması nedeniyle Int32.Max) değeri ile tanımlanmıştır.

   Yukarıda sizinle paylaştığım değerler ile bir WCF hizmetinin performansını/throughput’unu değiştirmek, hizmet kodundan geliştirmekten tamamen ayrı bir süreçtir. Sunucudan sunucuya değişkenlik gösterebilen bu değerler gerçek hayatta yazılım ekibinden ziyade deployment ekibince yönetilmelidir. Bu sebeple bu değerler hizmet üzerine yerleştirilen bir öznitelikle yapılamamaktadır/yapılmamalıdır (her ne kadar yapılması mümkün olsa bile..). Bu konudaki genel yaklaşım yapılandırma dosyası içerisinde hizmet tanımlaması yapılırken belirtilmesi yönündedir. Bazı istisnai senaryolarda bu işlemin kod içerisinden de yapılması gerekebileceğini göz önüne alarak her iki yöntemi de sizlerle paylaşıyor olacağım.

   Öncelikle bu değerleri yapılandırma dosyası içerisinde nasıl ayarlayabileceğimizi birlikte görelim. Örnek olarak WCF’e Giriş makalemde sizlerle paylaştığım örnek hizmet ve yapılandırma üzerinden gidiyor olacağım. Hizmet performansının yapılandırma dosyası içerisinde ayarlanabilmesi için bize serviceThrottling yapılandırma elementi sunulmuştur. Servisimizin davranışlarını tanımladığımız behaviors -> serviceBehaviors düğümü altındaki ilgili behavior düğümü içerisine aşağıdaki gibi bu elementi ekleyebilir, element içerisindeki maxConcurrentCalls, maxConcurrentInstances ve maxConcurrentSessions değerleri ile iş mantığımız doğrultusunda oynayabiliriz:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service
        name="Com.Enterprisecoding.WCF.Ornek.OrnekHizmet"
        behaviorConfiguration="metaVeriDestegi"
      >
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/WCFOrnekleri" />
          </baseAddresses>
        </host>
        <endpoint
          address="OrnekHizmet"
          binding="wsHttpBinding"
          contract="Com.Enterprisecoding.WCF.Ornek.IOrnekHizmet"
        />
        <endpoint
           address="mex"
           binding="mexHttpBinding"
           contract="IMetadataExchange"
        />
      </service>
    </services>
 
    <behaviors>
      <serviceBehaviors>
        <behavior name="metaVeriDestegi">
          <serviceMetadata httpGetEnabled="true"  httpGetUrl=""/>
  <serviceThrottling
                    maxConcurrentCalls="16"
                    maxConcurrentInstances="2147483647"
                    maxConcurrentSessions="10"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

   Örneğimizin 31. ve 34. satırları arasında gördüğünüz gibi hizmetimizin performans değerlerini değiştirmek oldukça kolay.  Her ne kadar örneğimizde her üç değer içinde birer girdi eklemiş olsakta, gerçek hayatta sadece değiştirmek istediğiniz değer için bir girdi eklemeniz yeterli olacaktır.

   Aynı yapılandırma dosyasından performans ayarları yapmakta olduğu gibi kod içerisinden performans ayarı yapmak oldukça kolaydır. Programsal Olarak WCF Hizmeti Oluşturma makalemde sizlerle paylaşmış olduğum kodlar üzerinden gidecek olursak; hizmet sunucumuza eklediğimiz hizmetMetaVeriDavranisi’mızdan hemen ardından ServiceThrottlingBehavior sınıfı vasıtasıyla performans davranışımızı ekleyebiliriz;

Console.WriteLine("Hizmet sunucusu hazırlanıyor...");
Uri hizmetTemelAdresi = new Uri("http://localhost:1234/WCFOrnekleri");
 
ServiceHost hizmetSunucusu = new ServiceHost(typeof(OrnekHizmet), hizmetTemelAdresi);
 
try {
    hizmetSunucusu.AddServiceEndpoint(typeof(IOrnekHizmet), new WSHttpBinding(), "OrnekHizmet");
 
    ServiceMetadataBehavior hizmetMetaVeriDavranisi = new ServiceMetadataBehavior { HttpGetEnabled = true };
    hizmetSunucusu.Description.Behaviors.Add(hizmetMetaVeriDavranisi);

    var throttlingDavranisi = new ServiceThrottlingBehavior {
MaxConcurrentCalls = 16,
MaxConcurrentInstances = Int32.MaxValue,
MaxConcurrentSessions = 10
};

    hizmetSunucusu.Description.Behaviors.Add(throttlingDavranisi);
 
    Console.WriteLine("Hizmet sunucusu başlatılıyor...");
    hizmetSunucusu.Open();
 
    Console.WriteLine("Hizmet sunucusu hazır");
    Console.WriteLine("Hizmet sunucusunu sonlandırmak için herhangi bir tuşa basınız");
    Console.ReadKey();
 
    hizmetSunucusu.Close();
}
catch (Exception ex) {
    Console.WriteLine("Hizmet sunucusunda hata oluştu: {0}", ex.Message);
 
    if (hizmetSunucusu.State != CommunicationState.Closed || hizmetSunucusu.State != CommunicationState.Closing) {
        hizmetSunucusu.Abort();
    }
 
    Console.WriteLine("Uygulamayı sonlandırmak için herhangi bir tuşa basınız");
    Console.ReadKey();
}

   Yukarıdaki kod içerisinde 12. ve 18. satırlar arasında uygulamamıza daha önce de yapılandırma dosyasında eklemeyi örneklediğim performans değerleri verilmekte.

   Programsal olarak uygulamanızı çeşitli katmanlara ayırmış ve yukarıdakinden farklı bir şekilde WCF hizmetinizi parçalar halinde fonksiyon çağrıları ile oluşturuyorsanız size tavsiyem olası bir hatayı engellemek adına öncelikle hizmetinize ServiceThrottlingBehavior davranışınızın eklenip eklenmediğini kontrol etmeniz. Bunun için  öncelikle hizmetinizde yer alan davranışlar içerisinde ServiceThrottlingBehavior davranışının bulunup bulunmadığını sorgulamalı, varsa değerlerini güncellemeli, yoksa yeni değerlerle bir tane oluşturarak eklemelisiniz;

var throttlingDavranisi = hizmetSunucusu.Description.Behaviors.Find<ServiceThrottlingBehavior>();

if (throttlingDavranisi == null) {
throttlingDavranisi = new ServiceThrottlingBehavior();
}
else {
hizmetSunucusu.Description.Behaviors.Remove(throttlingDavranisi);
}

throttlingDavranisi.MaxConcurrentCalls = 16;
throttlingDavranisi.MaxConcurrentInstances = Int32.MaxValue;
throttlingDavranisi.MaxConcurrentSessions = 10;

hizmetSunucusu.Description.Behaviors.Add(throttlingDavranisi);

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# konusundan Microsoft tarafından dört yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz.
vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir