Hash Slot Mimarisi
Redis Cluster'ın temelini oluşturan hash slot mekanizması, verilerin küme üzerinde dağıtılması için deterministik bir yöntem sunar. Bu yapı, geleneksel consistent hashing algoritmalarından farklı olarak, sabit sayıda (16384) virtüel bölme tanımlar. Her bir bölme bir hash slot'u temsil eder ve kümedeki her anahtar, bu slotlardan birine ve dolayısıyla bu slotu yöneten belirli bir ana düğüme (master) atanır. Bu mimari, veri dağılımının yönetilebilir ve tahmin edilebilir olmasını sağlar.
Slot kavramının getirdiği en önemli avantaj, küme topolojisi değiştiğinde (düğüm eklendiğinde veya çıkarıldığında) yeniden hesaplanması gereken hash aralığının sadece etkilenen slotlarla sınırlı kalmasıdır. Bu durum, veri taşınması gereken miktarı minimize eder ve kümenin yeniden dengelenmesi işlemini büyük ölçüde hızlandırır. Ayrıca, yönetimsel komutlar (örneğin CLUSTER SLOTS) ile slotların hangi düğümlerde bulunduğu net bir şekilde izlenebilir.
Slot dağılımı, küme kurulum aşamasında otomatik olarak veya yönetici tarafından manuel olarak yapılandırılabilir. Her bir ana düğüme, toplam 16384 slotun yaklaşık eşit parçalar halinde dağıtılması beklenir. Bu homojen dağılım, yük dengeli bir performans elde edilmesinin temel koşuludur.
16384 (2^14) sayısının seçilmesi teknik ve pratik sebeplere dayanır. Bu sayı, yeterince büyük olduğu için kümede çok sayıda düğüm olsa bile her birine makul sayıda slot düşmesini garantiler. Aynı zamanda, küme metadata'sının (düğüm-slot eşlemesinin) düğümler arasında iletilmesi için gereken bellek ve bant genişliği üzerinde optimize edilmiştir.
Slotların fiziksel karşılığı, bir düğümün bellek içindeki veri yapılarıdır. Her bir düğüm, kendisine atanmış slotlara karşılık gelen anahtar-değer çiftlerini saklamaktan sorumludur. Küme istemcileri, yönlendirme tablosu sayesinde bir anahtarın hangi düğüme ait olduğunu öğrenir ve isteği doğrudan ilgili düğüme yönlendirir. Bu, istemci tarafı yönlendirme (client-side routing) olarak bilinir ve merkezi bir proxy'ye ihtiyaç duyulmamasını sağlar.
- Sabit sayıda (16384) hash slot, tutarlı ve yönetilebilir bir dağıtım sağlar.
- Slotlar, düğüm ekleme/çıkarma sırasında minimal veri hareketi için temel birimdir.
- Slot-düğüm eşlemesi, küme metadata'sının merkezi bir parçasıdır ve tüm düğümler tarafından bilinir.
Sonuç olarak, hash slot mimarisi Redis Cluster'ın ölçeklenebilirliğinin ve veri tutarlılığının altında yatan temel soyutlamadır. Bu soyutlama, karmaşık bir dağıtık sistemin basit ve verimli bir şekilde yönetilmesine olanak tanır.
Slot Dağılımı ve Anahtar Hashleme
Bir anahtarın Redis Cluster'daki fiziksel konumunu belirlemek için iki aşamalı bir süreç işler. İlk aşama, anahtar isminden slot numarasının hesaplanmasıdır. Redis, bu hesaplama için CRC16 algoritmasının belirli bir varyantını kullanır. CRC16 sonucu, 16384 olası değere (0 ile 16383 arası) indirgemek için modulo 16384 işlemine tabi tutulur. Bu hesaplamanın matematiksel ifadesi şöyledir: SLOT = CRC16(key) mod 16384. Bu deterministik hesaplama sayesinde, aynı anahtar her zaman aynı slot numarasını ve dolayısıyla küme topolojisi değişmediği sürece aynı düğümü işaret eder.
Anahtar hashleme mantığı, birden fazla anahtarı aynı slot grubunda tutmayı sağlayan hash tag konseptini de destekler. Bu, çoklu anahtar işlemlerinin (örneğin, aynı hash içindeki farklı alanlar) aynı düğümde yapılabilmesi için kritiktir. Hash tag, anahtar string'i içinde `{` ve `}` karakterleri arasında belirtilen bölümdür. Örneğin, `user:{1000}:profile` ve `user:{1000}:settings` anahtarlarında, sadece `{1000}` kısmı hash hesaplamasına dahil edilir, böylece her iki anahtar da aynı slota atanır.
| Anahtar Örneği | Hash Hesaplanan Kısım | Açıklama |
|---|---|---|
product:550 |
product:550 |
Hash tag yok, tüm anahtar hashlenir. |
{cart:session}:items:123 |
cart:session |
Sadece `{}` içindeki kısım hashlenir. |
unrelated{data}key |
data |
İlk `{}` çifti arasındaki kısım kullanılır. |
İkinci aşama ise, hesaplanan slot numarasının hangi düğüme eşlendiğinin bulunmasıdır. Her Redis Cluster düğümü, kümenin güncel konfigürasyonunu içeren ve cluster bus üzerinden sürekli güncellenen bir slot-düğüm eşleme tablosu (cluster slots) tutar. Bir istemci, ilk bağlantıyı kurduğu herhangi bir düğümden bu tabloyu alır ve önbelleğine kaydeder. Bir komut gönderilirken, istemci önce anahtarın slotunu hesaplar, sonra önbelleğindeki bu tabloya bakarak komutu doğrudan ilgili düğüme yönlendirir.
Bu dağıtım mekanizması, veri erişiminde O(1) karmaşıklığı sağlar. Yönlendirme bilgisi istemci tarafında olduğu için, bir komutun işlenmesi için ek bir ağ atlaması gerekmez. Ancak, küme topolojisi değiştiğinde (örneğin, bir düğüm eklenip slotlar yeniden dağıtıldığında), istemciler bir `-MOVED` veya `-ASK` yönlendirme hatası alır. Bu hatalar, istemcinin kendi yönlendirme tablosunu güncellemesi için bir sinyal görevi görür.
// Anahtarın slot numarasını hesaplama (CRC16/Modulo kavramsal örneği)
function getSlot(key) {
// 1. Hash tag varsa, sadece {} içindeki kısmı al.
const tagMatch = key.match(/\{([^}]+)\}/);
const hashInput = tagMatch ? tagMatch[1] : key;
// 2. CRC16 hesapla (basitleştirilmiş gösterim).
const crc = calculateCRC16(hashInput);
// 3. Modulo 16384 uygula.
const slot = crc % 16384;
return slot;
}
// Örnek: getSlot("user:{1000}:name") -> {1000} kısmı hashlenir, slot 5478 olabilir.
Slot dağılımının adilliği ve hash fonksiyonunun kalitesi, kümenin genel performansını ve depolama dengesini doğrudan etkiler. İyi dağılmamış bir hash fonksiyonu, belirli düğümlerin aşırı yüklenmesine (hotspot) neden olabilir. Redis'in kullandığı CRC16 algoritması, pratikte anahtar dağılımı için yeternce uniform bir dağılım sağlar ve hash tag desteği ile geliştiricilere, ilgili verileri birlikte yerleştirme esnekliği verir.
Veri Yerleştirme ve Erişim
Redis Cluster'da veri yerleştirme stratejisi, hash slot algoritmasının deterministik çıktısına tamamen bağımlıdır. Her anahtar, hesaplanan slot numarası vasıtasıyla kümedeki tek bir ana düğüme sabitlenir. Bu sabitleme, veri yerellik ilkesini (data locality) korur ve birincil okuma-yazma işlemlerinin her zaman aynı düğümde gerçekleşmesini sağlar. Bu model, tek düğümlü Redis'teki gibi tutarlı bir programlama modeli sunarken, arka planda verilerin birden fazla makineye parçalanmış olmasını mümkün kılar.
İstemci tarafından gönderilen bir komutun işlenme süreci, gelişmiş bir yönlendirme katmanını içerir. Akıllı bir Redis Cluster istemcisi, başlangıçta rastgele bir düğümden alınan slot-düğüm haritasını (CLUSTER SLOTS komutunun çıktısı) saklar. Bir SET veya GET komutu gönderileceği zaman, istemci anahtarı işaret eden slotu hesaplar, haritada bu slotu yöneten düğümü bulur ve TCP bağlantısını doğrudan o düğüme yönlendirir. Bu, merkezi bir proxy olmaksızın doğrudan düğüme erişim (direct node access) sağlar ve gecikmeyi minimize eder.
Anahtarın hedef düğümde olmadığı durumlar, yönlendirme hatası mesajları ile ele alınır. Eğer bir istemci yanlış düğüme bir komut gönderirse, Redis düğümü bir hata ile cevap verir. -MOVED hatası, slotun kalıcı olarak başka bir düğüme taşındığını ve istemcinin kendi haritasını güncellemesi gerektiğini belirtir. Örneğin, -MOVED 3999 192.168.1.35:6379 yanıtı, 3999 numaralı slotun artık belirtilen IP ve porttaki düğümde olduğunu söyler. Modern istemci kütüphaneleri bu hatayı otomatik olarak yakalar ve haritalarını şeffaf bir şekilde günceller.
Çoklu anahtar işlemlerinin (multi-key operations) sınırlaması, bu mimarinin önemli bir kısıtıdır. MGET, MSET veya SUNION gibi komutlar, tüm ilgili anahtarların aynı hash slotunda bulunması koşuluyla desteklenir. Aksi takdirde, Redis Cluster -CROSSSLOT hatası döndürür. Bu sınırlama, hash tag'lerin ({...}) kullanımını kritik bir mühendislik kararı haline getirir. İlişkili verilerin aynı tag ile etiketlenmesi, atomik çoklu anahtar işlemlerinin mümkün olmasını sağlar.
| Yönlendirme Durumu | Döndürülen Hata | İstemci Davranışı | Arka Plandaki Neden |
|---|---|---|---|
| Slot başka bir düğümde | -MOVED <slot> <ip:port> |
Yönlendirme haritasını kalıcı günceller, komutu yeni düğüme yönlendirir. | Resharding veya düğüm hatası sonrası slot kalıcı taşınmıştır. |
| Slot geçici olarak başka düğümde | -ASK <slot> <ip:port> |
Haritayı güncellemez, sadece bu komut için yeni düğüme yönlenir, ASKING komutunu gönderir. |
Resharding sırasında, kaynak düğümden hedef düğüme veri taşınırken. |
| Anahtarlar farklı slotlarda | -CROSSSLOT |
Komutu reddeder, işlemi gerçekleştirmez. | Çoklu anahtar komutunda kullanılan anahtarlar aynı hash slotuna hashlenmemiştir. |
Veri erişim performansını optimize etmek için, istemci kütüphanelerinin bağlantı havuzu (connection pooling) ve düğüm önbelleği (node caching) mekanizmalarını etkin kullanması gerekir. Her ana düğüm için ayrı bir bağlantı havuzu oluşturmak, sürekli yeni bağlantı kurma maliyetini ortadan kaldırır. Ayrıca, sık erişilen düğümlerin adreslerinin önbellekte tutulması, her istekte slot hesaplama ve harita arama işlemlerinin yükünü azaltır. Bu optimizasyonlar, küme üzerinde tek düğüm performansına yakın bir gecikme süresi elde etmek için hayati öneme sahiptir.
Son olarak, okuma işlemleri için çoğaltma düğümlerinden (replica nodes) okuma özelliği, ana düğüm yükünü dengelemek için kullanılabilir. İstemciler, READONLY modunu etkinleştirerek, bağlı oldukları düğüm bir çoğaltma olsa bile okuma isteklerini yerel olarak işletebilir. Bu, anahtara göre yapılan yönlendirmeyi değiştirmez, ancak istemcinin bağlandığı çoğaltma düğümü, kendi ana düğümünden gelen verileri sunar. Bu dağıtım, tutarlı okuma (strong consistency) garanti etmez ancak sonunda tutarlılık (eventual consistency) modelinde yüksek okuma ölçeklenebilirliği sağlar.
Yeniden Şeritleme (Resharding) Süreci
Yeniden şeritleme, Redis Cluster'ın dinamik ölçeklenebilirliğini sağlayan en kritik operasyonel süreçtir. Bu işlem, hash slotlarının kümedeki mevcut ana düğümler arasında yeniden dağıtılması anlamına gelir. Kapasite artırımı (yeni düğüm ekleme) veya azaltımı (düğüm çıkarma) durumlarında, veri dağılımını yeniden dengelemek ve her düğümün yükünü eşitlemek için zorunlu olarak uygulanır. Resharding, küme çalışır durumdayken (online), istemci operasyonlarına minimum kesinti ile gerçekleştirilebilir.
Süreç, redis-cli --cluster reshard aracı veya düşük seviyeli CLUSTER komutları kullanılarak yönetilir. Operatör, taşınacak toplam slot sayısını ve bu slotların hangi hedef düğüme alınacağını belirler. Araç daha sonra, kaynak düğümlerin seçimini otomatik olarak yapabilir veya operatör belirli kaynak düğümleri de seçebilir. Her bir slotun taşınması, atomik bir birim olarak ele alınır; bir slottaki tüm anahtar-değer çiftleri birlikte taşınır.
Slot taşıma işlemi, kaynak ve hedef düğümler arasında senkronize bir protokol ile gerçekleşir. Hedef düğüm, CLUSTER SETSLOT <slot> IMPORTING <source-node-id> komutu ile belirli bir slotu "içe aktarma" (importing) durumuna getirir. Eş zamanlı olarak, kaynak düğüm CLUSTER SETSLOT <slot> MIGRATING <target-node-id> komutu ile aynı slotu "dışa aktarma" (migrating) durumuna getirir. Bu iki komut, slotun geçiş durumunu küme metadata'sında işaretler ve diğer düğümlerin bu durumu öğrenmesini sağlar.
Gerçek veri transferi, MIGRATE komutu ile yapılır. Bu komut kaynak düğümde çalıştırılır, belirtilen anahtarı serileştirir (serialize), hedef düğümle bir TCP bağlantısı kurar ve anahtarı orada yeniden oluşturur. Taşıma sırasında, kaynak düğümdeki anahtar silinir. MIGRATE atomik bir işlemdir; ya başarılı olur ya da hiçbir değişiklik olmaz. Slot içindeki tüm anahtarlar için bu işlem tekrarlanır. Bu sırada, taşınmakta olan slota gelen istemci istekleri özel mantıkla ele alınır.
İstemci, taşınmakta olan bir slota erişmeye çalıştığında iki özel durumla karşılaşabilir. Eğer anahtar hala kaynak düğümdeyse, işlem normal şekilde yürütülür. Eğer anahtar artık kaynak düğümde yoksa (taşınmışsa), kaynak düğüm istemciye bir -ASK yönlendirme hatası döndürür. -MOVED hatasından farklı olarak, -ASK hatası istemcinin kalıcı yönlendirme tablosunu güncellemesini gerektirmez. İstemci sadece bu tek istek için hedef düğüme bağlanır ve komutu göndermeden önce ASKING komutunu yürütür. Bu geçici yönlendirme mekanizması, resharding sırasında kullanılabilirliği maksimuma çıkarır.
# Yeniden şeritleme işleminin adımları (Kavramsal)
# 1. Hedef düğümü içe aktarma durumuna getir.
CLUSTER SETSLOT 5000 IMPORTING <source-node-id>
# 2. Kaynak düğümü dışa aktarma durumuna getir.
CLUSTER SETSLOT 5000 MIGRATING <target-node-id>
# 3. Slot 5000'deki anahtarları tek tek taşı (redis-cli aracı bunu otomatik yapar).
MIGRATE target-host target-port "" 0 5000 KEYS key1 key2 key3...
# 4. Slotun sahipliğini tüm düğümlerde hedef düğüm olarak ayarla.
# (Her düğümde çalıştırılır)
CLUSTER SETSLOT 5000 NODE <target-node-id>
Resharding'in güvenli bir şekilde tamamlanabilmesi için, işlem sonunda kümedeki tüm düğümlerin config epoch değerlerinin güncellenmesi ve slot sahipliği bilgisinin mutabakata varılması gerekir. Config epoch, küme konfigürasyon değişikliklerinin versiyon numarasıdır ve en yüksek epoch'a sahip düğümün bildirimi geçerli kabul edilir. CLUSTER SETSLOT ... NODE komutu bu epoch'u artırarak çalışır. Bu dağıtık mutabakat mekanizması, ağ bölünmeleri (split-brain) sırasında bile tutarlı bir küme görünümünün korunmasını sağlar.
Sonuç olarak, yeniden şeritleme süreci Redis Cluster'ı statik bir parçalı veritabanı olmaktan çıkarır ve ona dinamik bir elastik yapı kazandırır. Ancak, bu operasyonun planlı bir bakım penceresinde, düşük trafik dönemlerinde ve yeterli ağ bant genişliği varlığında yapılması önerilir. Büyük slotların veya çok sayıda slotun taşınması, ağ tüketimini artırabilir ve MIGRATE komutunun bloklayıcı doğası nedeniyle kaynak düğümde kısa gecikme artışlarına neden olabilir.
Çoğaltma ve Hata Toleransı
Redis Cluster'ın hata toleransı modeli, her bir ana (master) düğüm için bir veya daha fazla çoğaltma düğümü (replica/slave) tanımlanması üzerine kuruludur. Bu çoğaltma düğümleri, ana düğümlerin hash slotlarında bulunan verilerin tam bir kopyasını asenkron olarak senkronize eder. Birincil amaç, ana düğümün arızalanması durumunda yüksek kullanılabilirlik (high availability) sağlamaktır. Çoğaltma düğümü, bağlı olduğu ana düğümün tüm veri değişikliklerini sürekli alır ve aynı veri setini korur.
Failover (başarısızlığa geçiş) süreci, dağıtık bir oluşum (consensus) algoritması tarafından yönetilir. Kümedeki tüm ana düğümler, oy kullanma hakkına sahiptir ve her biri belirli aralıklarla diğer tüm düğümlere ping paketleri gönderir. Bir ana düğüm, yapılandırılan süre (NODE_TIMEOUT) içinde diğer ana düğümlerin çoğunluğundan yanıt alamazsa, bu düğümün başarısız olduğu ilan edilir. Bu tespitin ardından, başarısız ana düğüme ait çoğaltma düğümlerinden biri, diğer ana düğümlerden oylama (vote) toplayarak kendini yeni ana düğüm olarak yükseltmeye çalışır.
Başarılı bir failover için, oyların çoğunluğunun (N/2 + 1) alınması şarttır. Bu mekanizma, ağ bölünmelerinde (network partition) birden fazla ana düğümün aynı slot için yükselmesini engeller ve bölünmüş beyin (split-brain) senaryosunu önler. Failover tamamlandığında, yeni ana düğüm üzerindeki slotların sahipliği güncellenir ve bu bilgi tüm kümeye yayılır. İstemciler, bağlandıkları düğümlerden alacakları -MOVED yanıtları ile bu değişikliği öğrenir ve yönlendirme tablolarını günceller.
- Ana düğüm erişilemez hale gelir ve NODE_TIMEOUT aşılır.
- Diğer ana düğümler, başarısız düğümü
FAILdurumuna işaretler. - İlgili çoğaltma düğümleri, bir failover seçimi başlatır.
- Ana düğümler, çoğaltma düğümlerinin failover isteklerini oylar.
- Yeterli oyu alan bir çoğaltma, yeni ana düğüm olur ve slot sahipliğini devralır.
Çoğaltma düğümleri sadece yüksek kullanılabilirlik için değil, aynı zamanda okuma ölçeklenebilirliği için de kullanılabilir. İstemciler, bir çoğaltma düğümüne bağlanıp READONLY komutunu çalıştırarak, yazma işlemleri hariç tüm okuma isteklerini bu düğümden karşılayabilir. Bu, ana düğümün yükünü önemli ölçüde azaltır. Ancak, asenkron çoğaltma nedeniyle, bir çoğaltma düğümünden okunan veri ana düğümdeki en güncel veriden biraz eski olabilir (staleness).
| Hata Senaryosu | Küme Tepkisi | Kullanılabilirlik Etkisi | Veri Kaybı Riski |
|---|---|---|---|
| Tek bir ana düğüm çöker. | Çoğaltması failover ile ana düğüm olur. Slotlar erişilebilir kalır. | Yok. Otomatik kurtarma. | Ana düğüm çökmeden önce ağa yazılan, çoğaltmaya henüz ulaşmamış veri kaybedilebilir. |
| Bir ana düğüm ve onun tüm çoğaltmaları aynı anda çöker. | İlgili slotlar erişilemez hale gelir. Küme FAIL durumuna geçer. |
Kritik. O slotlardaki veriye erişilemez. | Çökene kadar yazılan tüm veri kaybolur (o düğüm grubundaki). |
| Ağ bölünmesi (Network Partition). | Çoğunluğu oluşturan tarafta failover başlatılır. Azınlık taraftaki düğümler yazmaya kapalı kalır. | Kısmi. Azınlık tarafındaki istemciler yazamaz ama okuyabilir (eski veri). | Bölünme çözüldüğünde, eski ana düğüm çoğaltma olarak yeniden katılır ve veri senkronizasyonu ile çözülür. |
Hata toleransı konfigürasyonunda NODE_TIMEOUT parametresi çok önemlidir. Bu değer, bir düğümün ne kadar süreyle yanıtsız kalması durumunda başarısız kabul edileceğini belirler. Çok kısa bir timeout, gereksiz failover'lara neden olabilir. Çok uzun bir timeout ise, gerçek bir arızada kullanılabilirliğin düşmesine yol açar. Benzer şekilde, çekirdek sayısı (quorum) ve çoğaltma sayısı, sistemin dayanıklılığını doğrudan etkiler. En az bir çoğaltma ile, bir ana düğüm hatasında veri kaybetmeden kurtarmak mümkündür, ancak her ana düğüm için iki çoğaltma, daha yüksek dayanıklılık sağlar.
Redis Cluster'ın çoğaltma ve hata toleransı mekanizmaları, onu üretim ortamlarında kullanıma uygun hale getiren temel bileşenlerdir. Asenkron çoğaltma yüksek performansı korurken, dağıtık oylama ile yönetilen otomatik failover, operatör müdahalesi olmaksızın sürekliliği sağlar. Bu mimari, CAP teoremi çerçevesinde tutarlılık (Consistency) ve kullanılabilirlik (Availability) arasında, ağ bölünmeleri durumnda kullanılabilirliği bir miktar sınırlayarak (azınlık tarafında yazmaya izin vermeyerek) denge kurar.