MongoDB Replica Set Kullanımı
MongoDB, şüphesiz son 5 yılın en iyi NoSQL veritabanı çözümlerinden bir tanesi. Foursquare gibi büyük firmalar tarafında kullanıldığı öğrenilince, insanlar kendi sistemlerinde ciddi veri saklama çözümleri için bir heyecanla MongoDB kullanmaya çalışıyor. Evet MongoDB bir çok alanda veri saklama işinde çok yararlı olabilir, ama inanın yanlış kullanıldığı takdirde sizin bir numaralı kabusunuz da olabilir…. MongoDB Replica Set kullanımı ile ilgili internette çok fazla döküman var ama tam olarak çalıştırabileceğiniz şekilde Replica Set kurulumunu anlatan bir kaynak yok. Bu yazıda sizlere adım adım nasıl kurulacağını anlatacağım.
Yüksek hit alan sistemlerde veri saklama işini yaparken verilerin en az bir kopyasının olması(redundancy) ve yüksek erişilebilir(high availability) olması olmazsa olmazlardandır. Biz bunu MongoDB de Replica Set ile yapacağız.
Replica Set Nedir?
Aynı veri setini barındıran ve yöneten bir grup mongod servisleridir. Replica Set in öncelikli amacı datanın redundant ve high available olmasını sağlamaktır. Verilerin kopyası birden fazla sunucuda tutulduğu için, herhangi bir sunucuda donanımsal sıkıntı yaşadığınız zaman, ayni veri baska sunucudan okunabilir. Daha sonra sıkıntı giderildiğinde başka sunucudan aynı veri sorun yaşanan sunucuya otomatik olarak senkronize edilir. Ya da başka bir senaryo düşünürsek, aynı veri birden fazla sunucuda var demiştik. Okuma işlemi yaparken hep aynı sunucudan okumak yerine okuma yükü verinin kopyasının olduğu sunuculara dağıtılır. Dolayısıyla veri okuma ya da yazma hızı artırılmış olur.
Replica Set Yöntemleri
MongoDB Replica Set oluşturmak için gerekli üye sayısı tek sayı olmalıdır. Mesela aşağıdaki 3 üyeli bir Replica Set. Gördüğünüz üzere bir tane Primary üye iki tane Secondary üye var. Diyelim ki sizin bir uygulamanız var ve bu uygulama MongoDB ye bağlanıp belirli işlemler yapıyor. Siz herhangi bir yazma işlemi yaptığınızda Primary üye bu isteği alıp kendi log sistemi olan oplog a yazar. Buraya ayzmasının sebei, daha sonra Secondary üyeler tarafından okunup Secondary üyelerin kendi veritabanlarina yazması için gerekli olmasıdır.
Şimdi de başa bir yönteme göz atalım. Bu senaryomuzda ise kalıcı bir Primary üye olmayacak, yeri geldiğinde Secondary üyeler Primary olabilecek. Peki neden böyle bir duruma ihtiyaç duyulsun? Diyelim ki Primary üyenin bulunduğu makine kapandı, bu durumda yazma isteklerini karşılayacak bir üye de olmayacak. Yani sistemde data kaybı olacaktır. Ama siz mimarinizi değiştirip, Primary kapandığında ya da Primary üye 10 saniyeden fazla bir süre diğer üyelerle iletişim kuramadığında, geri kalan üyeler kendi aralarında karar verip Primary üye seçerlerse sistem normal işleyişine devam edebilecektir. Bu mimariyi iki şekilde yapabilir siniz:
Burada yeni bir üye tipi var: Arbiter. Bu üye hiçbir şekilde veri işlemi yapmaz sadece Primary üye seçimi yapılırken seçmen sayısının tek sayının katı olması için vardır. Yani sadece seçim işleminde rol oynar. Daha önce de demiştik, Replica Set üye sayısı tek sayı olmalıdır. Peki neden 2 tane Secondary ve tek Primary yok? Aslında onu da yapabilirsiniz ama eğer 2 tane Secondary kullanmaya gerek yok ise, Arbiter kullanmak sizin veritabanı maliyetinizi düşürecektir.
Bu şekilde de Primary üye bir şekilde kapanırsa eğer, geri kalanlar kendi aralarında Primary seçeceklerdir.
Son olarak, Replica Set’ten veri okuma işlemi genelde Primary üye üzerinden yapılır ama siz okuma stratejinizi değiştirip sadece Secondary üyeden okuma işlemi yap diyebilirsiniz. Bu konuyla ilgili detaylı bilgiyi buradan bulabilirsiniz.
Kurulum İçin Gereksinimler
Kurulum sırasında birden fazla sunucuya (ya da sanal makine de olabilir) ihtiyacımız olacak. Aslında aynı makine üzerinde birden fazla mongod servisini ayrı portlarda da çalıştırabiliriz, ama gerçek yaşamdaki kullanıma yakın olsun diye farklı sunucularda kurarak anlatmayı tercih ediyorum. Ama birden fazla suncuyu nerde bulacağız diyebilirsiniz. Hiç sorun değil, lokal makinenize docker kurup birden fazla linux container ayağa kaldırıp bunlara kurulum yapacağız. Docker kurulumu ile ilgili detaylara burada değinmeyeceğiim, isteyen şuradan nasıl kurulduğuna bakabilir. Kurulum esnasında kullandığım docker komutlarından kısaca bahsediyor olacağım.
Replica Set kurulumundan önce size tek bir mongod servisinin nasıl kurulduğunu göstereceğim. Bu Replica Set kurulumu yaparken işinize yarayacak.
MongoDB kurulumu
Docker kurduktuna sonra ubuntu kullanacağız ama öncelikle indirmemiz gerekiyor. docker pull ubuntu komutunu çalıştırarak indirme işlemi tamamlayın. Daha sonra docker images komutunu çalıştırınca listede ubuntu imajını görmeniz lazım. Şimdi ubuntu imajını kullanarak bir tane container ayağa kaldırıp içine MongoDB kurulumu yapabiliriz ama en az 3 tane container olacak ve herbirine tek tek MongoDB kurmak pek mantıklı olmayabilir. O yüzden gelin bunu otomasyona bağlayalım. Yani öyle birşey yapacağız ki,
- ubuntuyu kullansın
- MongoDB paketini indirsin ve belirli klasöre kopyalasın
- daha önceden hazırladığımız mongo.conf dosyasını container içine kopyalasın
Bu adımları bir Dockerfile içine yazıp bu direktifler doğrultusunda kendi imajımızı yaratabiliriz. Şimdi Dockerfile adında bir dosya yaratın ve içine aşağıdaki içeriği koyun.
FROM ubuntu:latest RUN apt-get update -y && apt-get install -y wget unzip build-essential RUN cd /opt \ && wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.4.tgz \ && tar -xvzf mongodb-linux-x86_64-3.0.4.tgz \ && mv mongodb-linux-x86_64-3.0.4 mongodb RUN mkdir -p /data/mongo RUN mkdir -p /var/log/mongodb ADD mongodb.conf /opt/mongodb/mongodb.conf RUN chmod 644 /opt/mongodb/mongodb.conf RUN chmod 644 /data/mongo
Basitçe, yaratacağımız imajın özelliklerini direktif halinde belirttik, şimdi bunu derleyip imaj oluşturalım. Derlemek için ise aşağıdaki komutu kullanabilirsiniz.
docker build -t mongodb:1.0 .
Bu komut sayesinde, bulunduğunuz dizindeki Dockerfile kullanılarak mongodb adında ve 1.0 versiyonunda bir imaj oluşturduk. Artık bu imajı kullanarak istediğimiz kadar container yaratabiliriz. Sanki bilgisayarınızdaki işletim sistemi ve dosyaların imajını almışsınız ve her an istediğiniz makineye kuruluabilir şeklinde düşünebilirsiniz. Container çalıştırmak için aşağıdaki komutu kullanabilirsiniz.
docker run -d --name mongodb-1 -v /dockerdata:/dockerdata mongodb:1.0 tail -f /dev/null
Bu komut ile container arka planda(-d) çalışır durumda. Adını –name opsiyonuyla verdik ve çalıştırılırken kullanılacak imaj mongodb:1.0 . -v seçeneği volume anlamına geliyor ve bu da lokaldeki bir klasörü container içindeki klasör ile eşleştirmek için kullanılıyor. Mesela ileriki bölümlerde bir anahtar üreteceğiz ve bu anahtar lokaldeki /dockerdata/ klasöründe olacak ve container içinden /dockerdata/mongokey.pem aslında lokal klasörden ulaşılmış olacak. En sondaki fonksiyon zorunlu değil ama eğer docker container içinde hiçbirşey çalışmayacak şeilde ayağa kalkarsa açar açmaz kapanacaktır. O yüzden /dev/null dosyasını tail komutuyla okudum ve bu sayede container ayakta durmuş olacaktır. Container çalışıyor ama bu container e nasıl bağlanacağız? Bağlanmadan önce docker ps diyerek o anki çalışan docker container listesine bakabiliriz. Burada container biligilerini göreceksiniz. Container’a bağlanmak için NAME alanını kullanacağız. Biz container’ı ayağa kaldırırken adını mongodb-1 vermiştik. Bağlanmak için aşağıdaki komutu kullanalım.
docker exec -i -t mongodb-1 bash
Bu komuttan sonra container a bağlanıp komut satırına düşmüş olacaksınız. Artık elinizde icinde MongoDB kurulu olan Ubuntu işletim sistemi var. MongoDB’yi başlatmak icin aşağıdaki komutu kullanabilirsiniz:
/opt/mongodb/bin/mongod --config /opt/mongodb/mongodb.conf
MongoDB’yi başlatmanın birçok yöntemi var. İsterseniz parametreleri direkt olarak komut satırından verebilirsiniz, dilerseniz bir config dosyasına koyup –config opsiyonuyla config dosyasını geçebilirsiniz. Şimdi gelelim config dosyasının içerğindeki ifadelerin ne anlama geldiğine;
dbpath: MongoDB’nin verileri yazacağı klasörün path’i
logpath: MongoDB calışırken logları yazacağı log dosyası
fork: MongoDB’nin daemon modda çalışabilmesi için gereken parametredir. Normalde MongoDB arkaplanda çalışmaz, fork: true derseniz arkaplanda çalıştırmanıza imkan sağlar.
pidfilepath: MongoDB’yi çalıştırdığınızda process id’sini yazacağı dosyadır. Aslında process id’sini ps -ef | awk ‘/mongodb/{print $2}’ | head -1 komutuyla da alabilirsiniz.
logappend: Aslında bu opsiyon analitik için çok önemli. Bu seçenek true olarak ayarlanırsa, mongod restart edildiğinde var olan logların üzerine yazmaz ve kaldığı yerden devam eder. Ama bu seçenek yoksa, restart işleminde eski loglar uçar (Eğer rotate etmediyseniz tabi) ve yeni bir log dosyası yaratıp ona yazmaya devam eder.
smallfiles: Bu seçenek true olursa, MongoDB nin oluşturduğu default veri dosya boyutları küçük olur. Bu konu performans açısından önemli ve burada çok da detaya inmek istemiyorum. Detaylı bilgi için şuraya bakabilirsiniz.
Artık MongoDB çalışır durumda, ama tahmin edeceğiniz gibi hiç bir güvenlik seviyesi yok. İsteyen bağlanıp veri yazabilir. O yüzden yönetim için hesap ekeleyelim. MongoDB servisi çalışırken aşağıdaki komutu çalıştırırsanız:
/opt/mongodb/bin/mongo
MongoDB ye bağlanacaksınız. Replica Set işlemleri, aslında bir yönetici hesabının yapması gereken işlemlerdir. O yüzden sisteme root kullanıcısı ekleyelim. İlk önce admin veritabanına use admin diyerek geçelim ve aşağıdaki komut yardımıyla root kullanıcısı ekleyelim.
db.createUser( { user: "root", pwd: "123456", roles: [ { role: "root", db: "admin" } ] } )
Daha sonra şu komut yardımıyla kullanıcıya giriş yaptırabilirsiniz:
db.auth("root", "123456")
Artık kullanıcımız var, MongoDB’yi güvenlikli haliyle restart edebiliriz. Ama önce config dosyasına auth=true eklemeniz lazım. Ekledikten sonra MongoDB’yi restart edelim. Tekrardan admin database ine aşağıdaki komut ile bağlanalım.
/opt/mongodb/bin/mongo localhost:27017/admin
Bağlandıktan sonra db.getUsers() derseniz, yetkili olmadığınızı söyleyen bir mesaj belirecektir. Giriş yapalım:
db.auth("root", "123456");
Artık istediğimiz işlemi yapabiliriz.
Buraya kadar yaptığımız güvenlik tabakası olan bir MongoDB servisi kurmaktı. Şimdi replica set nasıl ayarlanır ona bakacağız.
Mantık çerçevesinden olaya baktığımız zaman, Replica Set üyelerinin birbirleriyle haberleşmesi şifreli olması lazım. Yani herhangi bir üye gelişi güzel Replica Set’e bağlanamamalı. Bunun için bir anahtar üreteceğiz ve bütün üyeler bu anahtarı kullanacak. Anahtarı aşağıdaki komut ile üretebiliriz.
openssl rand -base64 741 > mongokey.pem chmod 600 mongokey.pem
mongokey.pem dosyası, Replica Set üyeleri tarafından okunabilecek bir yerde olması lazım. Bu dosyayı herbir üyenin bulunduğu container’a kopyalayabilirsiniz, ya da dockerdata ortak klasöründen okuyabilirsiniz. Bu anahtarı belirtmek için de config dosyasına bir kayıt daha koymamız lazım.
keyFile=/dockerdata/mongokey.pem
mongokey.pem dosyasını /dockerdata/ klasörüne kopyalayıp MongoDB üyelerini yeniden başlatabiliriz. Tabi yeni configi 3 üyenin config dosyasına ekelmeyi unutmayalım. Diğer üyeler aslında henüz ortada değil onları da aşağıdaki komutlarla başlatalım.
docker run -d --name mongodb-2 -v /dockerdata:/dockerdata mongodb:1.0 tail -f /dev/null docker run -d --name mongodb-3 -v /dockerdata:/dockerdata mongodb:1.0 tail -f /dev/null
Artık 3 üyemiz var ve docker ps dediğinizde aşağıdaki gibi bir çıktı göreceksiniz.
Şimdi ilk container’a bağlanıp Replica Set ayarlarını yapalım.
docker exec -i -t mongodb-1 bash
ile bağlandıktan sonra
/opt/mongodb/bin/mongo localhost:27017/admin -u root -p ‘123456’
ile admin veritabanına bağlanalım ve Replica Set ayarlamaya hazırız.
Replica Set i akliftestirmek icin MongoDB konsolundayken aşağıdaki komutu kullanalım.
rs.initiate()
Bu komut aktifleştirmeyi yapıp kendisini de ilk üye olarak ekler. rs.conf() komutunu çalıştırırsanız aşağıdaki gibi bir çıktı görürsünüz.
Buradaki JSON objesinde members altında üyelerin bilgileri yer alır. İlk üyenin host değeri rasgele bir sayı olarak ayarlanmış. Aslında bizim mimaride üyelerin birbirleriyle bu adlarla ulaşması ilk aşamada host tanımlaması yapmadan imkansızdır. O yüzden buradaki host değerini IP ile değiştireceğiz. Peki IP yi nerden bulacağız? Burada docker inspect komutu imdadımıza yetişiyor. docker inspect <container_id> komutunu çalıştırınca ilgili container’a ait bir sürü bilgi gösterilecektir. NetworkSettings.IPAddress de ilgili container’ın IP adresi yer alır. <container_id> yi de docker ps diyerek ilgili container’ın id sini bulabilirsiniz. Aşağıdaki ekrana göre ilk mongo containerin id si 0f110ae7a9f3 tür.
docker inspect 0f110ae7a9f3 komutunu çalıştırdığımda IP adresini 172.17.0.29 olduğunu gördüm. Diğer container IP lerine bakmanıza gerek yok çünkü Docker ard arda açılan container ların IP lerini ardışık olarak atar. Yani diğer üyelerin IP adresleri bende 172.17.0.30 ve 172.17.0.32 dir. Şimdi gelelim ilk üyenin host değerini IP ile değiştirmeye. Basit olarak var olan Replica Set konfigürasyonunu bir değişkene atıp host değerini güncelleyeceğiz. Sonra da rs.reconfig() ile eski konfigürasyon ile değiştireceğiz.
cfg=rs.conf() cfg.members[0].host=”172.17.0.29:27017” rs.reconfig(cfg)
Diğer üyeleri de eklemek için aşağıdaki komutları kullanabilirsiniz.
rs.add(“172.17.0.30:27017”) rs.add(“172.17.0.31:27017”)
Tekrar rs.conf() komutuyla diğer üyelerin de eklendiğini görebilirsiniz. rs.conf() dediğinizde her bir üyeye ait bilgileri göreceksiniz. Burda benim bahsetmek istediğim özellik priority. Priority, master seçilirken öncelikli olarak kullanılan alandır. Mesela ilk container 1.0 diğerleri 0 priority değerine sahip olursa, ilk container her zaman seçilen master olacaktır. Örnek aşağıdadır:
cfg=rs.conf() cfg.members[0].priority = 1 cfg.members[1].priority = 0 cfg.members[2].priority = 0 rs.reconfig(cfg)
Priority hakkında daha fazla bilgiye buradan ulaşabilirsiniz
Son olarak anlatmak istediğim konu Replica Set’in durumuyla ilgili bilgi veren rs.status() komutu. Bu komutu çalıştırdığınızda aşağıdaki gibi bir çıktı alacaksınız.
Burada PRIMARY üyenin ne zaman seçildiğini electionTime ile, SECONDARY üyelerin nereye senkronize olduklarını syncingTo ile, SECONDARY üyenin PRIMARY üyeye ne zaman kontrol mesajı gönderdiğini lastHeartbeat, ne zaman yanıt aldığını lastHeartbeatRecv alanından anlayabilirsiniz.
Bu makalede temel olarak MongoDB Replica Set nasıl kurulduğundan bahsetmeye çalıştım. Buradaki anlatım en temel düzeyde olmasına rağmen epeyce uzun oldu. Bir sonraki makalede sizlere Replica Set mimarisinde günlük hayatta nasıl sorunlarla karşılaşılıyor ve bunların çözümleri nelerdir onlardan bahsedeceğim.
NoSQL’in Kısa Tarihi Spark ile Tanışma Etkinliği
Hüseyin eline sağlık, çok güzel bir yazı ile aramıza katıldın. Devamını da bekliyoruz 🙂