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 Code: https://github.com/borakasmer/AspNetCoreSessionOnRedis

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

8 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.

Bir Cevap Yazın

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