Redis’te veri tipi seçerken soracağınız soru “veriyi nasıl okuyup değiştireceğim?” sorusudur. Belgenin kısa özeti şöyledir: tek parça metin, ikili veri veya sayaç için string; az sayıda düz alanı olan nesneler için hash; iç içe ve çok alanlı belgeler için JSON; tekil öğeler için set; skorlu veya sıralı öğeler için sorted set; kuyruk ve yığın için list; zaman sıralı olay kayıtları ve birden fazla okuyucu için stream; tamsayı indeksle adreslenen seyrek diziler için de Redis 8.8 ile gelen array. Konum, yaklaşık sayım, zaman serisi ve vektör gibi özel işler için ayrıca özelleşmiş tipler vardır.

Bu yazı, resmî “Compare data types” sayfasındaki karar ağaçlarını Türkçe olarak adım adım uygular. Her tipin komutlarını burada anlatmıyoruz; her tip için ayrı bir yazımız var ve ilgili yerlerde bağlantı veriyoruz. Serinin tamamı için Redis öğrenme rehberine bakabilirsiniz.

Redis bir veri yapısı sunucusudur

Belge Redis’i bir veri yapısı sunucusu olarak tanımlar: önbellekten kuyruğa, olay işlemeye kadar birçok problemi çözen yerleşik veri tipleri sunar. Genel amaçlı tiplerin özellikleri birbiriyle örtüşür; belge, biraz yaratıcılıkla hepsini yalnızca string kullanarak taklit edebileceğinizi bile söyler. Ama her tip performans, bellek kullanımı ve işlev açısından farklı ödünleşimler sunar. Doğru tip, işin çoğunu sunucuda tek komutla yapmanızı sağlar; yanlış tip ise veriyi istemciye çekip orada işlemeye, dolayısıyla daha fazla ağ trafiğine ve yarış durumlarına yol açar.

Belge, tiplerin bir kısmını çok belirli amaçlar için özelleşmiş, diğerlerini genel amaçlı olarak ayırır. Özelleşmiş tipler şunlardır: koordinatlı stringler için coğrafi (geospatial) indeksler, büyük veri kümelerinde yaklaşık sayım ve istatistik için olasılıksal tipler, zaman damgalı gerçek sayı ölçümleri için time series ve vektör benzerlik sorguları için vector set. Genel amaçlı tipler ise string, array, hash, JSON, list, set, sorted set ve stream’dir.

Genel amaçlı tiplerin özeti

TipYapıTemel işlemlerUygun olduğu işler
StringYapısız metin veya ikili veri, sayaç, bit kümesiget, set, append, artırma, azaltma, bit işlemleriYapısız belgeler, sayaçlar, bayraklar, bitmap
ArraySeyrek, indeksle adreslenen string dizisiget, set, sil, aralık okuma, sıralı ekleme, toplamaOlay kayıtları, halka tampon, sensör okumaları
HashAlan-değer çiftleriget, set, sil, artırma, sorguAz alanlı basit nesneler
JSONİç içe diziler ve nesnelerget, set, güncelle, sil, sorguÇok alanlı, iç içe karmaşık nesneler
ListBasit string dizisipush, pop, get, set, trimKuyruk, yığın, kayıt
SetTekil stringlerekle, sil, üyelik, kesişim, birleşim, farkEk verisi olmayan tekil öğeler
Sorted setSkorlu tekil stringlerekle, sil, üyelik, skor veya sıraya göre aralıkSkorlu öğeler, sıralı koleksiyonlar
StreamAlan-değer çiftli kayıtlardan oluşan diziekle, oku, kırpKayıt verisi, zaman serisi, yalnızca eklenen yapılar

Tablodaki satırları biraz açalım. String, iç yapısını uygulamanızın yönettiği metin veya ikili parçalar için idealdir; ama bit aralıklarına erişen komutlarla bit kümesi, tamsayı ya da kayan nokta sayı olarak da kullanılabilir. Hash, iç içe olmayan az sayıda alanı olan nesneler için düşünülmüştür, ancak alan sayısında gerçek bir sınır yoktur; alan değerleri string olsa da tamsayı ve kayan nokta aritmetiği yapan komutları vardır, tek tek alanlara süre verilebilir ve Redis Search ile indekslenebilir. JSON iç içe alanlar ve dizilerle zengin modelleme sunar, belgenin herhangi bir alt kümesine yol sözdizimiyle erişilir ve Redis Search tarafında hash’e göre daha esnek özelliklere sahiptir.

List, baştan ve sondan az sayıda eleman eklemek ve çıkarmak için optimize edilmiştir; bu yüzden kuyruk, yığın ve iki uçlu kuyruk için çok verimlidir. Set üyelik testi, ekleme ve çıkarmayı verimli yapar ve kesişim, birleşim, fark işlemlerini destekler. Sorted set, skora dayalı aralık sorguları için optimize edilmiştir ve öncelik kuyruğu gibi sıralı koleksiyonlarda kullanılır. Stream yeni kayıt eklemek ve kayıtları sırayla okumak için optimize edilmiştir; ayrıca birden fazla okuyucuyu yöneten ve en az bir kez teslimi sağlayan tüketici gruplarını yerleşik olarak destekler. Array ise değerleri tamsayı indeksle tutar; belgeye göre rastgele erişim dizinin mantıksal boyutundan bağımsız olarak O(1)’dir ve dizi seyrek olduğu için 1.000.000 numaralı indekse yazmak aradaki boş yuvalar için bellek ayırmaz.

Her tipin ayrıntılı yazısı: string, array, hash, JSON, list, set, sorted set ve stream.

Doküman verisi: string, hash mi JSON mu?

Doküman verisi: string, hash mi JSON mu? İç içe veri yapılarına (alanlar ve diziler) veya Redis Search ile..., İç içe yapı ve coğrafi indeks olmadan Redis Search ile indeksleme...

Bir kullanıcı profili, ürün kartı veya ayar nesnesi gibi doküman verisini normalde string, hash veya JSON ile saklarsınız. Belge, bellek ve işlem gereksiniminin en yüksek JSON’da olduğunu, onu hash’in, en düşük olanın da string olduğunu belirtir. Karar ağacı şu soruları sırayla sorar ve ilk “evet” cevabında durur:

  • İç içe veri yapılarına (alanlar ve diziler) veya Redis Search ile coğrafi indeksleme ve sorguya ihtiyacınız var mı? Evet ise JSON kullanın. Belgeye göre derin iç içe yapıları destekleyen ve bu yapılar için Redis Search ile bütünleşen tek doküman tipi JSON’dur.
  • İç içe yapı ve coğrafi indeks olmadan Redis Search ile indeksleme ve sorgulama gerekiyor mu? Evet ise hash kullanın. Hash’ler indeksleme ve sorgulamayı JSON’a göre daha az bellekle ve daha hızlı alan erişimiyle destekler.
  • Doküman içindeki tek tek parçalara ayrı süre vermeniz gerekiyor mu? Evet ise hash kullanın. Alan düzeyinde verimli erişim ve süre yalnızca hash’lerde vardır.
  • Tek tek alanlara sık erişiyor musunuz ve bu alanlar bir tamsayı indeksle gösterilebilen basit tamsayılar veya bitler mi? Evet ise string kullanın. Yalnızca tamsayı indeksli bit alanlarına ihtiyacınız varsa string daha kompakt ve verimlidir.
  • Tek tek alanlara sık erişiyor musunuz ve bu alanlar string veya ikili değer mi? Evet ise hash kullanın. Hayır ise, yani dokümanı hep bütün olarak okuyup yazıyorsanız string yeterlidir ve daha kompakttır.

Bu ağacın pratik anlamı şudur: dokümanı her seferinde bütün olarak okuyup yazıyorsanız (örneğin önbelleğe alınmış bir API yanıtı) serileştirilmiş string en ekonomik seçenektir. Tek bir alanı, örneğin ürünün stok sayısını sık sık güncelliyorsanız hash bu alanı bütün dokümanı yeniden yazmadan değiştirmenizi sağlar. Doküman iç içe diziler içeriyorsa veya bu yapı üzerinde sorgu yapacaksanız JSON gerekir. Hash alanlarına süre vermek için hash alan süresi, indeksleme için Redis Search yazısına bakın.

Koleksiyonlar: set, sorted set, hash veya bitmap

Bir grup öğeyi, örneğin bir kullanıcının etiketlerini, bir makalenin beğenenlerini veya çevrimiçi kullanıcıları saklarken genellikle set veya sorted set kullanırsınız; çok basit koleksiyonlarda string bile yeterli olabilir. Hepsi temel üyelik testini destekler. Bellek ve işlem maliyeti en yüksek olan sorted set’tir, onu set ve en son string izler. Karar ağacının soruları:

  • Öğeleri belirli bir sırayla veya sözlük sırasıyla saklayıp okumanız gerekiyor mu? Evet ise sorted set. Sıralı gezinmeyi destekleyen tek koleksiyon tipi odur.
  • Her öğe için ek bilgi saklamanız gerekiyor ve küme işlemlerine (birleşim, kesişim, fark) ihtiyacınız yok mu? Evet ise hash. Hash her öğeye veri bağlamanızı sağlar ama küme işlemlerini desteklemez.
  • Öğeler her zaman bilinen bir aralıktaki basit tamsayı indeksler mi? Evet ise string üzerinde bitmap. Bitmap en düşük bellek yüküyle tamsayı indekslere verimli rastgele erişim sağlar ve bit işlemleri küme işlemlerinin karşılığıdır.
  • Hiçbiri değilse set kullanın.

Belge yararlı bir ipucu da verir: set veya sorted set içindeki öğeler için ek bilgi saklamanız gerekiyorsa, alan adları koleksiyondaki öğelerle eşleşen yardımcı bir hash veya JSON nesnesi kullanabilirsiniz. Böylece hem küme işlemlerini hem de öğe başına veriyi elde edersiniz. Bitmap için bitmap ve bitfield, çok büyük kümelerde yalnızca tekil sayıya ihtiyacınız varsa HyperLogLog yazısına bakın.

Sıralar: sorted set, array, stream veya list

Sıralar: sorted set, array, stream veya list: Keyfi bir öncelik sırası, sözlük sırası ya da küme işlemleri..., Elemanlara sizin seçtiğiniz bir tamsayı indeksle (seyrek veya...

String veya ikili değerlerden oluşan sıraları, yani sırası önemli olan veri dizilerini sorted set, list, stream veya array ile saklarsınız. Karar ağacı:

  • Keyfi bir öncelik sırası, sözlük sırası ya da küme işlemleri gerekiyor mu? Evet ise sorted set. Hem sıralamayı hem küme işlemlerini destekleyen tek sıra tipi odur.
  • Elemanlara sizin seçtiğiniz bir tamsayı indeksle (seyrek veya aralıklı indeksler dahil) erişmeniz, indeks aralıkları üzerinde sunucu tarafında toplama (toplam, en küçük, en büyük, bit işlemleri) yapmanız ya da en eski kayıtların üzerine yazan sabit boyutlu bir halka tampon kullanmanız gerekiyor mu? Evet ise array.
  • Elemanları öncelikle zaman damgası sırasıyla saklayıp okumanız ya da diziyi okuyan birden fazla tüketiciyi yönetmeniz gerekiyor mu? Evet ise stream. Zaman damgasına dayalı sıralamayı ve en az bir kez teslimli tüketici gruplarını destekleyen tek sıra tipi odur.
  • Hiçbiri değilse list kullanın.

Bu ağacın en sık kullanılan iki dalı list ve stream’dir. Basit bir iş kuyruğu için list yeterlidir ve iş kuyruğu yazımız bunu anlatır. Aynı olayları birden fazla bağımsız servisin okuması veya bir tüketici çöktüğünde mesajın başka bir tüketiciye geçmesi gerekiyorsa stream ve consumer group doğru araçtır. Skora göre sıralanan bir tablo için ise sorted set kullanılır; örnek uygulama leaderboard yazısında.

Özelleşmiş tipler ne zaman gerekir?

Genel amaçlı tiplerle çözülebilecek bazı işler için Redis özel yapılar sunar ve bunlar çoğu zaman daha az bellekle ve tek komutla sonuç verir. Belirli bir yarıçap veya kutu içindeki konumları bulmak için coğrafi indeksler (geo komutları); bir öğenin bir kümede olup olmadığını yaklaşık olarak test etmek için Bloom ve Cuckoo filtreleri (Bloom filtresi); bir değer akışında frekans, sıralama veya yüzdelik tahmini için count-min sketch, Top-K ve t-digest; zaman damgalı ölçümleri saklayıp toplamak için time series (time series) kullanılır. Vektör benzerlik araması için vector set tipi vardır; bu seri vektör aramayı ayrıntılı ele almıyor.

Redis 8.0 sürüm notlarına göre Redis Community Edition’ın adı Redis Open Source olarak değişti ve Search, JSON, time series ve olasılıksal tipler bu dağıtımın içinde gelmeye başladı. Daha eski bir sunucuda bu tipler ayrı modül olarak kurulmuş olabilir veya hiç bulunmayabilir.

Uygulamalı bir örnek: e-ticaret verisini tiplere dağıtmak

Karar ağaçlarını bir arada görmek için küçük bir e-ticaret sitesini düşünelim. Aşağıdaki eşleştirme belgedeki kuralların uygulanmasıdır; kendi erişim desenleriniz farklıysa sonuç da farklı olabilir.

VeriErişim biçimiAğacın önerdiği tip
Önbelleğe alınmış ürün listesi yanıtıHep bütün olarak okunur ve yazılırString
Ürün kartı (ad, fiyat, stok)Stok alanı sık güncellenir, iç içe yapı yokHash
Varyantları ve özellik dizileri olan ürünİç içe yapı ve sorgu gerekiyorJSON
Bir ürünü favorileyen kullanıcılarTekil öğe, kesişim gerekebilirSet
En çok satan ürünlerSkora göre sıralı okumaSorted set
Sipariş e-postası gönderme işleriBasit kuyruk, tek tüketiciList
Sipariş olaylarıBirden fazla servis okur, zaman sırası önemliStream
Sayfa görüntüleme sayacıAtomik artırmaString (INCR)

Tablodaki her satır bir anahtar ailesine karşılık gelir; anahtarları tutarlı bir önekle adlandırmak hem okunabilirliği artırır hem de farklı tipleri aynı ada yazma hatasını önler. Adlandırma için anahtar isimlendirme yazısına bakın.

Tip uyuşmazlığı: TYPE ve WRONGTYPE

Her anahtar tek bir veri tipi taşır ve her komut yalnızca bir tiple çalışır. Bir listeyi GET ile okumaya çalışmak gibi uyuşmazlıklarda Redis WRONGTYPE Operation against a key holding the wrong kind of value hatasını döndürür. Bir anahtarın tipini TYPE komutuyla öğrenirsiniz; resmî hata sayfası da ilk adım olarak bunu önerir:

text
> RPUSH mylist "a"
(integer) 1
> GET mylist
(error) WRONGTYPE Operation against a key holding the wrong kind of value
> TYPE mylist
list

Hata sayfası üç olası neden sayar: başka bir tip için yazılmış bir komut kullanmak, uygulamanın iki bölümünün aynı anahtar adını farklı veriler için kullanması ve anahtarın uygulamanın eski bir sürümünden kalma veri taşıması. Veri modelinizi değiştirirken eski tipteki anahtarları temizlemeyi unutmak bu hatanın sık rastlanan kaynağıdır. Diğer hata mesajları için Redis hata mesajları yazısına bakın.

Yerleşik tipler yetmezse

Belge, yerleşik tiplerin özelliklerini genişletmek için iki yol gösterir: Lua ile kendi sunucu tarafı fonksiyonlarınızı yazmak ya da modül API’siyle bir Redis modülü geliştirmek. Çoğu uygulama için ilk yol yeterlidir; birden fazla komutu tek bir atomik işlemde birleştirmek için Lua script ve Redis Functions yazılarına bakın.

Sık yapılan hatalar

Sık yapılan hatalar: Her şeyi JSON string olarak saklamak, Sıralama gereken yerde set kullanmak, Çok tüketicili olay akışını list ile kurmak, Ek bilgi için koleksiyonu bırakmak
  • Her şeyi JSON string olarak saklamak: Tek bir alanı değiştirmek için bütün dokümanı okuyup yazmak gerekir; sık güncellenen alanlar için hash daha uygundur.
  • Sıralama gereken yerde set kullanmak: Set sırasızdır; sıra gerekiyorsa sorted set seçin.
  • Çok tüketicili olay akışını list ile kurmak: Birden fazla okuyucu ve teslim takibi gerekiyorsa stream ve tüketici grupları vardır.
  • Ek bilgi için koleksiyonu bırakmak: Öğe başına veri gerekiyorsa koleksiyonun yanında yardımcı bir hash tutabilirsiniz.
  • Sürüm kontrolü yapmamak: Array tipi Redis 8.8, birçok özel tip de Redis 8.0 öncesinde ayrı modül gerektirir.

Sık Sorulan Sorular

Nesne saklamak için hash mi JSON mu kullanmalıyım?

İç içe alanlar ve diziler yoksa hash daha az bellek kullanır ve alanlara daha hızlı erişir; tek tek alanlara süre de verebilirsiniz. İç içe yapı veya bu yapı üzerinde sorgu gerekiyorsa JSON seçin.

Kuyruk için list mi stream mi?

Tek tüketicili basit kuyruklarda list yeterlidir. Zaman sırasına göre okuma, birden fazla tüketici ve en az bir kez teslim gerekiyorsa stream kullanın.

Set ile sorted set arasındaki fark nedir?

İkisi de tekil öğeler tutar. Sorted set her öğeye bir skor bağlar ve skora veya sıraya göre aralık okumayı sağlar; bunun karşılığında daha fazla bellek ve işlem harcar.

Her şeyi string ile yapamaz mıyım?

Belge teknik olarak mümkün olduğunu kabul eder, ama her tip farklı performans, bellek ve işlev ödünleşimleri sunar. Uygun tip seçildiğinde işin çoğu sunucuda tek komutla yapılır.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Redis öğrenme rehberi · Hash komutları · JSON komutları · Sorted set · Streams