Makale Özeti

Bir thread yardımıyla ardıl şekilde bir WCF hizmetine, bir url'ye veri göndermeye çalıştığınızda kısa bir sürede zaman aşımı hataları ile karşı karşıya kalırsınız. Bu makalemde bu hatanın nedenini sizlerle paylaşarak bu sorunu nasıl aşabileceğinizi gösteriyorum.

Makale

   C# ile bir WCF istemcisi oluşturarak bir web hizmetine ardıl olarak veri gönderiyorsanız ya da WebRequest sınıfı yardımıyla bir url'den yine ardıl olarak veri transfer ediyorsanız makalemi okumanızı tavsiye ederim.

   Yoğun olarak bir web hizmetinden veri alıyor/gönderiyorsanız mutlaka başınıza gelmiştir; kimi zaman ardıl olarak yaptığınız istekler, karşı sistem hizmetlerinde hiç bir sıkıntı olmamasına karşın, belirli bir istek sayısından sonra zaman aşımına düşebiliyor. Bu durumda pek çok yazılımcı -doğal olarak :)- sorunun kaynağı olarak karşı sistemi gösterecektir; fakat araç yardımıyla network dinlenerek giden/gelen paketler takip edildiğinde gerçek durumun çok farklı olduğu görülecektir.

   Network trafiği takip edildiğinde, özellikle thread kullanılarak web hizmetlerine yoğun veri gönderen istemci uygulamalarının aynı anda aynı adrese en fazla iki istek yapabildiği görülecektir. Eğer uygulamanız bir masaüstü uygulaması değil de bir ASP.Net uygulaması ise, biraz daha şanslısınız; ASP.Net uygulamaları varsayılan olarak aynı anda aynı adrese en fazla 10 istek yapabilmektedir. Bu durumda da varsayılan olarak tanımlı olan bu değerin üzerindeki istekler .Net framework tarafından sırası gelene kadar bir kuyrukta bekletilmektedir. Çok istek yapılması ya da karşı web hizmetinin yavaş yanıt vermesi gibi sebeplerle bu kuyrukta bekleyen isteklerin sayısının artması beraberinde isteklerin zaman aşımına uğramasına neden olacaktır; çünkü .Net framework varsayılan olarak, oluşturulan bir web isteğinin 1 dakika içerisinde yanıt alamaması durumunda bağlantıyı kapatır. Sorunun çözümü için belki de akla gelen ilk müdahale bu zaman aşım süresinin arttırılması olacaktır ve bir noktaya kadar da bu yöntem işe de yarayacaktır; fakat bu altta yatan asıl soruna yüzeysel bir yaklaşımdan başka bir şey değildir. Bu durumu öksürük şikayetiyle doktora giden bir hastaya sadece öksürük şurubu verilmesine benzetebiliriz; ilaç geçici olarak şikayeti keser fakat asıl rahatsızlığı çözmekten uzaktır.

   Bu durumu nasıl çözebileceğimizi yazımın devamında sizlerle paylaşıyor olacağım; fakat isterseniz çözüme geçmeden önce neden böyle bir durumla karşı karşıya kaldığımıza bir bakalım. Bir url'ye aynı anda yapılan istek sayısının varsayılan olarak değerinin 2 olması tabiki bir tesadüf değildir; bu değer, günümüzde internet ve intranet'te kullandığımız pek çok standardı belirleyen W3C organizasyonunca belirlenmiştir. W3C organizasyonunca Hypertext Transfer Protocol (HTTP) 1.1 sürümüne ait RFC 2616'da bağlantıları açıklayan 8. bölümde karşı sistemin yanıt verebilir olabilmesi adına tek kullanıcılı istemcilerin aynı sunucu ve/veya proxy'ye 2'den fazla bağlantı açmaması gerektiği belirtilmiştir. Birden çok kullanıcıya hizmet veren sistemler için ise (örneğin; asp.net ile yazılmış bir web uygulaması), bu sınır aktif kullanıcı sayısının iki katı olarak belirlenmiştir. Bu doğrultuda geliştirilen .Net Framework kütüphaneleri de W3C'in ilgili tanımlamalarına bağlı kalarak aynı anda aynı adrese yapılabilecek varsayılan maksimum istek sayısını masaüstü uygulamalarında 2, ASP.Net uygulamalarında ise 10 olarak belirlemiştir. Tabi ki bu değerler keskin çizgilerle çizilmiş sınırlar olmayıp istendiği takdirde yapılandırma dosyası ya da kodla değiştirilebilmektedirler.

   Sorunumuzun neden kaynaklandığını öğrendik, güzel, peki ben bu varsayılan değerleri nasıl değiştirebilirim? Bu soruya iki farklı yöntemle yanıt verilebilir: yapılandırma dosyası üzerinden ya da programsal olarak kodumuz içerisinden.

   İsterseniz öncelikle bu değerleri yapılandırma dosyasın üzerinden nasıl değiştirebileceğimizi görelim. Maksimum bağlantı değerleri uygulama yapılandırma dosyasında network ayarlarının toplandığı system.net düğümü altında yer connectionManagement başlığı altında toplanmıştır. connectionManagement altında tüm url'ler için tek bir maksimum bağlantı değeri tanımlanabileceği gibi her bir bir url için ayrı ayrı da tanımlama yapabilmek mümkündür. Adres (address) ve maksimum bağlantı (maxconnection) değer ikilisini vererek yapabileceğimiz bu tanımlamalarda adres alanına koyacağımız * karakteri ile, aksi belirtilmediği sürece tüm adresler için bu değerin kullanılacağını belirtmiş oluruz. Aşağıda yapılandırma dosyasında yer alan örnek bir tanımlama bulabilirsiniz;

<configuration>
    <system.net>
        <connectionManagement>
            <add address="*" maxconnection="5" />
            <add address="http://www.enterprisecoding.com" maxconnection="10" />
            <add address="http://79.98.134.244" maxconnection="10" />
        </connectionManagement>
    </system.net>
</configuration>

   Yapılandırma dosyası içerisindeki connectionManagement başlığı altında add dışında clear ve remove girdileri de kullanılabilmektedir. Hiyerarşik olarak kalıtılabilen yapılandırma dosyalarında bazı durumlarda üstten kalıtılarak gelmiş olan maksimum bağlantı değerlerinin kısmen ya da tamamen kaldırmak isteyebiliriz. Bu gibi durumlarda connectionManagement altına ilk girdi olarak eklenen clear elementi ile önceki tüm tanımlamalar silinebileceği gibi remove elementi ile sadece belirli bir adrese ait tanımlamanın da silinmesi mümkündür. Aşağıdaki örnekte, bir önceki örneğimizde farklı olarak, katılılarak gelen tüm maksimum bağlantı değerleri temizlenerek yeniden tanımlama yapılmaktadır;

<configuration>
  <system.net>
    <connectionManagement>
      <clear/>
      <add address="http://www.enterprisecoding.com" maxconnection="10" />
      <add address="http://79.98.134.244" maxconnection="10" />
    </connectionManagement>
  </system.net>
</configuration>

   Bu örneğimiz ise; kalıtılarak gelmiş maksimum bağlantı değerlerinden sadece http://www.enterprisecoding.com adresine ait tanımlama kaldırılmaktadır;

<configuration>
  <system.net>
    <connectionManagement>
      <remove name="http://www.enterprisecoding.com" />
    </connectionManagement>
  </system.net>
</configuration>

   connectionManagement başlığı altına add, remove ve clear elementlerinin iş mantığınız doğrultusunda birlikte kullanılması da mümkündür.

   Yapılandırma dosyası üzerinden maksimum bağlantı değerlerini ayarlamak gördüğünüz gibi zor değil; fakat bazı senaryolar için pek de doğru çözüm olmayabilir. Uygulamanızın kurulu olduğu uygulama sunucusunun işlemci sayısı ile doğru orantılı olarak daha fazla istek işleyebileceğini/gönderebileceğini düşünecek olursak, yapılandırma dosyasında sabit verilen değerler yerine uygulama sunucunun yapılandırmasına bağlı olarak değişen bir yapılandırma her zaman için tercih edilecektir. Bu gibi senaryolarda başvurulması gereken yöntem ise bu değerlerin kodumuz içerisinde verilmesidir.

   .Net framework içerisinde bir url'ye yapılacak olan HTTP bağlantılarını yönetmek için bizlere ServicePoint sınıfı sunulmuştur. Bu sınıf yardımıyla bağlantının ne kadar süre sonra kapatılacağı, anlık kaç bağlantı yapıldığı, hatta son yapılan bağlantıdan beri ne kadar zaman geçtiği dahi öğrenilebilmektedir. Bu bilgiler dışında url'ye yapılabilecek maksimum bağlantı sayısı da öğrenilebilir/ayarlanabilir. Doğrudan bir örneğini oluşturamayacağınız bu sınıfa ulaşmak için ServicePointManager sınıfı üzerinden değerlerini düzenleyeceğiniz url'yi parametre olarak vermeniz gereklidir. Aşağıdaki örnekte http://www.enterprisecoding.com url'si için ServicePoint örneğini nasıl alabileceğimizi görebilirsiniz;

ServicePoint hizmetNoktasi = ServicePointManager.FindServicePoint(new Uri("http://www.enterprisecoding.com"));

   Url'miz için ServicePoint'in bir örneğini aldıktan sonra ConnectionLimit özelliği üzerinden maksimum bağlantı limitini düzenleyebiliriz;

ServicePoint hizmetNoktasi = ServicePointManager.FindServicePoint(new Uri("http://www.enterprisecoding.com"));
hizmetNoktasi.ConnectionLimit = 10;

   Gördüğünüz gibi yapılandırma dosyasında olduğu gibi kod içerisinde de maksimum bağlantı limitini değiştirmek oldukça kolay.

   Maksimum bağlantı limitleri gerek yerel sistem kaynaklarını gerekse de karşı sistem kaynaklarını tüketme konusunda kritik olması nedeniyle dikkatli yönetilmesi gerekli olan değerlerdir. Yanlış verilecek olan değerler, sistemlerden en az birisinin yanıt veremiyor duruma düşmesine neden olabileceğinden gerçekten ihtiyaç olmadığı sürece  değiştirilmemesini kesinlikle tavsiye ederim.

Fatih Boy

http://www.enterprisecoding.com
http://twitter.com/fatihboy