Hakkında
Redis (REmote DIctionary Server), veriyi key-value şeklinde in-memory (hafıza/RAM) tutan açık kaynaklı bir veritabanıdır. Key-value şeklini Dictionary’den hatırlarsınız. Benzersiz bir Id’ye (key) karşılık bir değer (value) tutar. Veriyi RAM’de tutuyor olması sunucunun kapanması ile verinin tümden yok olması anlamına geliyor. Tabi bunu diske yazmanız mümkün fakat en temel haliyle Redis, veriyi RAM’de kullanmak için tasarlandı. Çünkü bilinen en hızlı yöntemlerin başında bu geliyor. Ayrıca ilişkisel (İVTYS = İlişkisel Veritabanı Yönetim Sistemi) veritabanlarının tümünden hızlıdır.
Farklılıkları
Redis’i anlamamız için en azından bir parça da olsa NoSQL’i anlamamız gerekir. Redis gibi veritabanlarını relational veritabanlarından ayıran en önemli nokta hiç belirgin ilişkisinin veya SQL’in olmaması. Relational veritabanında kayıtlar tablolarda ve bu tabloların aralarında da Foreign Key’ler (bağ) mevcut. Tipik veritabanlarında karşılıklı kolon bağlanması ile sunulan veri Redis’tekinden farklı. Veri gösterimi ele alındığında NoSQL yaklaşımı daha esnek.
Redis, diğer NoSQL yaklaşımlarından da biraz farklı. Mesela RavenDB veya MongoDB gibi. Bunlar doküman veritabanı olarak adlandırılıyor. Diske yazılıp, indexlenebiliyor (aynı SQL Server veya Oracle’daki tablo indexleri gibi). Redis’te ise veri tutarken key kullanılır ve veri kaydedilirken birden fazla veri tipi kullanma imkanımız var fakat indexleme sunmuyorlar. Bunun için kendi kodumuzu yazmamız gerekiyor. Kulağa biraz garip gelebilir, sonuçta veritabanı dendiğinde içerisinde index hizmeti de bekliyoruz. Bunun sebebi SQL Server, Oracle, MongoDB vs. SQL komutu çalıştırır yani sorgulamaya (query) izin verirler. Redis izin vermiyor. Redis sadece belirli key’e atanmış değeri verir. Yani, Redis’in sorgulamaya izin vermiyor olması dezavantaj gibi görünüyor. Sonuçta sorgulama hakkından kim vazgeçmek ister? Fakat emin olun Redis’in de uygulamanızın mimarisinde kullanılabileceği gerçeği hala kaya gibi duruyor. Verinin nasıl kaydedileceği ve kaydedilen veriye nasıl erişilebileceğine dair ufak bir çalışma ile kayıtlarınız muazzam hızlarda elinize gelecektir.
Yükleme
Redis, Windows işletim sistemi destekli değil. Piyasada unofficial yani yetkili olmayan Windows port versiyonları da mevcut. Linux kurulumu yapmayacağım için yetkili olmayan bir versiyon üzerinden işlemlerimizi yapacağız.
Redis’i yüklemek için bu linkten son sürümü indirip, kurun. Kurulum basit. Kurulum bittikten sonra “Services” alanından çalışıp çalışmadığına bakın (pre-release versiyon olmasın, sorun olabilir)
https://github.com/MicrosoftArchive/redis/releases
Server tarafını hallettik. Gelelim client tarafına. Client tarafında kullanabileceğimiz çok kütüphane var. Redis sunucuna bağlanmak için kullanılan bağlantı protokolü en temel seviyede olduğu için çoğu platform ve programlama dilimi tarafından kolaylıkla adapte edilebiliyor.
NOT : Redis Server kurulurken default port 6379 atanıyor.
NOT 2 : Redis CLI kullanmak istiyorsanız iki yöntem var.
- Github bağlantısından zip dosyasını indirirseniz (release -> şu an Redis-x64-3.0.504.zip) içerisinde redis-cli.exe ve redis-server programlarını göreceksiniz (önerilen yöntem)
- Github bağlantısından kaynak kodunu indirip, projeyi derleyin. Projeyi derlediğinizde size 5 adet .exe üretecek. Bunlardan bir tanesi CLI (client). CLI ile local’de bulunan Redis sunucuda komutlar çalıştırabileceğiz. Projeyi derleyebilmek için “Desktop Development with C++” modülü yüklü olmalı. (bkz. Visual Studio Installer) Derlenme hatası alırsanız projelere sağ tıklayıp “Platform Toolset” ve “Windows SDK Version” kısmını güncelleyin. Visual Studio 2017 ve Windows 10 kullanıyorsanız Platform Toolset’i v.140’a, SDK bilgisini de Windows 10’a çevirin. (Default hali Windows 8.1)
Nasıl Çalışır
Redis’in çalışma mantığı aşağıdaki resimde de gördüğünüz gibi oldukça basit. Redis sunucusu, belirli bir port üzerinden client (istemci) aracılığıyla gelen istekleri dinler. Client herhangi bir yazılım parçası olabilir. Çünkü Redis, çok fazla dil desteği bulundurduğu için implamantasyonu kolay. Client, Redis protocol (TCP) aracılığıyla Redis’le iletişime geçer ve komutları gönderir ve sunucu da bunları işler. Redis hızını bu basitlikten alır. Query veya index yok.
Redis Veri Tipleri ve Komutlar
Redis’i kullanırken key-value tabanlı olduğunu ve verilen key’e karşılık atanmış değeri tuttuğunu belirttik. Atanan değerin tipi sadece string değil aksine daha da kompleks tiplere destek veriyor. Beş farklı veri tipinin kaydı mümkün. Şimdi bu veri tiplerini ve en bilindik komutlarını inceleyelim. (Tüm komut listesini görmek bkz. isterseniz => https://redis.io/commands)
NOT : Lokalde Redis DB testlerinizi gerçekleştirirken kayıtlarınızı silmek isterseniz
- Tüm veri tabanlarından kayıtları silmek isterseniz flushall
- Bağlantınız üzerindeki mevcut veri tabanından silmek için flushdb
yazın.
1. Strings
Redis’de veri tutmanın en basit hali. Key’e atanmış string değeri belirtir. String değerin metin olmasına gerek yok. String ve 512 MB’dan daha az yer kapladığı sürece sorun yok. Tüm objeyi serialized formatta tutmak en bilinen yöntemlerden bir tanesi.
SET / GET : Değer atama / okuma
INCR / DECR : Text’in veri tipi int (rakam) ise INCR ile değerini artırıp DECR ile de değerini azaltabiliriz
MSET / MGET : Birden fazla değer atama / okuma
APPEND : Kayıt birleştirme
GETRANGE : Değerin belirli bir kısmını (substring gibi) döner
STRLEN : Değeri uzunluğunu döner
2. Lists
Metinsel ifadeler listesini temsil ediyor. Tüm programlama dillerinin ortak ögelerinden List, listeye eklenme sırasına göre sıralama uygular. Listelerin kuyruk gibi kullanıldığı durumlar da mevcut.
LPUSH / RPUSH : Listenin başına / sonuna kayıt ekleme
LPOP / RPOP : Listenin başından / sonundan kayıt silme
LREM : Listeden kayıt silme
LSET : Belirtilen index (sıra no.) sonucu kayıt ekleme
LINDEX : Belirtilen index’e göre kayıt getirme
LRANGE : Belirtilen aralıkta kayıtları getirir
LLEN : Listenin uzunluğunu getirir
LTRIM : Belirtilen aralıkta listeyi keser
3. Sets
Benzersiz metinsel ifadelerin bulunduğu liste. Bir kaydın listede olup olmadığını kontrol etme ihtiyacı yok ve sıralama tutmaz.
SADD : Listeye kayıt ekleme
SCARD : Listeden kayıt döner
SDIFF, SINTER, SUNION : Difference, Intersection, Union matematiksel işlemleri
SISMEMBER : Kayıt listede mevcut mu değil mi kontrolü
SMOVE : Bir listenin kayıtlarını diğer listeye taşıma
SREM : Listeden kayıt silme
4. Hashes
String alanlara karşılık atanmış string değerleri mapler. Bir objenin birden fazla değeri olabilir. Hash, Redis tarafından optimize edilmiş, yüzlerce alan olmadıkça kullanımı efektiftir.
HSET / HGET : Kayıt atama / alma
HMSET / HMGET : Çoklu kayıt atama / alma
HGETALL : Tüm kayıtları döndürür
HDEL : Kayıt silme
HEXISTS : Kayıt var mı kontrolü
HINCRBY : Integer (rakam) kaydın değerini artırma
HKEYS / HVALS : Tüm anahtar (key) / değerleri döndürür
5. Sorted Sets
Sorted Set’in Set’ten tek farkı her elemanının bir skoru var ve bu skor Set içerisindeki sırayı temsil ediyor. Ekleme, silme ve güncelleme işlemlerinde oldukça hızlıdır.
ZADD : Bir veya birden fazla kayıt ekleme. Kayıt varsa score güncellenir
ZCARD : Setteki kayıtların sayısını döndürür
ZCOUNT : Setteki belirli aralıkta score’u bulunan kayıtları döndürür
ZINCRBY : Setteki kaydın score değerini artırır
ZRANGE : Setteki belirli aralıkta kayıtları döner (index’e göre)
ZRANK : Setteki kaydın index bilgisini döner
ZREM : Bir veya birden fazla kaydı silme
ZSCORE : Setteki kaydın score’unu döner
Redis veri tipleri ile ilgili bilgi almak isterseniz buraya tıklayın => https://redis.io/topics/data-types
Message Bus
Redis’in message bus olarak kullanılabilmesi mümkün. Böylece belirli kanallara belirli mesajlar iletilip client’ların da bu belirli kanallardan verileri okuması mümkün oluyor.
Yukarıdaki örnekte önce tek bir kanala publish ettim daha sonra isim benzerliği olan kanalları dinlemek için başka bir subscribe client yarattım.
Transaction Desteği
Redis transaction desteği sunuyor. Birden fazla Redis komutunu tek bir kerede çalıştırabilirsiniz fakat rollback yok. Exec komutu çalıştırır, discard ise iptal eder. Redis transaction atomic’tir. Dikkat edilmesi gereken nokta; bu işlemin başında Redis multi komutu çalıştırılır. Sonrasında kuyruğa alma sırasında alınan hatada diğer komutlar çalışmaz fakat kuyruk işleminden sonra, transaction gerçekleşirken hata alınırsa diğer komutlar çalıştırılır.
Önce ilk ekranda işlem yaptım fakat exec komutunu işletene kadar işlem yapılmadı. Kuyruğa (QUEUED) alındı. 2. ekranda ise işlem direkt uygulandı ve bundan sonra ilk ekrandaki exec çalıştırıldı. Exec komutu 2. ekranın sonucu (hesap1’e 100 eklenmesi) üzerinden işlem yaptı. (İlk ekradaki -50 ve 50 ekleme işlemleri atomic gerçekleşti). Concurrency işlemleri için bkz. watch komutu.
C# ve Redis
Bu zamana kadar komutları direkt command line tool ile çalıştırmıştık. Şimdi ise programatik yoluna bakalım. Redis implamantasyonu için kullanacağımız open source paketin ismi ServiceStack.Redis. Bu paket bizim client uygulamamızı Redis sunucu ile konuşturacak ve komutları çalıştıracak bir kütüphane. ServiceStack sadece Redis implamantasyonu sağlamıyor. Redis’in yanı sıra ORMLite ve diğer hizmetleri de sunuyorlar fakat biz Redis adaptörünü kullanacağız. ServiceStack.Redis’i kullanabilmek için ServiceStack bilmemize gerek yok.
ServiceStack.Redis paketi içerisinde kullanabileceğimiz 4 adet interface var. Bu interface’ler uygulamınızda kullanacağınız katmanı (abstract layer) temsil ediyor. En uygun olanı uygulamamızda kullanacağız.
ICacheClient : Redis’in cache gibi uygulandığı anlarda kullanılır.
IRedisNativeClient : Düşük seviyeli (low level) bir interface çünkü Redis üzerindeki düşük seviyeli komutları çalıştırır. Command line tool aracılığıyla çalıştırdığımız komutları düşünebilirsiniz. Veri byte dizisi şeklinde gönderilir böylece tam kontrol sağlanır.
IRedisClient : Yüksek seviyeli bir interface. Redis üzerindeki çalışan tüm komutları destekler. Veri string şeklinde gönderilir. Bu da bizim gönderme ve alma işlemleri öncesinde ekstra efora sürüklüyor.
IRedisTypedClient : Redis işlemlerinde direkt olarak tip kullanılması. Convert (dönüştürme) işlemlerine gerek yok. Veriler serilalization/deserialization işlemlerinden geçer ve unique Id bile üretebilir.
Sınıf hiyerarşisi şu şekilde
RedisTypedClient (POCO) > RedisClient (string) > RedisNativeClient (raw byte[])
Aşağıdaki resimde de Redis API’nin bir parçasını görebilirsiniz.
Şimdi öncelikle Redis sunucuya bağlanmaya çalışalım. Redis-cli’yi çalıştırarak sunucuda çalıştırılacak komutları monitor edeceğiz. Sunucuda çalıştıracak komutları da programımızdan göndereceğiz.
Uygulamanıza ServiceStack.Redis nuget paketini kurduğunuz zaman
- ServiceStack.Common
- ServiceStack.Interfaces,
- ServiceStack.Text (serialize/deserialize)
paketleri de dependency’den ötürü yükleniyor.
IRedisNativeClient ile ilk denememizi yapalım.
IRedisClient ile örnek yapalım.
C# ile yaptığımız örneklerin tümüne kaydetmek istediğimiz verileri string veri tipi aracılığıyla gerçekleştirdik. Şimdi direkt tip kullanarak yapalım. Verinin kaydedilirken uygulanacak serialize/deserialize işlemleri ile ilgili tek bir satır kod yazmamıza bile gerek yok, kendisi bu işi bizim için hallediyor.
Transaction konusuna da bakalım. Kaydetmek istediğim değer 1 ve bu değeri 1 artırıyorum. Sonuç 2.
Son olarak Publish ve Subscribe işlemleri
Publish
Subscribe