• Çar. Ara 25th, 2024

Arif GÖKÇE

Senior Software Engineer

Redis’te Master-Slave ve Sentinel Yapıları

Byarifgokce

Mar 12, 2019

Bu yazıda Redis’in en kullanışlı, ilginç ve eğlenceli Sentinel özelliğinden bahsedeceğim. Ancak önce master-slave yapısını anlamamız gerekiyor. Teknik detaylara geçmeden önce kısaca hikayesini anlatayım:

Redis, bir NoSQL veritabanıdır ve verileri anahtar-değer ikilisi (key-value pair) şeklinde saklar, ve bu verilere hızlı erişim sağlar. Bu nedenle özellikle cache işlemleri için yoğun olarak kullanılır.

Verilere erişim için master-slave yapısını da sunar. Slave, master’ın bir kopyasıdır yani master güncellendikçe slave de güncellenir.

Slave’ler varsayılan olarak sadece okunabilir (read-only) olarak ayarlanmıştır. Yani sadece verilere okuma işlemi yapabilirler. Ancak read-only özelliği devre dışı bırakılabilir ve yeni kayıtlar eklenerek güncellenebilir. Ancak bu kayıtlar sadece slave’e eklenir, yani slave master’ı güncelleyemez. Böylece, Redis’ten sadece veri okuma işlemi yapmak istediğimiz bir program varsa, güvenli erişimi slave üzerinden sağlayabiliriz.

Bir master’a birden fazla slave eklemek mümkündür. Hatta slave’lere de slave eklenebilir.

Sentinel yapısı ise oldukça kullanışlı ve ilginç bir yapıdır. Sentinel’ler, Redis örneklerini (instance) takip ederler. Eğer master başarısız olursa veya hizmet veremez hale gelirse, ve yeterli sayıda sentinel bunu tespit ederse, master’ı görevinden azlederler ve oy çokluğu ile bir slave’i yeni master olarak atarlar. Diğer slave’leri de “Yeni kral yaşasın!” diyerek yeni master’a yönlendirirler.

Uygulama

Master-slave yapısını bir örnek üzerinden inceleyelim. Önce Redis’i indirmemiz gerekiyor. İlgili işlemi şuradan gerçekleştirebilirsiniz. Örnekte, Windows işletim sistemi üzerinden anlatacağım. İndirme tamamlandığında aşağıdaki gibi bir dosya yapısı görünecektir:

Redis master-slave yapısını kullanabilmek için öncelikle redis-server.exe uygulamasını çalıştırarak sunucu uygulamayı başlatıyoruz ve ekranda ilgili bir ekran görüntüsü beliriyor.

Redis sunucusunu başlattıktan sonra, varsayılan olarak 6379 portunu dinlediğini unutmayın. redis-cli.exe’yi çalıştırarak Redis komut satırı arabirimine erişebilirsiniz. Ardından aşağıdaki basit komutları kullanarak 6 tane key ve değer çifti oluşturabilir ve keys komutu ile key’leri, get komutu ile herhangi bir key’in değerini görüntüleyebilirsiniz.

Redis sunucu (server) ve istemci (client) ile çalışıyoruz. Kolaylık sağlamak için Redis’i indirdiğimiz konumda bulunan redis.windows.conf dosyasını kopyalayıp düzenleyebiliriz.

Dosyada ilk olarak “port” kısmını “port 6390” olarak değiştiriyorum. Ardından yorum satırı olan “slaveof” satırını da aşağıdaki gibi, master IP ve portunu belirterek düzenliyorum.

Redis sunucu (server) ve istemci (client) ile çalışırken localhost’tan yayın yaptığım için IP adresini 127.0.0.1 olarak belirledim ve master sunucunun yayın yaptığı portu kullandım. Yeni oluşan config dosyasını redis-server.exe üzerine sürükleyip bıraktığımda slave sunucu da ayağa kalkıyor.

Daha sonra komut istemcisini (redis-cli.exe) açıyorum ve Redis’i indirdiğim klasöre gidiyorum. redis-cli.exe -h 127.0.0.1 -p 6390 komutunu kullanarak slave istemcisini çalıştırıyorum. (h ve p harfleri host ve port kelimelerinin baş harfleridir) Sonra keys “*” komutunu çalıştırdığımda, daha önce master’da eklediğim kayıtları görebiliyorum, yani master’da set ettiğim key’ler slave sunucuya da yansımış durumda.

Sentineller Sentinel oluştururken dikkat etmemiz gereken önemli noktalardan biri sentinellerin sayısıdır. Konfigürasyonları yaparken sentineller için karar yeter sayısını (quorum) belirliyoruz. Örneğin, 3 sentinel oluşturacaksak bu sayıyı 2 olarak belirleyebiliriz. 5 sentinel olacaksa 3 veya 4 yapabiliriz. İlla belirli bir sayı olacak demek yerine mimarinin kurgusuna göre bir sayı belirlemek gerekiyor. Bunun için de örnek senaryoları incelemekte fayda var.

Redis, sitesinde oldukça detaylı bir dokümantasyon sunuyor ve ben de bu dokümanlardaki senaryoları sıralayacağım:

M1, M2, M3.. — Masterlar

R1, R2, R3.. — Slaveler(Replicalar)

S1, S2, S3.. — Sentineller

C1, C2, C3.. — Clientlar

Kutu: Farklı bir bilgisayar veya sanal makine

1. Senaryo: 2 sentinelli yapı

Bu senaryoda karar yeter sayımız (quorum) 1 olarak belirlenmiştir.

Burada M1’in başına bir şey geldiğinde, 2 sentinel de erişemediği konusunda uzlaştığından aralarından 1 tanesi (S2) bir Redis örneğine (R1) erişebildiği için R1 master seviyesine yükseltilir. Eğer soldaki kutunun başına bir şey gelirse S1 de duracak ve S2’nin uzlaşabileceği bir sentinel olmayacağı için sistem tamamen çökecektir. Diyelim ki kutular ayakta, ancak birbirleri arasındaki bağlantı koptu ve varsayalım ki R1 aşağıdaki gibi master oldu:

Burada başta birbirine simetrik olarak 2 farklı sistem oluşacak, ancak daha sonra birbirinden alakasız hale gelecek. Bu yüzden Redis bize en az 3 kutu ve en az 3 sentinelle kurgumuzu oluşturmamızı öneriyor.

Senaryo: 3 kutu ile temel kurulum

Şimdi 3 kutu ile aşağıdaki gibi basit bir kurulum yaptığımızı düşünelim:

M1 ile diğer kutular arasındaki bağlantı koparsa, S2 ve S3 uzlaşamayabilir ve sistemde bir master seçilemeyebilir. Bu yüzden, Redis’in önerdiği gibi en az 3 kutu ve en az 3 sentinelle kurgu oluşturmak önemlidir. Bu, sistemin yüksek güvenilirlik ve tolerans sağlamasını sağlar.

M1’in master olduğu bir senaryoda, M1’de yaşanan bir sorun nedeniyle istemci (C1) M1’e yazmaya devam ederse, bu yazılan veriler tamamen kaybolabilir. Çünkü M1, bir kez azledildiği için yeni master’a biat eder ve slave olarak devam eder. Bu tür bir durumu engellemek için Redis’in “min-slaves-to-write” ve “min-slaves-max-lag” gibi konfigürasyon ayarları kullanılabilir. Örneğin, “min-slaves-to-write” ayarı, M1’in en az kaç slave’den veri alması gerektiğini belirleyebilir ve “min-slaves-max-lag” ayarı ise slave’lerin M1’e olan veri gecikmesini sınırlayabilir. Bu ayarlar, M1’in kendini istifa etmesini (downsize) sağlar ve 10 saniye boyunca en az 1 slave’den veri alamazsa, M1 kendiliğinden istifa eder. Ancak, Redis’in de belirttiği gibi, herhangi bir ayarın tamamen sorunları çözmediği ve 2 slave’in devre dışı kalması gibi senaryolarda hâlâ sistemde sorunlar yaşanabileceği unutulmamalıdır. Bu nedenle, Redis’in önerdiği en az 3 kutu ve en az 3 sentinelle kurgu, daha güvenli bir yaklaşım olarak tercih edilebilir.

Senaryo: Sentinelleri istemci kutularında konumlandırma

Redis için sadece 2 kutu bulunduğunu düşünelim. Bu durumda birini master, diğerini slave olarak ayarlayabiliriz. Ayrıca sentinelleri de istemci kutularına yerleştirerek aşağıdaki gibi bir yapı oluşturabiliriz:

Bu senaryoda, sentineller ve istemciler aynı durumdadır ve Redis örneğine müşterilerin çoğu erişebiliyorsa, durum uygun olarak kabul edilir. Ancak, M1 ve S1’e ulaşılamaz hale gelirse, kalan sentineller R1’i master olarak belirleyebilir. Bu durumda ise, sentineller ayarlanamayacağı için Redis kutuları ile aradaki bağlantı kopmuş olabilir.

Diyelim ki C3 ile M1 ayrı bir yere taşındı. Bu durumda kalan sentineller R1’i master olarak seçecek ve paralel yapılar oluşacaktır. Sonuç olarak, 2. senaryoda olduğu gibi problemler yaşanabilir.

Senaryo: 3’ten az istemci ve her yerde sentineller

yukardaki senaryodaki yapı için elimizde 3 istemci yok diyelim. Aşağıdaki gibi ortaya karışık bir yapı kurabiliriz:

Bu senaryo, elimizde dört Redis kutusu ve dört sentinel bulunduğunu varsayıyoruz. Eğer M1 (master) kullanılamaz hale gelirse, diğer üç sentinel yük devretme işlemini gerçekleştirir.

Bu senaryolar daha da çeşitlendirilebilir. Önemli olan, elimizdeki kaynakları ve durumları göz önünde bulundurarak avantaj ve dezavantajları değerlendirerek kendimize uygun bir senaryo oluşturabilmektir.

Demo Şimdi basit bir örnekle, kişisel bir bilgisayarda farklı portlar kullanarak olaya bir göz atalım.

Yukarıda bir master (port 6379) ve bir slave (port 6390) oluşturduk. Aynı yöntemi kullanarak 2. bir slave daha oluşturuyoruz (port 6391). Ardından hepsine keys komutunu çalıştırıyoruz (en üstteki master’a ait client):

Şimdi sentinel için bir konfigürasyon dosyası oluşturuyorum. Aşağıdaki değerleri yazıp, sentinel1.conf diye kaydediyorum (İsimlerinden anlaşılacağını düşünerek değerlerin detayına girmiyorum):

port 5000
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

Sonra command prompt ile dosya yoluna gidip aşağıdaki komutu çalıştırıyorum:

Aşağıdaki gibi bir ekran açılıyor:

Portları değiştirerek sentinel2.conf (port 5001) ve sentinel3.conf (port 5002) dosyalarını oluşturuyorum ve aynı şekilde çalıştırıyorum. Şu anda sistemde 1 master, 2 slave ve 3 sentinel bulunmaktadır.

Not: Doğrulamak için netstat -ab komutunu kullanarak kullanılan portları da görebilirsiniz:

Şimdi master uygulamasını erişilmez hale getirelim. Uyutarak -geçici süreliğine- bu işlemi gerçekleştirebilirim. Master’a bağlı redis-cli uygulamasına aşağıdaki komutu giriyorum:

Sonra sentinellerde bazı olaylar meydana geliyor:

Gözlemlediğiniz gibi, master’a ulaşılamadığında sentineller hemen oylama yaparak, ilk başta oluşturduğumuz slave’i (port 6390) yeni master olarak seçiyorlar.

Bu örnekle Redis’in master-slave ve sentinel yapılarını inceledik.