MongoDB replica set, aynı veri kümesini tutan birden fazla mongod sürecinden oluşan bir gruptur. Kurmak için her üyeyi aynı replication.replSetName değeriyle başlatırsınız, ardından üyelerden yalnızca birinde rs.initiate() çalıştırırsınız ve rs.status() ile bir primary seçildiğini doğrularsınız. Resmî belgeler, üretim ortamındaki her MongoDB kurulumunun temelinin replica set olduğunu açıkça söyler; tek başına çalışan (standalone) bir sunucu yalnızca test ve geliştirme içindir.

Bu yazıda replica set mimarisini, üç üyeli bir kümenin adım adım kurulumunu, var olan bir standalone sunucunun replica set'e dönüştürülmesini, keyfile ile üyeler arası kimlik doğrulamayı, seçimlerin (election) nasıl işlediğini ve en sık yapılan hataları anlatıyoruz. Okuma ve yazma garantileri için ayrı bir yazımız var: write concern ve read concern rehberi. Serinin tamamı için MongoDB öğrenme rehberine bakabilirsiniz.

Replica Set Nasıl Çalışır?

Replica Set Nasıl Çalışır? Primary, Secondary, Priority 0 secondary, Arbiter

Bir replica set içinde veri tutan üyelerden tam olarak biri primary olur; diğerleri secondary rolündedir. Tüm yazma işlemleri primary'ye gider. Primary, verideki her değişikliği oplog adı verilen özel bir kayıt koleksiyonuna yazar. Secondary üyeler bu oplog'u kopyalar ve aynı işlemleri kendi veri kümelerine uygular. Bu kopyalama eşzamansızdır (asynchronous): secondary'ler primary'nin biraz gerisinden gelebilir. Primary ile secondary arasındaki bu gecikmeye replication lag denir. Küçük bir gecikme normaldir; belgeler, gecikme büyüdükçe primary üzerinde önbellek baskısı gibi sorunların ortaya çıktığını belirtir.

Primary erişilemez hale gelirse uygun bir secondary seçim başlatır ve yeni primary olmaya aday olur. Bu otomatik devralma (automatic failover) replica set'in asıl değeridir: bir sunucu kaybedildiğinde veri başka sunucularda zaten vardır ve uygulama kısa bir kesintiden sonra yeni primary ile çalışmaya devam eder. Ayrıca okuma işlemlerini secondary'lere yönlendirerek okuma kapasitesini artırabilir, bir kopyayı yedekleme, raporlama veya felaket kurtarma için ayırabilirsiniz.

Üye türüVeri tutar mıPrimary olabilir miSeçimde oy
PrimaryEvetZaten primaryEvet (varsayılan 1 oy)
SecondaryEvetEvet, priority 0 değilseEvet (varsayılan 1 oy)
Priority 0 secondaryEvetHayırYapılandırmaya bağlı
ArbiterHayırHayırEvet, tam 1 oy

Arbiter, oy veren ama veri tutmayan bir üyedir. Belgelere göre arbiter her zaman arbiter olarak kalır; primary ise geri çekilip secondary olabilir, secondary de seçimle primary olabilir. Bir düğüm aynı anda yalnızca bir replica set'e ait olabilir; aynı mongod sürecini iki kümede paylaşamazsınız.

Mimari Kararlar: Kaç Üye, Arbiter Gerekli mi?

Resmî kurulum rehberi üç üyeli bir replica set'i başlangıç noktası olarak önerir ve üye sayısının her zaman tek olması gerektiğini söyler; tek sayı, seçimlerin sorunsuz sonuçlanmasını sağlar. Üretimde her üye ayrı bir makinede, mümkünse ayrı güç ve ağ hatlarına bağlı olarak çalışmalıdır; bu kural sanal makineler için de geçerlidir. Aynı fiziksel makinede üç mongod çalıştırmak, o makine çöktüğünde üç kopyayı birden kaybetmek demektir.

Bir replica set en fazla 50 üyeye sahip olabilir, ancak bunlardan en fazla 7 tanesi oy verebilir. Yedinci üyeden sonrakiler votes: 0 ve priority: 0 ile oy vermeyen üye olarak eklenir; bu üyeler veri tutar ve okuma alabilir. Belgeler, hangi üyenin primary olacağını belirlemek için oy sayısıyla oynamamanızı, bunun yerine priority değerini değiştirmenizi önerir.

Maliyet nedeniyle yalnızca bir primary ve bir secondary çalıştırabiliyorsanız, oy sayısını tek yapmak için bir arbiter ekleyebilirsiniz. Bu düzene PSA (primary-secondary-arbiter) denir ve belgelerde birkaç önemli uyarı taşır. Arbiter'ı primary veya secondary ile aynı makinede çalıştırmayın. PSA düzeninde secondary düştüğünde veya geride kaldığında "majority" yazma onayı gecikebilir ya da hiç gelmeyebilir. Birden fazla arbiter kullanmak çoğunluk tabanlı yazma garantisini zayıflatır ve geride kalmış bir düğümün seçilmesine, dolayısıyla veri kaybına yol açabilir. Bu yüzden MongoDB 5.3'ten bu yana birden fazla arbiter eklemek varsayılan olarak kapalıdır; denerseniz sunucu, tüm düğümlerin allowMultipleArbiters=true ile başlatılması gerektiğini söyleyen bir hata döndürür. Mümkünse arbiter yerine veri tutan üçüncü bir üye kullanın.

Kurulum Öncesi Hazırlık

MongoDB'yi kümeye katılacak her sunucuya önceden kurmuş olmanız gerekir; Ubuntu için MongoDB Ubuntu kurulumu yazısını izleyebilirsiniz. Ardından şu konuları netleştirin:

  • Host adları: Üyeleri IP adresiyle değil, DNS üzerinden çözülebilen host adlarıyla tanımlayın. IP değişirse yapılandırmayı güncellemek zorunda kalmazsınız. Belgelere göre MongoDB 5.0'dan itibaren yalnızca IP adresiyle yapılandırılmış düğümler başlangıç doğrulamasından geçemez. DNS yoksa her sunucunun /etc/hosts dosyasına tüm üyeleri yazın.
  • IP bağlama: mongod varsayılan olarak yalnızca localhost'u dinler; bu durumda diğer üyeler ve uzak istemciler bağlanamaz. net.bindIp ile localhost'a ek olarak sunucunun özel ağdaki adını ekleyin. Herkese açık bir adrese bağlamadan önce mutlaka kimlik doğrulamayı açın.
  • Ağ ve güvenlik duvarı: Her üye diğer tüm üyelere bağlanabilmelidir. Belgeler üyeler arası trafiğin mümkünse özel ağ (VPN veya yerel ağ) üzerinden gitmesini ve 27017 portunun yalnızca küme üyeleri ile uygulama sunucularına açılmasını önerir. Ubuntu'da bunun için UFW güvenlik duvarı rehberine bakın.
  • Sürüm: Sürüm yükseltmesi sırası dışında tüm üyeler aynı ana MongoDB sürümünü çalıştırmalıdır.
  • Veri dizini ve yapılandırma: Veri dizinini önceden oluşturun ve ayarları komut satırı yerine /etc/mongod.conf dosyasında tutun. Dosyanın ayrıntıları için mongod.conf yapılandırma rehberi yazısına bakın.

Adım 1: Her Üyeyi replSetName ile Başlatın

Bu örnekte üç sunucu kullanıyoruz: db1.ornek.lan, db2.ornek.lan ve db3.ornek.lan. Her birinin mongod.conf dosyasına aynı replica set adını ve dinlenecek adresleri yazın. Replica set adı, uygulamanız birden fazla kümeye bağlanıyorsa her küme için farklı olmalıdır.

yaml
replication:
  replSetName: "rs0"
net:
  port: 27017
  bindIp: localhost,db1.ornek.lan

Aynı ayarı komut satırından da verebilirsiniz; belgelerdeki eşdeğer biçim --replSet ve --bind_ip seçenekleridir. Paketle kurulmuş bir sistemde ise dosyayı düzenledikten sonra servisi yeniden başlatmak yeterlidir:

bash
# Komut satırı eşdeğeri (yalnızca deneme için)
mongod --replSet "rs0" --bind_ip localhost,db1.ornek.lan

# Paketle kurulmuş sunucuda
sudo systemctl restart mongod
sudo systemctl status mongod

Servis yönetimi hakkında ayrıntı için systemd servis yönetimi yazısına göz atabilirsiniz. Üç sunucunun her birinde bu adımı tekrarlayın; bindIp satırında her sunucu kendi host adını yazar.

Adım 2: Üyeler Arası Kimlik Doğrulama (Keyfile)

Erişim denetimi açık bir replica set'te üyelerin birbirini de doğrulaması gerekir. Buna iç kimlik doğrulama (internal authentication) denir. Belgelerdeki keyfile yöntemi şöyledir: rastgele bir anahtar dosyası üretilir, yalnızca sahibinin okuyabileceği izinlerle tüm üyelere kopyalanır ve security.keyFile ayarıyla gösterilir. mongod'u keyfile ile başlatmak hem iç kimlik doğrulamayı hem de kullanıcı erişim denetimini birlikte zorunlu kılar.

bash
openssl rand -base64 756 > /etc/mongodb/rs0.key
chmod 400 /etc/mongodb/rs0.key
yaml
security:
  keyFile: /etc/mongodb/rs0.key
replication:
  replSetName: "rs0"
net:
  bindIp: localhost,db1.ornek.lan

Dosya, mongod sürecini çalıştıran kullanıcıya ait olmalıdır. Belgelerin MongoDB 9.0 sürümü önemli bir not düşer: keyfile'lar yönetimi ve kriptografik gücü sınırlı olduğu için yalnızca test ve geliştirme ortamlarında önerilir; üretimde X.509 sertifikaları kullanılmalıdır. Kullanıcı tarafı için MongoDB authentication etkinleştirme ve kullanıcı ve rol yönetimi yazılarına bakın.

Henüz hiç kullanıcı yoksa, keyfile ile başlattığınız üyeye aynı makineden localhost üzerinden bağlanabilirsiniz. Buna localhost exception denir ve yalnızca ilk kullanıcı oluşturulana kadar geçerlidir. Replica set'i bu bağlantıyla başlatabilirsiniz; ilk kullanıcıyı ise ancak küme bir primary seçtikten sonra eklemelisiniz.

Adım 3: rs.initiate() ile Kümeyi Başlatın

Üç üye de çalışırken birinin üzerinde mongosh açın ve rs.initiate() çağrısını yalnızca bir kez, yalnızca bu üyede çalıştırın. Belge, yapılandırma belgesinde üye _id değerlerini ve host:port biçimindeki adresleri içerir. mongosh kullanımına yabancıysanız mongosh kullanım rehberi işinizi kolaylaştırır.

javascript
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "db1.ornek.lan:27017" },
    { _id: 1, host: "db2.ornek.lan:27017" },
    { _id: 2, host: "db3.ornek.lan:27017" }
  ]
})

rs.initiate() bir seçim tetikler ve üyelerden birini primary yapar. Yapılandırma belgesi vermezseniz MongoDB varsayılan bir yapılandırma kullanır ve küme yalnızca komutu çalıştırdığınız üyeyle başlar; diğerlerini sonradan eklersiniz. Ardından iki kontrol yapın:

javascript
rs.conf()    // replica set yapılandırma belgesini gösterir
rs.status()  // her üyenin durumunu ve primary'yi gösterir

rs.conf() çıktısında her üye için priority: 1, votes: 1, hidden: false gibi varsayılanları; settings altında ise heartbeatIntervalMillis: 2000 ve electionTimeoutMillis: 10000 gibi değerleri görürsünüz. rs.status() çıktısındaki members dizisinde bir üyenin stateStr değeri PRIMARY, diğerlerininki SECONDARY olmalıdır. Yeni eklenen bir üye ilk eşitleme (initial sync) sırasında bir süre STARTUP2 durumunda kalabilir.

Var Olan Standalone Sunucuyu Replica Set'e Dönüştürme

Var Olan Standalone Sunucuyu Replica Set'e Dönüştürme: Mevcut sunucuya bağlanın ve admin veritabanında shutdown komutuyla düzgünce..., Bu sunucunun ve yeni eklenecek sunucuların...

Elinizde veri dolu tek bir sunucu varsa, verileri dışa aktarıp yeniden yüklemeniz gerekmez. Resmî dönüşüm prosedürü şu sırayı izler. Başlamadan önce mutlaka güncel bir yedek alın; mongodump ve mongorestore yazısı bu konuda yardımcı olur.

  • Mevcut sunucuya bağlanın ve admin veritabanında shutdown komutuyla düzgünce kapatın. Bağlantınızın kapandığını bildiren bir ağ hatası görmeniz beklenen bir durumdur.
  • Bu sunucunun ve yeni eklenecek sunucuların yapılandırma dosyasına replication.replSetName ekleyin.
  • Erişim denetimi kullanacaksanız üyeler arası kimlik doğrulamayı (keyfile veya X.509) yapılandırın.
  • Tüm mongod süreçlerini başlatın.
  • Veri içeren eski sunucuya bağlanıp parametresiz rs.initiate() çalıştırın. Küme tek üyeli olarak, bu sunucu primary olacak şekilde başlar.
  • Diğer sunucuları rs.add() ile ekleyin ve rs.status() ile listede göründüklerini doğrulayın.
  • Uygulamanızın bağlantı dizesini üç üyeyi ve replica set adını içerecek şekilde güncelleyip uygulamayı yeniden başlatın.
javascript
use admin
db.adminCommand({ shutdown: 1, comment: "replica set'e geçiş" })

// yapılandırma güncellenip mongod yeniden başlatıldıktan sonra:
rs.initiate()
rs.add("db2.ornek.lan:27017")
rs.add("db3.ornek.lan:27017")
rs.status()

rs.add() çağrısını primary'ye bağlıyken çalıştırmalısınız. Belgeler, bazı durumlarda (örneğin primary'den daha yüksek önceliğe sahip bir üye eklendiğinde) bu çağrının seçim tetikleyebileceğini ve mongosh bağlantısını koparabileceğini belirtir; bu durumda işlem başarılı olsa bile ekranda hata görebilirsiniz. Böyle bir şey olursa yeniden bağlanıp rs.status() ile sonucu kontrol edin. Yeni bağlantı dizesinin biçimi için connection string URI rehberine bakın:

bash
mongodb://db1.ornek.lan:27017,db2.ornek.lan:27017,db3.ornek.lan:27017/?replicaSet=rs0

Seçimler (Election) Nasıl İşler?

Seçimler yalnızca primary çöktüğünde yapılmaz. Belgelere göre yeni bir üye eklemek, rs.initiate() çalıştırmak, rs.stepDown() veya rs.reconfig() ile bakım yapmak ve secondary'lerin primary ile bağlantısının yapılandırılan süreden (varsayılan 10 saniye) uzun süre kopması seçimi tetikleyebilir.

Üyeler birbirine iki saniyede bir heartbeat (ping) gönderir. On saniye içinde yanıt gelmezse ilgili üye erişilemez sayılır. settings.electionTimeoutMillis süresi (varsayılan 10000 milisaniye) dolduğunda uygun bir secondary seçim başlatır. Varsayılan ayarlarla yeni primary seçilene kadar geçen ortanca sürenin genellikle 12 saniyeyi aşmaması beklenir; ağ gecikmesi bu süreyi uzatabilir. Seçim tamamlanana kadar küme yazma kabul etmez; okumalar secondary'lere yönlendirilmişse devam edebilir.

Seçimi kimin kazanacağını birkaç etken belirler. Daha yüksek priority değerine sahip secondary'ler seçimi daha erken başlatır ve kazanma olasılıkları daha yüksektir; yine de daha düşük öncelikli bir üye kısa süreliğine primary olabilir ve küme en yüksek öncelikli erişilebilir üye primary olana kadar seçime devam eder. Önceliği 0 olan üyeler hiçbir zaman primary olmaz. Bir üyenin primary olabilmesi için görünür üyeler arasında en güncel optime değerine sahip olması gerekir ve oyların çoğunluğunu ilk alan üye kazanır.

Ağ bölünmesinde (network partition) primary, oy veren üyelerin yalnızca azınlığını görebildiğini fark ederse kendiliğinden geri çekilip secondary olur. Çoğunluğu görebilen taraftaki bir üye ise yeni primary olmak için seçim yapar. Bu davranış, aynı anda iki yazılabilir primary oluşmasını engellemek içindir ve tek sayıda üye kuralının nedenini de açıklar.

Oplog Boyutu ve Neden Önemli?

Oplog, her üyenin local.oplog.rs koleksiyonunda tuttuğu sınırlı boyutlu (capped) bir kayıttır. Yalnızca veriyi gerçekten değiştiren işlemler oplog'a yazılır ve her oplog girdisi idempotent'tir; yani bir kez de uygulansa birkaç kez de uygulansa aynı sonucu verir. Herhangi bir secondary, oplog girdilerini başka bir üyeden de alabilir.

Boyut belirtmezseniz WiredTiger kullanan bir üye için varsayılan oplog boyutu boş disk alanının yüzde 5'idir; bu değer 990 MB'tan küçük çıkarsa oplog 990 MB olarak oluşturulur. Oplog, çoğunluk tarafından onaylanmış son noktayı silmemek için yapılandırılan sınırın üzerine çıkabilir. Bir secondary uzun süre kapalı kalır ve oplog bu süreyi karşılayamazsa, o üye kaldığı yerden devam edemez ve yeniden tam eşitleme gerekir; bu yüzden yoğun yazma alan kümelerde oplog penceresini izlemek önemlidir.

MongoDB 9.0 ile Gelen Değişiklikler

MongoDB 9.0 sürüm notları replikasyon tarafında, mantıksal ilk eşitleme (logical initial sync) sırasında replSetGetStatus çıktısına initialSyncStatus.phase, initialSyncStatus.totalAttempts ve initialSyncStatus.bytesPerSecond alanlarının eklendiğini belirtir. Böylece yeni bir üyenin eşitlemenin hangi aşamasında olduğunu daha kolay izlersiniz.

Aynı notlarda açık bir bilinen sorun da var: bir düğüm temiz olmayan bir kapanmadan sonra dosya kopyalama tabanlı ilk eşitleme (file copy based initial sync) için yeniden başlatılırsa her açılışta çökebilir. Kendi sunucunuzda bunun için iki çözüm verilmiştir: düğümü initialSyncMethod parametresi logical olacak şekilde yeniden başlatmak ya da düğümün storage.dbPath dizinini boşaltıp yeni bir eşitleme başlatmak. Sürümün diğer değişiklikleri için MongoDB 9.0 yenilikleri yazısına bakın.

Sık Yapılan Hatalar

Sık Yapılan Hatalar: rs.initiate() komutunu birden fazla üyede çalıştırmak. Komut yalnızca bir..., Üyeleri localhost veya 127.0.0.1 ile tanımlamak. Uzak istemciler ve diğer...
  • rs.initiate() komutunu birden fazla üyede çalıştırmak. Komut yalnızca bir üyede, bir kez çalıştırılır.
  • Üyeleri localhost veya 127.0.0.1 ile tanımlamak. Uzak istemciler ve diğer üyeler bu adresi kendi makineleri olarak yorumlar; DNS ile çözülebilen host adları kullanın.
  • Bakım sırasında iki üyeyi aynı anda kapatmak. Üç üyeli kümede bu, çoğunluğun kaybı demektir ve küme primary seçemez. Bakımı secondary'lerden başlayarak tek tek yapın, primary'yi en sona bırakın.
  • Güvenlik duvarında yalnızca uygulama sunucusuna izin verip üyelerin birbirine erişimini unutmak. Bağlantıyı her yönde test edin.
  • Üye sayısını çift tutmak veya birden fazla arbiter eklemek.
  • Uygulamanın bağlantı dizesinde hâlâ tek bir host ve replicaSet seçeneği olmadan bağlanmak.

Bağlantı tarafındaki sorunları teşhis etmek için MongoDB bağlantı hataları ve server selection timeout yazısında adım adım bir kontrol listesi bulabilirsiniz.

Sık Sorulan Sorular

İki sunucuyla replica set kurabilir miyim?

Teknik olarak evet, ancak iki oy veren üyede biri düştüğünde kalan üye çoğunluğu sağlayamaz ve primary seçilemez. Belgeler üye sayısının tek olmasını önerir. Üçüncü bir veri sunucusu mümkün değilse arbiter eklenebilir, fakat PSA düzeninin "majority" yazmalarla ilgili uyarılarını dikkate alın.

Standalone sunucuyu dönüştürünce verilerim kaybolur mu?

Hayır. Dönüşüm sırasında veri dizinine dokunulmaz; mevcut sunucu kümenin ilk üyesi olur ve yeni üyeler veriyi ilk eşitleme ile bu sunucudan alır. Yine de işlemden önce yedek almak her zaman doğru yaklaşımdır.

Arbiter sunucusuna nasıl bağlanırım?

Arbiter veri tutmadığı için kullanıcı ve rol bilgisi de tutmaz. Belgelere göre yetkilendirme açıkken bir arbiter'a giriş yapmanın tek yolu aynı makineden localhost exception ile bağlanmaktır.

Replica set kurmak sharding ile aynı şey mi?

Hayır. Replica set aynı verinin kopyalarını tutarak yüksek erişilebilirlik sağlar; sharding ise veriyi birden fazla sunucuya bölerek yatay ölçekleme yapar ve her shard'ın kendisi bir replica set olarak çalışır. Ayrıntılar için MongoDB sharding ve shard key yazısına bakın.

Transaction ve change stream için replica set şart mı?

Belgeler, çok belgeli transaction'ların ve change stream'lerin replica set'lerde (ve sharded kümelerde) kullanılabildiğini belirtir. Bu özellikleri kullanmak istiyorsanız tek üyeli bile olsa bir replica set kurmanız gerekir. Bkz. transaction kullanımı ve change streams.

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: MongoDB öğrenme rehberi · Write concern ve read concern · Sharding ve shard key · Authentication etkinleştirme · Güvenlik kontrol listesi · Bağlantı hataları · VPS güvenlik sertleştirme