Session modülüne erişim esnasında diğer isteklerin "RequestAcquireState" durumunda beklemeleri
Merhaba,
Çoğumuz IIS üzerinde çalışan uygulamalarımızda, oturum bazındaki bilgileri saklamak için "SessionState" modülünü kullanıyoruz. Fakat bu modülü kullanırken dikkat edilmesi gereken bir nokta var. Bu yazıda bu konuya değineceğiz.
Biliyoruz ki bir “ASP.NET” isteği, konfigürasyonu doğrultusunda, bir dizi “HTTP modül”leri içerisinde taşınır ve işlenir. Buna “IIS pipeline” diyoruz. IIS’in gücü bu yapıdan gelmektedir ve birçok farklı teknoloji IIS üzerinde sunulan “Authentication”, “Authorisation” vs. gibi özellikleri kullanırlar.
Bu modüllerden bir tanesi de “SessionState” modülüdür. “Asp.net” isteği “IIS pipeline” modülleri içerisinde ilerledikçe, işlenmeye hazır hale gelinceye kadar , “HTTPContext” nesnesi içerisine kullanıcı bazında birtakım durum bilgileri yüklenir. Örneğin “SessionStateModule” modülü istek işlenmeden önce “HTTPContext “içerisine session değerlerini bir “Dictionary” nesnesi içerisinden çeker (“Deserialize” işlemi) ve doldurur. İstek işlendikten sonra değişen session bilgileri, gine “SessionStatemodule” tarafından bellek içerisinde geri yüklenir (“serialization” işlemi) ve güncellenmiş “Session” değerleri diğer istekler için hazır hale gelir. . Kullanıcı bazındaki “session” bilgilerine sunucu ve istemci arasında bir cookie içerisinde taşınan “SessionKey” ile erişilir.
Aşağıdaki resimde görüldüğü gibi Session bilgileri, “SessionState” moduna göre, "ASP.NET Cache" içerisinde ("in-proc" modu), Sql suncusu üzerinde ("SQL Server" modu) yada harici bir “aspnet_state.exe” process’i içerisinde ("State Server" modu) tutulabilir. Her bir modun kendine göre avantajları ve dezavantajları vardır. Bu mod aşağıda kısmen gösterdiğim konfigürasyon ile uygulamanın konfigürasyon dosyası üzerinde ("web.config" dosyası) belirtilir.
<sessionState mode="InProc | StateServer | SQLServer />
Session nesnesine erişim bir “reader/writer”lock üzerinden korunur. Bunun temel amacı, aynı session’a erişmeye çalışan birden fazla istek olduğu zaman, session üzerinde saklanan verinin tutarlılığını korumaya almaktır.
Yazının başında belirttiğim dikkat edilmesi gereken nokta bu kilitleme (“lock”) mekanizması. Varsayılan değer olarak tüm ASP.NET sayfaları için “EnableSessionState”
değeri “enabled” olarak gelir. Yani sayfa, Session üzerinde "Read/Write" yetkilerine sahiptir. Sayfanın ilk satırındaki “@Page” direktifinde bu değer “ReadOnly” yada “false” olarak değiştirilerek, sayfanın SessionState modülü üzerindeki talepleri değiştirilebilir.
Aynı anda iki istek Session bilgilerini “context” içerisine doldururken “ReadOnly” haklara sahip “aspx” sayfaları, diğerlerine göre daha öncelikli durumdadır, ve “Read/Write” yetkilerine sahip diğer sayfalar bu sebepten beklerler. Aynı anda iki veya daha fazla “ReadOnly” yetkilerine sahip istek ise, “Session” bilgilerine aynı anda erişebilirler. Fakat diğer bir durumda eğer bir “Read/Write” yetkili sayfa Session bilgilerini kilitledi ise, bu durumda diğer hiçbir sayfa, Session üzerindeki işlemler bitinceye kadar “Session” bilgilerine erişemez. Temel olarak “Read/Write” kilit mekanizması bu şekilde çalışır.
Eğer IIS yönetim arayüzünden, birçok isteğin “RequestAcquireState” durumunda beklediğini görmekte isek, bunun sebebi büyük ihtimalle yukarıda belirttiğim koruma mekanizmasıdır.
Bunu kendiniz de test edebilirsiniz. Örneğin aşağıdaki gibi 3 test sayfası hazırlayalım:
SessionPage.aspx : Bu sayfa session’a “Read/Write” yetkileri ile erişen ve session’ı 30 saniye boyunca kilitleyen bir sayfa.
<%@ Page %>
<script language="C#" runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
Session["SessionLock"] = "Lock Here!";
System.Threading.Thread.Sleep(30000);
}
</script>
SessionTest.aspx: Bu sayfada “Read/Write” yetkilerine sahip , ve aynı session’ı modifiye etmeye çalışıyor.
<%@ Page %>
<script
language="C#" runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
Session["SessionLock"]= "Modify Lock";
}
</script>
SessionValue.aspx : son olarak sadece “ReadOnly” etkileşime sahip bir sayfa yaratalım.
<%@ Page EnableSessionState="ReadOnly" %>
<script language="C#" runat="server">
private void Page_Load(object sender, System.EventArgs e)
{string sessionLock="";
if(Session["SessionLock"] != null)
sessionLock = Session["SessionLock"].ToString();
}
</script>
Devamında bu sayfaları IIS üzerinde bir uygulamaya ekleyelim ve Explorer üzerinden bu sayfalara 10-15 civarında istekte bulunalım.
Test sonucunda aşağıdaki resimden göreceğiniz üzere birçok isteğin beklemeye geçtiğini göreceksiniz.
Bu davranışı farklı şekillerde de test edebilirsiniz. Örneğin “readonly” erişime sahip sayfada “Sleep()” fonksiyonunu uzunca bir süre çağırarak bunun diğer sayfalar üzerindeki etkilerini de test edebilirsiniz.
(Aşağıdaki ekran IIS yönetim arayüzünde sunucu seviyesindeki özelliklerden “Worker Processes”e tıklandığında, mevcut isteklerin görülebildiği ekrandır.)
İyi çalışmalar dilerim,
Mert