.net uygulamalarında redis kullanımı
.Net Uygulamalarında Redis Kullanımı
İÇİNDEKİLER
- Redis Nedir ?
- Redis Deployment
- Redis Çalıştırma
- Redis Konsol
- .Net Redis İmplementasyonu
- Session Provider olarak Redis
Redis Nedir ?
Redis; açık kaynak, in-memory çalışan nosql veritabanıdır. https://github.com/redis/redis adresinde reposu yer almaktadır.
Yüksek performanslı servis olup, bu özelliğinde C dili ile yazılmış olmasının katkısını yabana atmamak gerekir. Linux dağıtımlarında sorunsuz çalışmaktadır. Redis’in bize sunduğu (en azından uygulamalarınızdaki gözlemlerimiz) avantajları vardır.
Avantajları
- Yüksek Performans
in-memory çalıştığı için; verileri sabit diskte tutmak yerine, Ram üzerinde tutar. Veri erişimi Ram seviyesinde olmaktadır. -
Yedeklilik
Redis, master-slave mimarisinde çalışır. Etkin servis Master tanımlanan servistir.Slave üzerindeki tüm veriler master’in birer kopyası olarak çalışır.Master servisi fail olduğunda, slave pozisyondaki servis,master pozisyonuna geçer. -
Veri Tipi Çeşitliliği
Redis verileri ram üzernde key,value çift olarak tutmaktadır. Verilerdeki key karşılıkları farklı tiplerdeki veriler olabilmektedir. Başlıca desteklediği veri tipleri; String ,List, Set, Hash, Bitmaps, HyperLogLogs - Çoklu Dil İmplementasyonu
Redis, Bir çok programlama dilinde destek vermektedir. Bunlar Java,C#,Python,C,C++,Node.js,R,Go,Ruby. vb.Kurumsal Uygulama
Kurumsal uygulama yöntemi olarak docker üzerinde ayağa kaldırmayı tercih ediyoruz. Bu sebeple docker üzerinde redis servisi ayağa kaldırma yöntemlerinden bahsediyor olacağız.
Redis Deployment
Docker üzerinde Redis Kurulumu
Docker; windows 10 işletim sisteminde https://docs.docker.com/docker-for-windows/install/ adresinden indirip kuruyoruz. Docker’in windows için GUI içeren uygulamasıdır. GUI üzerinde image ekleyip yönetebiliyorsunuz. Biz konsol üzerinden işlemlerimizi ilerleteceğiz.
Uygulamayı kurduktan sonra windows komut satırında(cmd) docker komutu ile kurulup kurulmadığını kontrol edebilirsiniz.
C:\>docker
komut çıktısında; docker komutlarını içeren bir help mesaj çıktısı alınacaktır. Şİmdi gelelim Redis imajını alıp docker üzerinde ayağa kaldırmaya.
Docker’ın kendi sitesinde Redis imajı ile ilgili dokuman mevcuttur. https://hub.docker.com/_/redis adresinden erişime açıktır.
Redis imajını çekelim(105 MB)
c:\docker pull redis
Redis Ayağa Kaldırma
Kısa sürede Redis Containeri oluşturduk. Şimdi Redis’i ayağa kaldıralım. Redis varsayılan olarak 6379 portunu kullanır.
docker run -d -p 6379:6379 redis
Komut detayı :
- -d : detached modda çalışsın
- -p 6379:6379 hostun 6379 numaralı portunu container üzerindeki 6379 numaralı porta map et.
komut başarıyla işlendikten sonra, kurduğumuz docker GUI ekranında redis containerin in-use olduğunu göreceksiniz.
Redis Ayarlar
Redis Network Ayarları
Redis default 6379 portunu kullanır. Host cihazdaki 6379 portunu container’ın 6379 portuna map ediyoruz. Böylelikle cihazın 6379 portuna gelen istekler, Redise yönlendirilecektir. Bu ayarı yapmadıysanız:
C:\>docker inspect ff614abe7f23 --> container ID ya da adı
komutu ile redis container network ayarlarını gözlemleyebiliriz. Network Settings altında Ports parametrelerinden gereken düzenleme aşağıdaki gibi yapılabilmektedir.
"NetworkSettings": {
"Bridge": "",
"SandboxID": "19af672cb7172912db59b5a964ef489eaad4e7cd64dad78e17960f9e1da001a5",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"6379/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "6379"
}
]
},
Redis Konsol
Docker üzerinde Redis Cli Erişim
Docker konsol üzerinde container ile ilgili bilgi almak için;
C:\>docker container ls
komutu uyguladıktan sonra konsolda , kurulu ve çalışan konteynırlar listelenecektir.
C:\>docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ff614abe7f23 redis "docker-entrypoint.s…" 9 minutes ago Up 9 minutes 0.0.0.0:6379->6379/tcp admiring_morse
görüldüğü gibi Redis imajından oluşturduğumuz container ayakta ve 6379 portunda dinleme yapıyor.admiring_morse adında ve ff614abe7f23 ID’ye sahip bir yapımız var. Şimdi Redis Konsola Docker üzerinden erişim sağlayacağız.
C:\>docker exec -it ff614abe7f23 redis-cli
127.0.0.1:6379>
Yukarıdaki komut seti ile docker üzerinde ID ile belirttiğimiz Redis container konsoluna erişim sağladık. Erişim sağladıktaın sonra redis cli’a bağlanmış oluyoruz.
Test
Redis cli bağlantısından sonra cli üzerinde ilk test çalışmamızı gerçekleştirelim.
127.0.0.1:6379> Set name Test
OK
127.0.0.1:6379> get name
"Test"
127.0.0.1:6379>
Dotnet Uygulamasında Redis İmplementasyonu
.Net Uygulamamızda, Redis client işlemleri için Nuget PM üzerinden ServiceStack.Redis kütüphanesini kullanıyor olacağız.
Senaryo
Birimimiz tarafından geliştirilen açık kaynak yayınlanan Web tabanlı Aktif Dizin Yönetim Uygulamasında, AD veritabanındaki kullanıcı ve cihazları redis’e alıp, sorguları redis üzerinde gerçekleştirmek.
Uygulama
Uygulamamızı Asp.net MVC model-view yapısı üzerinde geliştirdik.
RedisManager > Redis işlemlerini yapacağımız Sınıf
Arayüz tanımlama:
public interface IRedisManager
{
bool IsKeyExist(string key);
void SetKeyValue(string key, string value);
string GetKeyValue(string key);
bool StoreList<T>(string key, T Value, TimeSpan timeout);
T GetList<T>(string key);
}
public class RedisManager:IRedisManager
{
RedisEndpoint _redisEndpoint;
public RedisManager()
{
_redisEndpoint = new RedisEndpoint(_redisHost, _redisPort);
}
// Key Redis veritabanında var ise true döner
public bool IsKeyExist(string key)
{
using (var client = new RedisClient(_redisEndpoint))
{
return client.ContainsKey(key);
}
}
// Key set edilir
public void SetKeyValue(string key, string value)
{
using (var client = new RedisClient(_redisEndpoint))
{
client.SetValue(key, value);
}
}
// Key karşılık değeri geriye döndürülür.
public string GetKeyValue(string key )
{
using (var client = new RedisClient(_redisEndpoint))
{
return client.GetValue(key);
}
}
// Generic yapıda key kontrolü
public bool StoreList<T>(string key, T Value, TimeSpan timeout)
{
try
{
using (var client = new RedisClient(_redisEndpoint))
{
client.As<T>().SetValue(key, Value, timeout);
}
return true;
}
catch (Exception)
{
throw;
}
}
// Generic: Key karşılık değeri döndürülür.
public T GetList<T>(string key)
{
T result;
using (var client = new RedisClient(_redisEndpoint))
{
var wrapper = client.As<T>();
result = wrapper.GetValue(key);
}
return result;
}
}
RedisEndpoint Sınıfı, ServiceStack.Redis kütüphanesinden implement edilen, redis servis bağlantısını yapacağımız sınıftır.
RedisClient sınıfı,ServiceStack.Redis kütüphanesinden implement edilen, redis işlemlerini yapan sınıf.
_redisHost = Redis Servisinin İP’si
_redisPort: Redis Port
Redis İşlemleri için sınıfı tanımladıktan sonra, Web Uygulamamızda redis işlemlerine devam edelim.
### Aktif Dizin Kullanıcıları Listeleme
Aktif Dizin veritabanında kayıtlı kullanıcıları , kullanıcı arayüzünde listeleyeceğiz.
İş Planı şu şekilde olacak :
- Kullanıcı Listesi için uygulama Redis Servisine istek atacak
- Redis Servisinde UserList Key değeri var ise, Redis Servisinden, GetList() Methodu ile ilgili veriyi alacağız
- Redis Servisinde UserList key değeri yok ise; Aktif Dizin Veritabanından listeyi alıp, redis’e StoreList methodu ile ekleyeceğiz.
- Tekrar Redis Servisinden Kullanıcı Listesini isteyeceğiz.
Görüldüğü gibi senaryonun ektin rolü redis üzerindedir. Tüm sorguları onun üzerinde kontrol edip, yok ise DB’ye erişim sağlıyor olacağız.
Kullanıcı işlemlerini yaptığımız UserController içerisinde ilgili düzenlemeleri yapıyoruz.
public ActionResult KullaniciListele()
{
List<UserEntities> userList;
// Kullanıcı Redis'te var mı
if (_redisManager.IsKeyExist("UserList"))
{
userList = _redisManager.GetList<List<UserEntities>>("UserList");
}
else
{
var usersFromServer = KullaniciGetir(); // Aktif dizin veritabanında kullanıcıları getiren method
_redisManager.StoreList<List<UserEntities>>("UserList",usersFromServer,TimeSpan.MaxValue); //AD DB'den alınan kullanıcı listesi UserList Key adı ile Redise yazılıyor.
userList = _redisManager.GetList<List<UserEntities>>("UserList"); // Redisten UserList key değer karşılığı çekiliyor.
}
return View(userList);
}
Performans
İlgili düzenlemeden sonra sorgu süresi 6sn’den 150 ms seviyesine inmiştir. Redis Servisi cache hizmetinden beklentimizin üzerinde performans karşılığı alınmıştır..
Session Provider olarak Redis
Redis’in muazzam özelliklerinden birisine daha değineceğiz.Redis’i web uygulamalarında session yöneticisi olarak ayarlayabiliyoruz. Böylece sunucu üzerinden bu yükü alıp, redis’e aktarmış oluyoruz.
Örnek Uygulama İle Session Yönetimi
Asp.Net uygulamamızda, Redis ile Session yönetimi için, npm ile RedisSessionStateProvider paketini kurduk.
Session verileri, Redis tarafında Redis Hash veri tipinde saklanır. RedisSessionStateProvider paketini kurduktan sonra web.config dosyası içerisinde,
Örnek :
<sessionState mode="Custom" customProvider="MySessionStateStore">
<providers>
<!-- For more details check https://github.com/Azure/aspnet-redis-providers/wiki -->
<!-- Either use 'connectionString' OR 'settingsClassName' and 'settingsMethodName' OR use 'host','port','accessKey','ssl','connectionTimeoutInMilliseconds' and 'operationTimeoutInMilliseconds'. -->
<!-- 'throwOnError','retryTimeoutInMilliseconds','databaseId' and 'applicationName' can be used with both options. -->
<!--
<add name="MySessionStateStore"
host = "127.0.0.1" [String]
port = "" [number]
accessKey = "" [String]
ssl = "false" [true|false]
throwOnError = "true" [true|false]
retryTimeoutInMilliseconds = "5000" [number]
databaseId = "0" [number]
applicationName = "" [String]
connectionTimeoutInMilliseconds = "5000" [number]
operationTimeoutInMilliseconds = "1000" [number]
connectionString = "<Valid StackExchange.Redis connection string>" [String]
settingsClassName = "<Assembly qualified class name that contains settings method specified below. Which basically return 'connectionString' value>" [String]
settingsMethodName = "<Settings method should be defined in settingsClass. It should be public, static, does not take any parameters and should have a return type of 'String', which is basically 'connectionString' value.>" [String]
loggingClassName = "<Assembly qualified class name that contains logging method specified below>" [String]
loggingMethodName = "<Logging method should be defined in loggingClass. It should be public, static, does not take any parameters and should have a return type of System.IO.TextWriter.>" [String]
redisSerializerType = "<Assembly qualified class name that implements Microsoft.Web.Redis.ISerializer>" [String]
/>
-->
<add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="127.0.0.1" accessKey="" ssl="false" />
</providers>
</sessionState>
Yukarıda yer alan ayarlarda, “add name” etiketi içerisinde gereken ayarı yapıyoruz. Önemli nokta Redis host ve port bilgilerinin belirtilmesi. Port belirtilmez ise default 6379 portunu kullanacaktır. lokalde çalıştığımız için ssl attribute değerini false yaptık.
config tarafı bu kadar. Şimdi gelelim örnek kodlara.
Controller :
public class HomeController : Controller
{
public ActionResult Index()
{
Session["Username"] = "Test";
Session["LoginTime"] = DateTime.Now;
return View();
}
}
View :
<!DOCTYPE html>
<html>
<body>
<div class="container">
@Session["Username"] | @Session["LoginTime"]
</div>
</body>
</html>
Redis tarafındaki Key ve data takibi için Another Redis Desktop Manager adlı uygulamayı kullanmaktayız. Bu uygulama üzerinde ilgili oturuma ait verileri görebilmekteyiz.