Asp .NET Core Mvc Bir Projede Session Bilgilerini Redis’de Tutma

Selamlar,

Bugün Asp.Net Core ile Web Sayfarı üzerinde yoğun yüklerin olduğu durumlarda,  distributed cache ile var olan yükleri nasıl azaltırız hep beraber inceleyeceğiz. Burada diğer durumlardan farklı olarak, eski alışkanlıklarımız olan ya da var olan projede bulunan “Session“‘larımızı hiç değiştirmeden kullanacağız.

Bildiğiniz gibi Session ile çalışmak yoğun trafikli portallarda hiç de tavsiye edilmiyen bir yöntemdir. Çünkü ilgili Session kaybolana kadar server side tarafda “In Memory” olarak tutulmaktadır. Bu da yoğun yükde, sunucunun şişmesine neden olmaktadır. Peki ya biz sessionlarımızı Redis üzerinde tutar isek :)

Yani diyelim ki projenin ortasındasınız ve var olan session kodlarını değiştirmek istemiyorsunuz, ya da session ile çalışmak istiyor ama bunun negatif durumları ile karşılaşmak istemiyorsunuz.

 

İşte bu durumda Asp.Net Core Mvc prjesine Redis ve Session servisleri tanıtılıp, session’a kaydedilen key ve valuelerin “In Memory” yerine Redis’de saklanması sağlanabilir. Redis ile alakalı yazıma buradan erişebilirsiniz. Yukarıda Windows ortamı için kurulmuş olan 6379 portunda çalışan bir Redis Server gözükmektedir. İstenir ise redis client’da açılıp “Ping” yazılarak, eğer herşey yolunda ise “Pong” cevabının alınması beklenir.

Şimdi gelin Visual Studio 2015 Update 3 ve.NET Core 1.0.1 versiyonlarında Mvc uygulamamızı geliştirelim.

Aşağıda görüldüğü gibi Proje oluşturulur.

Şimdi sıra geldi üç paketin NuGet Pacage Manager’dan kurulmasına:

View => Other Windows => Package Manager Console seçilir.

1-) Asp.Net Core’a Redis kütüphanesi aşağıdaki komut ile en son versiyonu kurulur.

2-) Session Asp.Net Core ile Default gelmemektedir. Aşağıdaki komutun çalıştırılması ile kurulur.

3-) Görselde Css olarak ben bootstrap kullandım. İlgili paket nugetden aşağıdaki gibi indirilir.

Startup.cs: ConfigureService() methodu önce redis cache’in sonra session’ın configure edilmesi ile sistem ayağa aşağıdaki gibi kaldırılır.

  • Redis’e atanacak key (InstanceName) “Blog” ismi ile başlayacaktır.
  • Redis uzakta bir sunucu olarak ayarlanır ise ona ait IP adresi girilmelidir. Bu örnekde localhost yani 127.0.0.1 girilmiştir. Her iki kullanım da doğrudur.
  • Services’e Session eklenmesi durumunda “services.AddSession()”, redis’e atılan keyler’e, belli bir expire süresi verilmesi gerekmektedir. Aksi takdirde redis’e atanan keyler, Session Time Out süresinde kaybolmıyacak ve belli bir zaman sonra milyonlara ulaşabilecektir. İşte bu neden ile “options.IdleTimeout = TimeSpan.FromMinutes(10);” configuration’ı ile ilgili expire süresi, 10 dakka olarak ayarlanmıştır.

Ayrıca Configure() methoduna Session’ın kullanımı için app.UseSession() ‘ın aşağıdaki gibi eklenmesi unutulmamalıdır.

Şimdi sıra geldi projemizi oluşturmaya. Projede bir login sayfası yapılacaktır. İlgili girilen bilgiler session’da yani bu sistem de Redis’de saklanacaktır. Daha sonra About sayfasında ilgili bilgiler redisden çekilip karşılama yazısı olarak ekrana basılacaktır.

HomeController.cs/Index(): Aşağıda görüldüğü gibi hiçbir işlem yapılmdan, doğrudan Index.cshtml sayfasına gidilmiştir.

Index.cshtml: Yukarıda görüldüğü gibi clinet’ın Kullancı Adı ve TC nosu girilmektedir. Form Post durumunda “Home/Index” [Post] action’ına gidilmektedir. Görsellik için bootstrap kullanılmıştır.

Login işlemi olmadan önce Redis-Client’da tüm keyler listelenmek istendiğinde “keys *” aşağıda görüldüğü hiçbir sonuç dönmemektedir. Çünkü daha henüz bir atama işlemi yapılmamıştır.

Index-Post(): Aşağıda görüldüğü gibi gelen “UserName” ve” UserID” byte’a çevrilip “Session”‘a atandığında, ilgili data Session yerine Redis’de saklanmaktadır. Sonra da “About” action’ına yönlenmeketedir. Atanma işleminden sonra Session kontrol edilir ise boş olduğu görülebilir.

Login işleminden sonra Redis-Client’a gidilip, tüm keyler listelenir ise aşağıda görüldüğü gibi artık tek bir key’in döndüğü görülür. Dönen key’in başlangıç kelimesi “Blog” ==> “AddDistributedRedisCache()” methodunda tanımladığımız “InstanceName“‘inden gelmektedir. Devamı da client’ın _sessionKey‘idir.

 

About(): Bu actionda Session’dan, yani  gerçekte Redis’den çekilen data byte’dan ==> string context’e çevrilir. Bu işlem hem “UserName” hem de “UserID” için yapılır. Ve son olarak çekilen datalar ViewData[“Message”]’a konarak Action view’a dönülür.

About.cshtml: İlgili sayfa yukarıda görüldüğü gibidir. Login ekranında girilen datalar Redis’den çekilerek About ekranına basılmıştır.

Aşağıda görüldüğü gibi Redis’e yazılan key başı “Blog”  ile başlamakta ve devamında _sessionKey gelmektedir. Value değerleri olarak “UserName” ve “UserID” değerleri Redis’de Hashes data tipi olarak byte[] olarak tutulmaktadır. Value değerine redis consoleda “hgetall  key” komutu ile erişilebilir.

Bu makalede klasik kullanımlarda karşımıza çıkan geleneksel sorunlara, yenilikçi çözümler bulduk. Session, kullanım kolaylığı nedeni ile çokça kullanılan bir yapıdır. Ama yoğun trafikde size büyük sorunlar çıkarabilir. Zaten uygulamanızı bu makalede olduğu gibi Asp.Net Core üzerinde koşturuyorsanız, 2 amacınız vardır. Biri performans, diğeri de işletme maliyetlerini kısıp Linux bir işletim sistemi üzerinde yayımlamak. Bu durumda session çok da mantıklı bir çözüm olmayabilir. Ama ya önceden yazılmış ve içinde bolca Session kullanılmış bir projeyi Asp.Net Core’a çevirmek ve optimizasyon yapmak isterseniz. Ya da Redis kütüphaneleri ile uğraşmadan her zamanki kolay kullanımı ile Session’a devam etmek isterseniz, işte o zaman bu makalede esas anlatılmak istenen, Session’a kaydedilmek istenen tüm verinin Redis’e kaydedilmesi konusu hem performans hem de Session’ın negatif durumlarına karşı karanlıkta parlayan bir ışık gibi karşımıza çıkmaktadır.

Not: Hepsinden önemlisi normal şartlarda farklı makinalarda tutulan ve tek bir yerden erişilemiyen Session bilgisi, bu makalede anlatıldığı gibi redisde saklanması durumunda, ilgili distributed cache Redis Sentinel” kullanılarak master ve slave şeklinde scale edilerek çoğaltılabilir ve tek bir yerden tüm session bilgisine “hashes” data tipinde erişilebilir.

Madalyonun Öbür Yüzü: Session TimeOut olduğu zaman Redis tarafında atanan keyler silinmez. Eğer makale içinde kullanılan 10 dakikalık redis expire süresi atanır ise, clientın çalışma anındaki bilgileri 10 dakika sonunda sayfa üzerinden kaybolabilir. Bunun önüne geçmek için aşağıda görüldüğü gibi ilgili redis key’e 1 günlük Expire süresi verilebilir. Böylece gelen client’ın session bilgileri 24 saat boyunca korunur. Tek sorun, yüksek trafikli bir sitede herbir session’a ait key’in kaybolmamak üzere 24 saat boyunca redisde tutulması olacaktır. Tek bir sunucuda Redis’in 232 – 1 yani 4 milyardan fazla hash tipinde key tutabildiği düşünülür ise korkulacak pek de birşey yoktur:)

 

Geldik bir makelnin daha sonuna:) Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Source: https://redis.io/documentation, https://stackoverflow.com/questions/50228068/not-able-to-increase-session-timeout-in-net-core-2-0, https://www.mikesdotnetting.com/article/270/sessions-in-asp-net-core

Source Code: https://github.com/borakasmer/AspNetCoreSessionOnRedis
Herkes Görsün:

Bunlar da hoşunuza gidebilir...

30 Cevaplar

  1. Ahmet dedi ki:

    Bora hocam öncelikle elinize emeğinize sağlık. Sizden bir ricam olacak. Ben de kendi blogumu yaziyorum ayesilyurt.com uzantili adresim. Bloguma göz atıp bana fikirlerinizi ve eleştirilerinizi iletir misiniz?

    • borsoft dedi ki:

      Selam Ahmet,

      Öncelikle başka Url’leri bloğuna kaynak olarak verirken çok dikkat et. Mümkün ise verme. İlerde o siteler kapanırsa bloğun Google Amcadan düşük score alır. Bunu unutma. Kapanmayacağı kesin siteleri bloğuna referans vermeye çalış. Site tasarımı hoşuma gitti. Bazı imajlar gelmiyor. Ama sade olduğı için hızlı. Seo amaçlı google analistic codeları da koysan fena olmaz. og:titleları koyman facebook adına ii olmuş :)
      Bence başarılı. Eline sağlık.

      Kolay gelsin.

  2. MBiya dedi ki:

    Sessionlar in-memory yerine Redis’te saklanabilir demişsiniz. Redis’in kendisi de in-memory değil mi? Ayrımı kavrayamadım.

    • borsoft dedi ki:

      Selamlar,

      Sanırım bir anlam karmaşası yaratmışım:)
      Redis harici bir sunucu olabilir ve scalable olabilir. Kısaca Sunucu makinanın memorisi şişirilmeden başka makinanın memorisi üzerinden çalışılabilir. Ayrıca 5 sunuculu bir portalın tüm session bilgilerine tek bir yerden listelenebilir. Uzun lafın kısası tabiki 2si de memoride tutulur. Ama risk dağıtımı açısından başka makinanın kaynakları kullanılır hale getirilebilir. bir de Redis’in memory yönetimi ve istene key’e ait value değerini getirme hızı kat ve kat üstündür.

      İyi çalışmalar.

      İyi çalışmalar.

  3. Cemal dedi ki:

    Session bilgisini saklayabileceğimiz diğer alternatifler ile ( stateserver veya sqlserver) ile ilgili yorumlarınızı öğrenmek isterim.

    • borsoft dedi ki:

      Selamlar,

      Onların da eksi ve artılarını başka bir makalede paylaşmak isterim. SqlServer ile yavaş ama sağlamcı olabilirsiniz. Redis makinası kapanırsa In Memory data uçar. Tabii istersek redis’in fiziksel diske de yazmasını aynı zamanda sağlayabiliriz. Tabii hızdan feragat ederek.

      İyi çalışmalar.

  4. Serkan dedi ki:

    hocam selamlar, asp.net webform projesinde bu yapıyı kullanmak bize hız kazandırırmı, 50 civarı session datası var, aktif kullanıcı sayısı anlık olarak 250-500 arası,öneriniz olabilirmi

    • borsoft dedi ki:

      Anlık kullanıcı sayııs çok değil. Ama illaki performans derseniz çok fark eder. Bu yapı baya sağlıklı. Tavsiye olunur.

  5. sevgiler dedi ki:

    Bora hocam selamlar, Sessionlarda bazen sorunlar yaşıyoruz. timeout sürelerini uzatmamıza rağmen yine sessionlar bazen boşalıyor. tek bir server ımız var. redis bize çare olur mu. Yoksa ikisi de memory de tutulduğundan aynı sorunu yaşamaya devam edermiyiz. Teşekkürler

    • borsoft dedi ki:

      Selamlar Sevgiler :)

      IIS üzrinde mi yayımlıyorsunuz yoksa Kestrel mi? IIS ise session timeout süresini sadece webconfigden değil bir de IIS’den ayarlamalısınız. Eğer Redis kullanacaksanız :Redis Candır. Siz timeout vermediğiniz sürece kalır:)

      İyi çalışmalar.

      • sevgiler dedi ki:

        Selamlar ve Sevgiler hocam:)
        IIS üzerinde tutuyoruz. Timeout süresini 2 tarafta da artırdık. Merak ettiğim Redis kullanırsak tek sunucu kullandığımızdan sessionları memory de tutarsak sorun yaşama durumumuz var mı

        • borsoft dedi ki:

          Selamlar,

          Hayır yok. Performans için Redislerinizi sentinel ile master slave olarak ayırabilir; hatta read ile write yapacak sunucularınızı da önceden belirleyip ayırabilirsiniz.

          İyi çalışmalar.

  6. ferdi dedi ki:

    bora hocam ben asp.neti biliyorum mvc de de yeni yeni birşeyler yapıyorum videolarınız sayesinde. asp.net i tamamen bırakacak mıyız bütün projeleri mvc ile mi yapacağız. birde mvc core yeni çıktı deniyor. mvc core şimdiden geçmelimiyiz. yoksa mvc ile mi devam etmeliyiz

    • borsoft dedi ki:

      Ben şahsen 2011’den beri Asp.Net kullanmıyorum. Aslında malesef artık Mvc de pek tercih edilmiyor. Angular, React, Vue gibi javascript frameworkleri ile cross platform yani mesela (.Net Core) ile çalışmak artık son 1-2 yılın modası.

      İyi çalışmalar.

  7. ferdi dedi ki:

    bora hocam bir de mvc türkçe kitap tavsiye edebilirmisiniz.

    • borsoft dedi ki:

      Selam Ferdi,

      Gerçekten türkçe kitap Mvc tavsiye edebileceğim yok.
      İyi çalışmalar.

  8. Sinem dedi ki:

    Merhaba ben HttpContext üzerinden methodlara ulaşmak istiyorum ancak gelmiyor sebebi ne olabilir?

    • borsoft dedi ki:

      Selamlar Sinem,
      HttpContext’e erişemiyorsundur. Eğer uygulaman Console App ya da WebApplication değil ise bu çok normal.
      Bu şekilde denermisin “System.Web.HttpContext.Current”. Methodlar :)

      İyi çalışmalar.

  9. Gokhan dedi ki:

    Makale için teşekkürler. Çok faydalı ve sayenizde kullanmaya başladım. Fakat benim iki ihtiyacım var ki belkide bu konuda birçok kişi müzdarip.
    1. Oturum açmış kişi, başka bir bilgisayardan, yada başka bir tarayıcıdan oturum açmışsa, önceki oturumunu düşürmek istiyorum.
    2. Bir kullanıcı oturum açmışken, eğer onu pasif duruma getirirsem veya silersem, kullanıcı sürekli sistemde gezmeye devam edecek, taa ki oturumu süresi dolana kadar.

    Bu oturumlara bir şekilde ulaşıp, o kişinin login olanlar arasında var olup olmadığını kontrol etmek gerekiyor. Buraya kadar sorun olmuyor fakat o kişinin oturumunu kaldırmak gerektiğinde iş biraz karmaşık hale geliyor. Bu konuda bilginiz var ise en acilinden bir makale bekliyoruz.

  10. Erol dedi ki:

    Sayın Bora hocam henuz oluşturulmamış bir sessionu HttpContext.Session.GetString(“Id”) şeklinde okumya çalıştığımda NullReferenceException hatası alıyorum bunu nasıl aşabilirim?

  11. Kadir dedi ki:

    Merhaba Hocam. .Net core’da bir mvc projem var. Api kullanarak login olduğumda, api tarafında session’a bazı değerler atıyorum. Sonra başka bir request attığım zaman api tarafında session boş oluyor. Ne önerirsiniz?

    • borsoft dedi ki:

      Session’yerine, USERID key olarak atayıp Session’a ne atıyorsan ilgili datayı Redis’e atmanı öneririm..

  12. Hasan dedi ki:

    Bora Hocam Merhaba,

    İki sorum olacak cevaplayabilirseniz sevinirim.
    1- Sadece Redis kullanımında(Session kullanmadan) tıpkı Session kullanımında olduğu gibi timeout süresinin her işlemde yenilenmesini nasıl sağlayabilirim
    2- Eskiden Global.asax’de Session_End ile Session bitiminde işlem yapabilirdik bunu Redis kurgusunda sağlayabiliyor muyuz? Amacım Logout yapmadan direk sayfayı kapatan kişilerin login sürelerini tahmin etmek ve cache temizlemek

    Şimdiden Teşekkürler,
    Saygılar

    • borsoft dedi ki:

      Selam Hasan,

      Sorunun cevabında Redis’e Expire süresi ile Token atabilirsin. Zaten süre dolunca Token kaybolacağı için, Logout ayrıca yapmana gerek yok. Çünkü client’ı 403 forbidden hatası alınca Login ekranına redirect yapabilirsin. Ayrıca Client Side tarafda da Cookie’ye Expire süreli atabilirsin.

      İyi çalışmalar.

  13. Samet dedi ki:

    Merhaba Bora Hocam,
    Yazılarınız ve videolarınız çok bilgilendirici bunun için öncelikle teşekkür ediyorum.

    Bir konuda fikrinizi almak istiyorum.
    Uzun bir süredir Asp.Net Webforms ile geliştirdiğim ve makul seviyede kullanıcısı olan ve Azure App Service’te koşan bir uygulamam var. Bu uygulama da session saklamak için Azure Cache for Redis kullanıyorum ve performansından çok memnunum. Fakat ekibime yeni arkadaşlar katmak istediğimde mevcut uygulamam Webforms olduğu için istekli ekip arkadaşları bulamıyorum, dolayısıyla projeyi yavaş yavaş Angular & .Net Core API olacak şekilde migrate etmek istiyorum, fakat bunu tek seferde yapmam mümkün değil dolayısıyla yeni geliştirme gereken işleri bu yeni projede yapmak istiyorum. Buraya kadar herşey olması gerektiği gibi ilerliyor fakat bir noktada takıldım, yapmak istediğimde Webforms uygulamasından bir menüye veya bir butona basılınca yeni uygulamaya yönlendirmek fakat yeniden giriş yapmasına gerek olmamalı. Bu işlemi 2 farklı webforms uygulamasını aynı domain farklı subdomainler ile web.config’e ekleyerek yapabiliyorum fakat Webforms ve yeni proje ile bunu yapamıyorum. Çünkü yeni projedeki .Net Core API tarafına gelen request’te ASP.NET_SessionId’ye erişemiyorum.

    .Net Core API projesinde StartUp.cs içindeki
    ConfigureServices içine
    services.AddDistributedRedisCache(options =>
    {
    options.Configuration = “redis’e erişim için gerekli bilgiler”;
    });

    services.AddSession(options => {
    options.Cookie.Name = “ASP.NET_SessionId”;
    options.Cookie.Domain = “.test.com”;
    });

    Configure içine de
    app.UseSession();

    ekliyorum.

    Farkındayım özel bir durum ve net bir cevabınız olmayabilir, fakat böyle bir dönüşüm işi eminim bir çok kişinin yapmayı düşündüğü bir işlemdir, dolayısıyla konu hakkında bilgilerinizi paylaşırsanız sevinirim.
    İyi günler.

  1. 30 Temmuz 2021

    […] Session, cookie gibi data saklamaya yarar fakat cookie den büyük bir farkı vardır. Session da bilgiler server tarafında tutulur. Bu yüzden server da oluşabilecek problemlerde sessionlar da etkilenir. Bununla beraber sessionların yüksek trafikli durumlarda kullanılması tavsiye edilmez, çünkü sessionlar bellekte (in-memory) tutulduğu için yoğunlukla beraber belleğin şişmesine sebep olabilir. Buna çözüm olarak alternatif yollar vardır. Örneğin session bilgilerini Redis üzerinde tutmak. https://www.borakasmer.com/asp-net-core-mvc-bir-projede-session-bilgilerini-redisde-tutma/ […]

borsoft için bir cevap yazın Cevabı iptal et

E-posta hesabınız yayımlanmayacak.