Dağıtık bir veritabanı seçerken karşınıza mutlaka çıkan üç harfli bir kısaltma var: CAP. Ürün sayfalarında "AP sistemdir" ya da "güçlü tutarlılık sunar" gibi ifadeler görürsünüz, forumlarda "CAP teoremi gereği üçünden ikisini seçebilirsiniz" cümlesiyle karşılaşırsınız. Sorun şu ki bu popüler özet, teoremin söylediğinden farklı bir şey anlatıyor ve yanlış mimari kararlara yol açıyor. CAP teoremi, üç özellikten ikisini seçtiğiniz bir menü değildir; ağınız bölündüğünde ne yapacağınızı önceden belirlemeniz gerektiğini söyleyen bir uyarıdır.
Bu rehberde CAP teoreminin üç harfinin gerçekte neyi ifade ettiğini, "üçünden ikisi" özetinin neden yanıltıcı olduğunu, CP ve AP sistemlerin gerçek hayatta nasıl davrandığını, quorum matematiğinin nasıl işlediğini ve CAP'in eksik bıraktığı yeri dolduran PACELC modelini anlatacağım. Amaç teorik bir gösteri değil; kendi sisteminizde "bir sunucu ağdan koptuğunda uygulamam ne yapmalı" sorusuna bilinçli bir cevap verebilmeniz.
CAP'in Üç Harfi Gerçekte Ne Anlatıyor#
Teorem 2000'lerin başında Eric Brewer tarafından bir varsayım olarak ortaya atıldı ve daha sonra biçimsel olarak kanıtlandı. Üç özellik şunlardır:
Consistency (Tutarlılık), buradaki anlamıyla, sistemdeki her okumanın en son tamamlanmış yazmayı ya da bir hata döndürmesidir. Yani birden fazla düğüm olsa bile, dışarıdan bakan biri sistemi tek bir kopya gibi görür. Bu, teknik olarak "linearizability" denilen güçlü bir garantidir.
Availability (Erişilebilirlik), çalışır durumdaki her düğümün, aldığı her isteğe hata olmayan bir cevap vermesidir. Cevabın en güncel veri olması gerekmez; önemli olan sistemin "şu anda cevap veremiyorum" dememesidir.
Partition tolerance (Bölünme toleransı), düğümler arasındaki ağ bağlantısı koptuğunda ya da mesajlar kaybolduğunda sistemin çalışmaya devam edebilmesidir. Ağ bölünmesi (network partition), iki grup düğümün birbirini görememesi ama her ikisinin de dışarıdan istek almaya devam etmesi demektir.
Burada çoğu kişinin gözden kaçırdığı kritik nokta şudur: CAP'teki C harfi, ACID'deki C harfiyle aynı şey değildir. ACID'in tutarlılığı, bir transaction'ın veritabanı kısıtlarını (yabancı anahtar, benzersizlik, kontrol kuralları) bozmadan tamamlanmasıdır. CAP'in tutarlılığı ise kopyalar arasındaki güncellik garantisidir. İkisini karıştırmak yaygın bir hatadır; farkın tamamı için ACID ve BASE modelleri yazısına bakabilirsiniz.
"Üçünden İkisini Seç" Neden Yanıltıcı#
Popüler anlatım, üç köşeli bir üçgen çizip "CA, CP veya AP seçin" der. Bu görsel akılda kalıcı ama pratikte yanıltıcıdır, çünkü bölünme toleransı seçilebilecek bir özellik değildir. Birden fazla makineye yayılmış ve aralarında ağ olan her sistemde ağ bölünmesi eninde sonunda yaşanır: bir anahtar arızalanır, bir kablo çekilir, bir veri merkezi arası hat kesilir, bir güvenlik duvarı kuralı yanlış yazılır. Bunlar teorik olasılıklar değil, işletme hayatının rutin olaylarıdır.
Dolayısıyla gerçek karar şudur: ağ bölündüğünde tutarlılıktan mı yoksa erişilebilirlikten mi vazgeçeceksiniz? Bölünme olmadığı sürece her iki özelliği de aynı anda sunabilirsiniz; teoremin bağladığı el yalnızca bölünme anındadır.
"CA sistemi" diye anılan şey, aslında dağıtık olmayan tek düğümlü bir sistemdir. Tek sunuculu bir PostgreSQL kurulumu, ağ bölünmesi kavramının kendisine uygulanmadığı için CAP'in dışındadır; o sunucu düşerse sistem tamamen erişilemez olur, bölünme değil kesinti yaşarsınız.
| Bölünme yokken | Bölünme varken | Sistem sınıfı | Örnekler |
|---|---|---|---|
| Tutarlı ve erişilebilir | Tutarlılığı korur, bazı isteklere hata döner | CP | etcd, ZooKeeper, Consul |
| Tutarlı ve erişilebilir | Erişilebilirliği korur, eski veri dönebilir | AP | Cassandra, DynamoDB (varsayılan) |
| Tek düğüm, bölünme yok | Kavram uygulanmaz | Dağıtık değil | Tek sunuculu MySQL |
CP Sistemler: Emin Değilsem Cevap Vermem#
CP tarafındaki bir sistem, bölünme sırasında azınlıkta kalan tarafı devre dışı bırakır. Beş düğümlü bir etcd kümesinde ağ ikiye bölünüp bir tarafta üç, diğer tarafta iki düğüm kalırsa, üç düğümlü taraf çoğunluğu (quorum) oluşturduğu için çalışmaya devam eder; iki düğümlü taraf ise yazma ve tutarlı okuma isteklerini reddeder. Böylece "iki farklı gerçeklik" oluşması engellenmiş olur.
Bu davranış, verinin doğruluğunun erişilebilirlikten daha değerli olduğu yerlerde tam olarak istediğiniz şeydir: dağıtık kilitler, servis keşfi, lider seçimi, konfigürasyon yönetimi, hesap bakiyesi. Bir kilit servisinin bölünme sırasında iki farklı istemciye aynı kilidi vermesi, kısa süreli erişilemezlikten çok daha kötüdür.
# etcd kümesinde sağlık ve lider durumu — çoğunluk kaybedilirse yazmalar durur
etcdctl --endpoints=185.12.34.56:2379,185.12.34.57:2379,185.12.34.58:2379 \
endpoint status --write-out=table
# Çoğunluk yoksa alacağınız tipik hata:
# etcdserver: request timed out, possibly due to previous leader failure
Bu tasarımın pratik sonucu, küme boyutunun tek sayı olmasının gerekmesidir. Dört düğümlü bir kümede quorum yine üçtür; yani dördüncü düğüm size ek dayanıklılık vermez, sadece maliyet ekler. Bu yüzden CP kümeleri neredeyse her zaman 3, 5 ya da 7 düğümlüdür.
| Düğüm sayısı | Quorum | Dayanabileceği kayıp |
|---|---|---|
| 3 | 2 | 1 düğüm |
| 4 | 3 | 1 düğüm |
| 5 | 3 | 2 düğüm |
| 6 | 4 | 2 düğüm |
| 7 | 4 | 3 düğüm |
AP Sistemler: Cevabım Var Ama Biraz Eski Olabilir#
AP tarafındaki bir sistem, bölünme sırasında her iki taraftaki düğümlerin de istek almaya devam etmesine izin verir. İki taraf birbirinden habersiz yazma alır ve bölünme bittiğinde bu farklılıkların uzlaştırılması gerekir. Uzlaştırma stratejisi genellikle "son yazan kazanır" (last-write-wins) ya da uygulama düzeyinde birleştirme mantığıdır.
Bu tasarım, hizmetin ayakta kalmasının anlık güncellikten daha değerli olduğu yerlerde doğrudur: alışveriş sepetleri, sosyal medya beğeni sayaçları, ürün görüntülenme istatistikleri, bildirim akışları, log toplama. Bir kullanıcı sepetine ürün eklerken "sistem şu anda çalışmıyor" mesajı almaktansa, bir başka cihazdaki sepetinin birkaç saniye gecikmeli görünmesi kabul edilebilir bir bedeldir.
Cassandra gibi sistemler bu ödünleşmeyi sorgu bazında ayarlanabilir hâle getirir. Buradaki matematik son derece nettir: R + W > N olduğunda okuduğunuz değer en son yazılan değeri mutlaka içerir. Burada N replikasyon faktörü, W yazmanın kaç kopyadan onay beklediği, R ise okumanın kaç kopyadan cevap beklediğidir.
-- Cassandra: replikasyon faktörü 3 olan bir keyspace
CREATE KEYSPACE uygulama
WITH replication = {'class': 'NetworkTopologyStrategy', 'istanbul': 3};
-- W=2 (QUORUM) yazma + R=2 (QUORUM) okuma → 2+2=4 > 3, güçlü tutarlılık
CONSISTENCY QUORUM;
-- W=1 + R=1 → 1+1=2, 3'ten küçük: hızlı ama eski veri okuyabilirsiniz
CONSISTENCY ONE;
Yani AP bir sistemde bile, tutarlılık seviyesini yükselterek belirli sorgular için CP davranışı elde edebilirsiniz. Bunun bedeli gecikme ve bölünme sırasında hata almaktır. Ayrıntılı örnekler için Apache Cassandra nedir yazısındaki tutarlılık bölümüne bakabilirsiniz.
PACELC: CAP'in Eksik Bıraktığı Yarı#
CAP'in en büyük eksiği, yalnızca bölünme anını konuşmasıdır. Oysa bir dağıtık sistemin ömrünün büyük çoğunluğu bölünmesiz geçer ve o süre boyunca da bir ödünleşme yaşanır: gecikme ile tutarlılık arasındaki ödünleşme.
PACELC modeli bunu şöyle ifade eder: eğer bölünme (Partition) varsa, Availability ile Consistency arasında seçim yaparsınız; Else (bölünme yoksa) ise Latency ile Consistency arasında seçim yaparsınız. Bunun sebebi basittir: bir yazmanın üç veri merkezindeki kopyaların hepsi tarafından onaylanmasını beklerseniz, o yazma en yavaş bağlantı kadar yavaş olur.
| Sistem tipi | Bölünme varken | Bölünme yokken | PACELC etiketi |
|---|---|---|---|
| Cassandra (varsayılan) | Erişilebilirlik | Düşük gecikme | PA/EL |
| etcd, ZooKeeper | Tutarlılık | Tutarlılık | PC/EC |
| MongoDB (majority write) | Tutarlılık | Tutarlılık | PC/EC |
| Tek DC içi replikalı MySQL | Tutarlılık | Düşük gecikme | PC/EL |
Bu tablo, "hangi veritabanı daha iyi" sorusunun neden anlamsız olduğunu gösterir. Coğrafi olarak dağıtılmış bir sistemde her yazmayı tam tutarlılıkla yapmak, kıtalar arası gidiş-dönüş süresini her isteğe eklemek demektir. Kullanıcı deneyimi açısından bu, çoğu senaryoda kabul edilemez.
Kendi Sisteminizde Kararı Nasıl Verirsiniz#
CAP tartışmasını mimari toplantısından çıkarıp somut bir karara dönüştürmenin yolu, veriyi tek bir kategoriye sokmaya çalışmamaktan geçer. Aynı uygulamada farklı veri tipleri farklı garantilere ihtiyaç duyar. Şu adımları izleyin:
- Veri tiplerinizi listeleyin. Kullanıcı bakiyesi, sipariş durumu, oturum verisi, beğeni sayısı, arama indeksi ayrı ayrı yazılmalı.
- Her biri için "eski veri okunursa ne olur" sorusunu cevaplayın. Cevap "para kaybederiz" ise tutarlılık zorunludur. Cevap "sayaç birkaç saniye geç güncellenir" ise erişilebilirlik önceliklidir.
- Yazma yolunu ayrı değerlendirin. Okumada gevşek olabileceğiniz bir veride bile, yazmanın kaybolmaması gerekebilir.
- Bölünme senaryosunu yazın. "Veri merkezleri arası hat 10 dakika koparsa" cümlesini tamamlayın: hangi ekranlar çalışmaya devam eder, hangileri hata verir.
- Uzlaştırma stratejisini önceden belirleyin. AP tarafındaysanız, bölünme bittiğinde çakışan yazmaların nasıl birleştirileceğine karar verin.
// MongoDB: kritik yazmada çoğunluk onayı bekle (CP davranışı)
db.hesaplar.updateOne(
{ _id: "H-1042" },
{ $inc: { bakiye: -250 } },
{ writeConcern: { w: "majority", wtimeout: 5000 } }
);
// Sıradan sayaç yazması: hız öncelikli (AP davranışı)
db.sayaclar.updateOne(
{ _id: "urun-77" },
{ $inc: { goruntulenme: 1 } },
{ writeConcern: { w: 1 } }
);
Bu yaklaşımın pratik faydası, tek bir "biz AP sistemiz" kararı vermek yerine, veri bazında bilinçli seçimler yapmanızdır. Hangi motorun hangi işe uygun olduğuna karar verirken SQL mi NoSQL mu seçim rehberi yazısındaki kontrol listesi de işinizi kolaylaştırır. Altyapı tarafında bölünme riskini azaltmak isterseniz, düğümleri aynı veri merkezinde ve düşük gecikmeli bir ağda tutmak en etkili yöntemdir; VDS ve bulut sunucu paketleri bu tür kümeler için uygun bir temel sağlar.
Sık Yapılan Yanlış Anlamalar#
"Bölünme toleransından vazgeçelim" demek en yaygın hatadır. Ağ bölünmesi sizin seçiminiz değildir; olur. Vazgeçtiğinizi sandığınız şey, bölünme yaşandığında sisteminizin tanımsız davranmasıdır — ki bu, tutarlılık ya da erişilebilirlikten vazgeçmekten çok daha kötüdür.
CAP'i tek düğümlü sistemlere uygulamak ikinci hatadır. Tek bir MySQL sunucusu için "CA sistem" demek anlamsızdır; orada bölünme kavramı yoktur, sadece sunucu ayakta ya da değildir. CAP yalnızca birden fazla düğüm ve aralarında ağ olduğunda konuşulur.
"Eventual consistency" ifadesini "veri kaybolabilir" sanmak üçüncü hatadır. Nihai tutarlılık, yazmanın kaybolacağı anlamına gelmez; kopyaların bir süre sonra aynı değere ulaşacağı anlamına gelir. O süre genellikle milisaniyeler ile saniyeler arasındadır. Veri kaybı riski, tutarlılık modelinden değil dayanıklılık (durability) ayarlarından ve yedekleme disiplininden gelir.
Tutarlılığı yalnızca veritabanı sorunu sanmak dördüncü hatadır. Uygulamanız veriyi hem veritabanına hem önbelleğe yazıyorsa, aralarındaki tutarsızlık veritabanının CAP sınıfından bağımsız olarak sizin sorununuzdur. Önbellek geçersizleştirme stratejisi, en az replikasyon ayarı kadar önemlidir.
Sıkça Sorulan Sorular#
CAP teoremi neden üçünden ikisi diye anlatılıyor#
Bu özet, teoremin ilk popülerleştiği dönemde akılda kalıcı olduğu için yayıldı ve zamanla teoremin kendisinin yerine geçti. Teoremin gerçek ifadesi, bir ağ bölünmesi sırasında tutarlılık ile erişilebilirliği aynı anda garanti edemeyeceğinizdir. Bölünme olmadığı sürece her ikisini de sunabilirsiniz. Yani seçim üç özellik arasında değil, yalnızca bölünme anında iki özellik arasında yapılır.
CAP teoremindeki tutarlılık ile ACID'deki tutarlılık aynı mı#
Hayır, aynı değiller ve bu karışıklık çok yaygın. ACID'in C harfi, bir transaction'ın veritabanı kısıtlarını bozmadan tamamlanmasını ifade eder; yabancı anahtar, benzersizlik ve kontrol kuralları geçerli kalır. CAP'in C harfi ise dağıtık kopyalar arasındaki güncellik garantisidir; her okumanın en son yazmayı görmesi anlamına gelir. Bir sistem ACID tutarlılığını sağlayıp CAP tutarlılığından ödün verebilir.
Hangi veritabanı CP hangisi AP#
etcd, ZooKeeper ve Consul tipik CP sistemlerdir; çoğunluk kaybedildiğinde yazma isteklerini reddederler. Cassandra ve DynamoDB varsayılan olarak AP tarafında konumlanır ama tutarlılık seviyesi ayarlanabilir olduğu için sorgu bazında CP davranışına yaklaşabilirler. MongoDB, çoğunluk yazma onayı (majority write concern) ile kullanıldığında CP'ye yakın davranır. Etiketler mutlak değil, yapılandırmaya bağlıdır.
Eventual consistency ne kadar sürede tamamlanır#
Sağlıklı bir ağda ve normal yük altında bu süre genellikle milisaniyelerle ölçülür; kopyalar birkaç yüz milisaniye içinde aynı değere ulaşır. Ağ gecikmesi arttığında, bir düğüm geçici olarak kapandığında ya da onarım süreçleri gerektiğinde bu süre saniyelere hatta dakikalara çıkabilir. Kritik olan nokta, uygulamanızın bu gecikme penceresinde ne yapacağını bilmesidir; örneğin kullanıcının kendi yazdığı veriyi hemen görmesi gerekiyorsa, o okumayı yazmayı aldığı düğümden yapmak yaygın bir çözümdür.
Küçük bir projede CAP teoremini düşünmem gerekir mi#
Tek sunuculu bir kurulumda CAP teoremini düşünmenize gerek yoktur, çünkü bölünme kavramı uygulanmaz. Ancak okuma replikası eklediğiniz anda ilk CAP kararını vermiş olursunuz: replikadan okuma yapan bir sorgu, primary'de yeni yazılmış veriyi bir süre görmeyebilir. Bu yüzden replika eklerken hangi okumaların replikaya, hangilerinin primary'ye gideceğine karar vermeniz gerekir. Küçük projelerde CAP tartışması genellikle tam olarak bu noktada başlar.
Bölünme sırasında iki taraf da yazarsa veriler nasıl birleşir#
AP sistemlerde bu birleştirme birkaç yöntemle yapılır. En yaygını "son yazan kazanır" yaklaşımıdır; her yazmaya bir zaman damgası eklenir ve bölünme bittiğinde daha yeni olan kazanır. Bu yöntem basittir ama veri kaybına yol açabilir, çünkü kaybeden yazma sessizce üzerine yazılır. Daha güvenli yöntemler, çakışmayı uygulamaya bildirmek ya da toplanabilir veri tipleri kullanmaktır; örneğin bir sepette iki tarafın eklediği ürünlerin birleşimi alınabilir. Stratejiyi baştan seçmezseniz, varsayılan davranışa mahkûm olursunuz.
Kapanış#
CAP teoremi, dağıtık sistem tasarımında sihirli bir formül değil; bir zorunluluğu kabul ettiren dürüst bir hatırlatmadır. Aklınızda kalması gereken dört şey şunlar: bölünme toleransı seçilebilir bir özellik değildir, ağ eninde sonunda bölünür; asıl karar bölünme anında tutarlılıktan mı erişilebilirlikten mi vazgeçeceğinizdir; bu karar sistem geneli için değil veri tipi bazında verilmelidir; ve bölünme yokken bile gecikme–tutarlılık ödünleşmesi devam eder, PACELC bunu hatırlatır.
Dağıtık bir küme kurmayı planlıyorsanız düğümler arası ağ gecikmesi ve kararlılığı, seçtiğiniz veritabanı kadar belirleyicidir. Düşük gecikmeli bir altyapıda küme kurmak için VDS, esnek ölçeklenme için bulut sunucu, yüksek ve öngörülebilir performans için dedicated sunucu paketlerine bakabilirsiniz. Küme işletimini, izlemeyi ve failover senaryolarının denenmesini kendiniz üstlenmek istemiyorsanız sunucu yönetimi hizmetimiz bu yükü paylaşabilir.