Redis ile Azure da Mvc, AngularJs ve SignalR İle PubSub Bölüm1

Selamlar,

Bugün Asp.NET Mvc ile Azure üzerinde Redis kullanarak dataların nasıl memory’de tutulup, istendiğinde çekilebileceğini hep beraber inceleyeceğiz.

Öncelikle redis Salvatore Sanfilippo tarafından open source olarak geliştirilen, veriyi bellekte tutup, dosyaya yani herhangi bir storage’ı yazmayan memcached bir yapıdır. Ama istenir ise disk’e de yazabilmektedir. Sitesinden bu konu ile ilgili bilgi alınabilir. Kısaca memcached bir yapıda tutulacak verinin miktarına göre makinadaki rem kapasitesine dikkat edilmelidir. İlk akla tüm cache mimarilerinde olduğu gibi “key-value” pair yapısı gelse de Redis’de beş farklı veri  tipi vardır.

Bunlar: “Strings”, “Lists”, “Sets” , “Hashes”, “Sorted Sets”‘dir.

Redis’in açılımı “Remote Dictionary Service”’dir. En büyük özelliği çok hızlı olmasıdır. Sn’de 100bin operasyon yürütebilmektedir. Peki memoryde ne kadar yer kaplar ? Örneğin sadece <String,String> şeklinde 1 milyon veri için 100mb ya da <Hash,Obj> şeklinde 5 kırılımlı karmaşık 1 milyon ver için 200mb yer kaplamaktadır. Kısaca hem çok hızlı hem de nerede ise hiç yer kaplamıyan bir yapıdır.

redis-everywhere-sunshine-php-8-638

Nasıl Kurulur ? : Esasen Linux işletim sistemi için tasarlanmıştır. Ama sitesinde resmi olarak desteklenmese de, windowsda da çalışmaktadır. http://redis.io/download ilgili link tıklanıp, sayfanın aşağısındaki windows bölümünden GitHub altındaki “MSOpenTech”‘e ait “https://github.com/MSOpenTech/redis/releases” kaynak dosyalarına ulaşılır. Örneğin bu projede aşağıdaki dosya indirilmiştir.

Untitled

Yukarıdaki zip dosyası açılınca ilgili klasörden önce “redis-server.ex”e tıklanarak redis-server çalıştırılır. Ayrıca “redis-ci.exe” ile client console aşağıdaki gibi açılır. Artık bu noktadan sonra local windows ortamında redis ile çalışılabilir.

source

Untitled

Bundan sonra Azure üzerinde Redis kurulumu yaparak makaleye devam edeceğim. Siz isterseniz örneğinize, local makinadan da devam edebilirsiniz. Aşağıda görüldüğü gibi Azure üzerinde “Data + Storage”‘dan “Redis Cache” tıklanarak ilgili kurulum yapılır.

CZwOB4hWIAAXDcH

Kurulumdan sonra istenir ise Azure üzerinde Redis Console’una aşağıdaki gibi erişilebilir. İstenilen monitoring, test ve sorgu işlemlerinin hepsi aynı local makinada olduğu gibi buradan da kolaylıkla yapılabilir.

Cosole

Redisin test işelemi aşağıdaki gibi “Get”-“Set” komutları ile aşağıdaki gibi yapılmıştır. Güvenlik için Azure ortamında “SSL” aktif edilmelidir. Azure üzerinde SSL ile redis “6380” nolu portdan çalışır. “SSL” kapalı iken Redis, Azure üzerinde “6379” nolu portu kullanır.

RedisTest

Aynı test işleminin, Redis dökümanlarında aşağıdaki gibi server’a çekilecek “Ping” komutu ile de yapılabileceği söylenmiştir.

Ping2

Redis’de kullanılan birçok komut vardır. http://redis.io/commands adresinden ilgili komutlar örenilip, http://try.redis.io/ adresinden de test edilebilir. Ayrıca local bir makinada da kolaylıkla test işlemleri yapabilmektedir. Bu makalenin konusu aşağıdaki komutlardan ziyade, Redis’in Mvc .Net ve Azure ile nasıl kullanıldığına dair uygulamalı bir web app yapmaktır. Kod içinde, kullanılan komutlardan yeri geldiğince sırası ile bahsedilecektir.

commands

Öncelikle Visual Studio 2015 ortamında Empty bir Mvc project yaratılır. Nuget’den Redis ile çalışmak üzere aşağıdaki 2 package’dan biri indirilir. Bu örnekde “ServiceStack.Redis” kütüpahanesi kullanılmıştır.

Redis

Ayrıca bu projede AngularJS’in 1.4.9 versiyonu indirilmiştir. Aslında an itibari ile AngularJS’in “1.5.0-rc.2” versiyonu yayınlanmıştır.

angular2

Bu projede hepsiborda.com :) sitesinin ürünlerinin kategori bazında listelenip, fiyatlarının göründüğü bir vitrin ve admin sayfası yapılacaktır. İstenen kategoriler ve her kategoriye ait ürünler eklenip, düzenlene bilecektir. Son olarak en ucuz 5 ürün real time olarak sayfanın altında bant şeklinde kayacaktır.

shop

Öncelikle belli kategorilerin listeleneceği bir combobox’ı, Redis ve AngularJS kulanarak dolduralım. Bunun için Redis’deki strings tipi kullanılacaktır.

prds2

HomeController.cs:  Aşağıda görüldüğü gibi “Index()” actionında herhangi bir işlem yapılmaz.

Index.cshtml: İlgili AngularJs, Jquery ve Bootstarp kütüpahaneleri aşağıdaki gibi indirilir. Tüm javascript kodları “index.js”‘de yazılacaktır. Ayrıca css dosyası için “productStyle2.css” kullanılmıştır.

Combo

Aşağıda görüldüğü gibi, yeni bir kategori eklemek için bir Link ve kategorilerin AngularJS ile doldurulduğu bir “<select>” html elementi bulunmaktadır. Ilgili “$scope.Products” ‘dan “Id” ve “Name” fieldları combobox’a doldurulur. Ayrıca seçilen ürün id’si “$scope.selectedProduct””a “ng-model” ile bağlanmıştır. Herhangi bir kategori seçildiğinde ona ait olan ürünler “GetItems()” function’ı ile doldurulur.

index.js (Part 1): Aşağıda görüldüğü gibi AngularJs ile “ProductController” oluşturulmuştur. Sayfa ilk yüklendiğinde “Home/GetProducts” action’ından ürünler Redis üzerinden çekilmekte ve “$scope.Products”‘a doldurulmaktadır. Ayrıca seçilen kategoriye göre ilgili itemlar “GetItems()” function’ı ile “Home/GetItems” action’ına post işlemi yapılarak Redis üzerinden “productID”‘ye göre “$scope.Items” doldurulmuştur.

Redis

HomeController.cs/GetProducts(): Aşağıda görüldüğü gibi ürünler Redisden doldurulmuştur. Öncelikle Redis’e bağlanmak için “RedisEndpoint” aşağıdaki gibi oluşturulur. “Host” Azure üzerindeki Redis’den yukarıdı görülen “Host name”alanından doldurulur. “Local” için kendi makinanızın ipsini “127.0.0.1” girmeniz yeterlidir. Port için Azure’da “Setting/Properties” sekmesinden ilgili portlar görülebilir. “6380”.  Güvenlik amaçlı “Ssl=true” yapılmıştır.  İlgli configurasyon dosyası ile Redise’e bağlanıldıktan sonra “client.As<Product>” ile Redis üzerindeki “ids:Product” strings’i ne ait tüm elemanlar çekilir. Daha sonra “GetAll()” methodu ile tüm “urn:product:1”, “urn:product:2”, “urn:product:3” strings lerine ait value değerler alınır. Ve çekilen tüm data “Json” formatında geri dönülür. Merak etmeyin hepsi tek tek açıklanacaktır:)

port

Şimdi ilgili komutları inceleyelim: Öncelikle yukarıdaki komutlar çalışırken Redis üzerinde “monitoring” komutu yazılarak ilgili methodların, Redis üzerindeki komut karşılıkları kolaylıkla gözlemlenebilir. Yani “ServiceStack”‘in .Net üzeriden çağırdığı komutların, Redis üzerinde anlamlandırılması biraz farklıdır. İşte yazının başında bahsedilen komutlara şimdi değinilmeye başlanacaktır.

Monitor

Yukarıda görüldüğü gibi :

  • “SMEMBERS” “ids:Product” Bu komut “SET” kümesindeki(bir çeşit List) tüm elemanları listelemek için kullanılır. “SET” tiplerine ilerde değinilecektir.
  • “MGET” “urn:product:1” “urn:product:2” “urn:product:3” Birden çok key’a ait value’yu çekmek için strings veri tipinde kullanılır. ServiceStack kütüpahanesindeki “GetAll()” methoduna karşılık gelmektedir. Burada dikkat edilecek husus “key” oluşturulurkenki durumdur. “urn:product” productları belirler “:1” product ID’ye karşılık gelir. Yani 1 id’ili product anlamına gelmektedir. Biz de isimlendirmeleri yaparken “:” koyarak istediğimiz kırılımı yapabiliriz. Aşağıda görüldüğü gibi ilgili result Json olarak alınır.

Commands

Projede kullanılan “Product” ve “Item” modelleri aşağıdaki gibidir:

Items

HomeController.cs/GetItems(): Aşağıda seçilen bir product’a göre ilgili itemlar filitrelenerek gözükmektedir. Redis’e bağlanıldıktan sonra itemlar “Lists” türünde ilgili “productID”‘ye göre çekilir. “urn:item”+ productID çekilen liste Json olarak dönülür.

Yukarıda çalışan komutu Azure tarafında monitoring ettiğimizde seçilen kategoriye göre ilgli itemların filitrelenmesi, Redis tarafında aşağıdaki gibi yorumlanmaktadır:

Lrange2

  • LRANGE “urn:item:2” “0” “-1”: Liste içindeki elemanları başlangıç ve bitiş verilerek toplu olarak listelemesini sağlar. Burada “-1” sonuna kadar yani hepsi anlamına gelmektedir.

Ilgili komut redis tarafında çalıştırıldığında aşağıdaki gibi bir sonuç ile karşılaşılır.

Lrange3

Şimdi gelelim dönen sonucun “$scope.Items”‘a basılmasından sonra UI’da gösterimine: Aşağıda görüldüğü gibi bootstarp ile bir table oluşturulmuştur. İlgili ürünler “data-ng-repeat” ile gezilerek ekrana basılmaktadır. Ayrıca sona bir “Düzenle” button’u konmuştur. “ng-click”‘de “EditItem()” function’ı çağrılarak ilgili item’ın editlenmesi sağlanmıştır.

Edit

Şimdi sıra geldi yeni bir kategorinin eklenmesine:

En başdada belirtildiği gibi “Yeni Bir Kategori Giriniz” buttonuna tıklanınca “/Home/AddProduct” action’ına gidilmektedir.

Home/AddProduct: Aşağıda görüldüğü ilgili view’a direk gidilmektedir.

Product

AddProduct.cshtml: Aşağıda görüldüğü gibi tüm işlemler yeni eklenecek “SubController” altından yapılmaktadır. Girilecek ürünün ismi “ng-model=Name” ve açıklaması “ng-model=Detail” ile tanımlanmıştır. Kaydet button’una basılınca “SaveProduct()” function’ı çağrılmaktadır.

index.js (Part 2): Aşağıda görüldüğü gibi “app” module’üne Dependency Injection ile “directApp” module’u eklenmiştir. “directApp” module’ünde “SubController” controller’ı tanımlanmış ve “$scope.Name ve $scope.Detail” fieldları “SaveProduct()” action’ına postlanmıştır. İşlem bittiği zaman da Ana sayfaya yönlendirilmiştir.

Home/SaveProduct: Aşağıda görüldüğü gibi öncelikle “Redis”‘e bağlanılmıştır.

Not: Her seferinde özellikle Redis’e bağlanılmıştır. Amaç size yapıyı her seferinde tekrar tekrar göstermektir. İlgili işlem, optimizasyon amaçlı bir static sınıf altında  tek bir seferde yapılabilirdi.

“client.As<Product>” ile product client’ı oluşturulur. “GetNextSequence()” methodu ile aynı Sql’deki identity colomundaki gibi, enson “id” değerinin bir fazlası alınır. Ve gönderilen Product sınıfı Redis’e kaydedilir.

İlgili işlemler yapılırken Redis monitoring edilir ise aşağıdaki kodların çalıştırıldığı görülür.

Add2

  • “INCR”: Sayısal bir alanın verilen bir key’e göre “1” arttırılması için kullanılır. Koddaki “GetNextSequence()”‘in karşılığıdır.
  • “SET”: Belirtilen key değerine value atamak için string yapılarda kullanılan bir komuttur. Burada “urn:product:4” yani id’si 4 olan “Product” Key’ine yeni eklenen json “Product” sınıfı atanmıştır.
  • “SADD”:  Redis te Set dizi tiplerine “SADD” komutu ile veri eklenir. Set tipleri herhangi bir sıra gözetmeksizin veri eklenen dizilerdir. “SMEMBERS” komutu ile yukarıda da belirtildiği gibi tüm veriler okunur. “Set”‘tipine bağlı en büyük belirleyici özellikler, bir Set listesinde ilgili elemanın var olup olmadığının kolaylıkla bakıla bilmesi, 2 Set dizisinin kolaylıkla “Union” yani birleştirilip geriye dönülebilmesi, 2 Set dizisi arasındaki farklı veya ortak elemanların kolaylıkla bulunabilmesi sıralanabilir. Bir Set’e aynı isimli “Key” 2 kere yazılamaz. Setler sıralanabilir yada belirli bir eğer işlemine göre değer döndürebilirler.

sets

Şimdi sıra geldi ilgili kategori altında yeni bir ürünün eklenmesine:

En başda da belirtildiği gibi “Yeni Bir Ürün Giriniz” buttonuna tıklanınca “/Home/AddItem/2” gibi bir action’ına gidilmektedir.

HomeController.cs/AddItem(): Aşağıda görüldüğü gibi ilgili action’a seçilen “Product”‘a göre gidildiğinde “AddItem.cshtml”‘ine ilgili seçilen “ProductID” “ViewBag.ProductID” ile gönderilmiştir.

Url satırına yukarıdaki yol yazıldığında ilgili Action’a gidilebilmesi için “RouteConfig.cs” sınıfına aşağıdaki tanımlamanın yapılması gerekmektedir.

RouteConfig.cs:

itemAdd

AddItem.cshtml: Aşağıda görüldüğü gibi ürünün fiyat ve ismi “ng-model=Price” ve “ng-model=Name” ile AngularJs’deki “ItemController”‘a ait ilgili değişkenlere atanmışlardır. Burada “ng-app=’app'” olarak yine aynı “app”‘in kullanılmasına rağmen yeni bir “ItemController”‘ın eklenmesi AngularJs tarafında yeni bir “Dependency Injection”‘ın olduğu anlamına gelmektedir. “Kaydet” buttonu tıklanınca “SaveItem()” function’ı çağrılmıştır. Ayrıca en başta seçilen türe ait olan “ProductID” burada hidden “hdnProductID”‘ye viewbag vasıtası ile atanmıştır. Amaç kaydetme işleminde ilgili ProductID’nin  ilgili Action’a gönderilebilmesidir.

index.js (Part 3): Aşağıda görüldüğü gibi “itemApp”‘de Injection ile “app” module’üne eklenmiştir.  Burada diğerlerinden farklı olarak yeni bir “item” sınıfı yaratılmasıdır. item sınıfına ait “Name” ve “Price” propertyleri, AngularJS’deki text fieldların “ng-model” ile bağlandıkları “$scope” değişkenleri(“Name”,”Price”) ile atanmışlarıdır. Son olarak “ProductID”‘nin değeri olarak “hdnProductID”‘deki hidden filed’ın values’u atanmıştır. Daha sonra ilgili “item” sınıfı “Home/SaveItem()” action’ına post edilmiş ve işlem tamamlandığında ana sayfaya yönlendirilmiştir.

HomeController.cs/SaveItem(): Aşağıda görüldüğü gibi Redis’e bağlanılıp “client.As<item>” ile “itemClient”‘a Redisdeki “item” listesi atanır. “itemClient.Lists” propertysinin key alınına “urn:item” ile başlanıp, bağlı olduğu productID’nin de sonuna eklenmesi ile yeni bir key oluşturulur. Örnek “urn:item:2” yani ProductID’si 2 olan itemları ifade etmektedir. Gelen item’ın “id” alanına “GetNextSequence()” methodu ile yeni bir “id” atanıp “itemList.Add()” ile kaydedilir.

İlgili işlemler yapılırken Redis monitoring edilir ise aşağıdaki kodların çalıştırıldığı görülür.

itemRedis

  • “INCR”: Sayısal bir alanın verilen bir key’e göre “1” arttırılması için kullanılır. Koddaki “GetNextSequence()”‘in karşılığıdır. “seq.Item” değeri bir arttırılmıştır.
  • “RPUSH”: “List”‘in sonuna yeni eleman ekler. Burada da “Add()” komutu ile item “Lists”e yeni bir eleman eklenmiştir.

Bu zamana kadar yeni kategoriler Redis ile girilmiş ve listelenmiştir. Ayrıca ilgili kategorilere göre bir alt kırılım ile yeni itemlar girilmiş ve istendiğinde ilgili “Product”‘a göre listelenmiştir. En önemlisi de bu yapılan işlerin tamamı memory’de tutulmuş ve hiçbir fiziksel dosyaya yazılmamıştır. Redis, NoSql in memorized yapısı ile okuma ve yazma işlemlerinde gerçekten de çok başarılıdır. Bir sonraki makalede en ucuz 5 ürün real time olarak  ekranın altında kayar band da listelenecek ve yeni bir item girildiğinde yada düzenlendiğinde yazılacak “MicroServices” ile tekrardan düzenleneceklerdir. Bu işlemler Redis’in Pub/Sub özeliği kullanılarak tetiklenecek ve sonunda gerçekten sıralamada bir değişiklik var ise signalR ile ekrana real time olarak basılacaktır. Ayrıca yine istenir ise ilgili MicroServisler’de Redis’e gelen data asenkron olarak MsSql bir database’e de basılabilir.

Bu makalenin 2.bölümünde görüşmek üzere hoşçakalın.

Not: Kaynak kodlar 2.makalenin sonunda verilecektir.

 

 

 

 

Herkes Görsün:

Sevebilirsin...

4 Yanıt

  1. Yigit dedi ki:

    Hocam elinize saglik. 2. makaleyi beklemeden devam ediyorum :)

  2. borsoft dedi ki:

    :)

Bir Cevap Yazın

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