Dağıtık veritabanlarının neden çoğu zaman tutarlılığı gevşetip erişilebilirliği koruduğunu, CAP ve quorum mantığını ve hangi yaklaşımı ne zaman seçmeniz gerektiğini öğrenin.

Bir veritabanı birden çok makineye (replikalara) bölündüğünde hız ve dayanıklılık elde edersiniz—ama aynı zamanda bu makinelerin her zaman tam olarak aynı fikirde olmadığı veya güvenilir şekilde iletişim kuramadığı dönemler ortaya çıkar.
Tutarlılık demek: başarılı bir yazmadan sonra herkes aynı değeri okur. Profil e-posta adresinizi güncellerseniz, sonraki okuma—hangi replika cevap verirse versin—yeni e-posta adresini döndürür.
Pratikte, tutarlılığı öncelikleyen sistemler arızalar sırasında bazı istekleri geciktirebilir veya reddedebilir ki çelişkili cevaplar dönülmesin.
Erişilebilirlik demek: sistem her isteğe yanıt verir, bazı sunucular kapalı veya bağlantısız olsa bile. Aldığınız cevap en güncel veri olmayabilir ama bir cevap alırsınız.
Pratikte, erişilebilirliği öncelikleyen sistemler replikalar anlaşmazlık içindeyken bile yazmaları kabul edip okumaları cevaplayabilir ve farkları sonra uzlaştırır.
Bir ödün şu demektir: her hata senaryosunda her iki hedefi de aynı anda en üst düzeye çıkaramazsınız. Replikalar koordine olamıyorsa veritabanı ya:\n
Doğru denge, hangi hataları tolere edebileceğinize bağlıdır: kısa bir kesinti mi yoksa kısa süreli yanlış/eski veri mi. Çoğu gerçek sistem arada bir nokta seçer ve bu ödünü açıkça belirtir.
Bir veritabanı, veriyi birden çok makinede (düğümlerde) sakladığında ve hizmet verdiğinde “dağıtık” olur. Uygulama için hâlâ tek bir veritabanı gibi görünebilir—ama altyapıda istekler farklı düğümler tarafından, farklı yerlerde işlenebilir.
Çoğu dağıtık veritabanı veriyi çoğaltır: aynı kayıt birden çok düğümde saklanır. Bu yüzden ekipler bunu yapar ki:
Replikasyon güçlüdür, ama hemen bir soru getirir: iki düğüm aynı verinin bir kopyasına sahipse, onların her zaman aynı fikirde olduklarını nasıl garanti edersiniz?
Tek bir sunucuda “kapalı” genelde açıktır: makine çalışır ya da çalışmaz. Dağıtık bir sistemde arıza genellikle kısmi olur. Bir düğüm canlı ama yavaş olabilir. Bir ağ bağlantısı paket kaybedebilir. Bir rafın tamamı bağlantısını kaybedebilirken kümenin geri kalanı çalışmaya devam edebilir.
Bu önemlidir çünkü düğümler diğerinin gerçekten kapalı mı, geçici olarak ulaşılamaz mı yoksa sadece gecikmiş mi olduğunu anında bilemez. Ne olup bittiğini anlamaya çalışırken gelen okuma ve yazma istekleriyle ne yapacaklarına karar vermeleri gerekir.
Tek sunucuda bir kaynak gerçekliktir: her okuma en son başarılı yazıyı görür.
Birden çok düğümde “en son” koordinasyona bağlıdır. Eğer bir yazma Node A'da başarılı oldu ama Node B'ye ulaşılamıyorsa, veritabanı şunu yapmalı mı:
Bu gerilim—kusurlu ağlarla gerçek hale gelen—dağıtımın kuralları değiştirmesinin nedenidir.
Bir ağ bölünmesi, birlikte bir veritabanı gibi çalışması gereken düğümler arasındaki iletişimin kırılmasıdır. Düğümler hâlâ çalışıyor ve sağlıklı olabilir, ancak bir anahtarın arızalanması, aşırı yüklü bir bağlantı, yanlış yönlendirme değişikliği, hatalı bir güvenlik duvarı kuralı veya bulut ağında gürültülü bir komşu gibi sebeplerle mesajlar güvenilir şekilde geçemez.
Sistem birkaç makineye (genellikle raflara, bölgelere veya bölgelere) yayıldığında artık aralarındaki her hopu kontrol edemezsiniz. Ağlar paket düşürür, gecikme ekler ve bazen “ada”lara bölünür. Küçük ölçekte bu olaylar nadir olur; büyük ölçekte rutinleşir. Kısa bir kesinti bile önemlidir, çünkü veritabanlarının olup biteni kabul etmesi ve üzerinde anlaşması için sürekli koordinasyona ihtiyacı vardır.
Bir bölünme sırasında her iki taraf da istek almaya devam eder. Kullanıcılar her iki tarafta da yazabiliyorsa, her taraf diğerinin görmediği güncellemeleri kabul edebilir.
Örnek: Node A bir kullanıcının adresini “Yeni Sokak” olarak günceller. Aynı anda Node B adresi “Eski Sokak Apt 2” olarak günceller. Her taraf kendi yazmasının en güncel olduğuna inanır—çünkü gerçek zamanlı olarak notları karşılaştıramazlar.
Bölünmeler temiz hata mesajları olarak değil, kafa karıştırıcı davranışlar olarak ortaya çıkar:
Bu, baskı noktasıdır: ağ iletişimini garanti edemediğinde dağıtık veritabanı tutarlılığı mı yoksa erişilebilirliği mi önceliklendireceğine karar vermelidir.
CAP, bir veritabanı birden çok makineye yayıldığında ne olacağını özetleyen kısa bir yoldur.
Bölünme yokken, birçok sistem hem tutarlı hem erişilebilir gibi davranabilir.
Bölünme olduğunda, neyi önceliklendireceğinize karar vermeniz gerekir:
balance = 100 yazmasını Server A'ya gönderir.\n- 10:01 Ağ bölünmesi: Server A Server B'ye ulaşamaz.\n- 10:02 İstemci Server B'den okuma yapar.\n - Eğer Tutarlılığı önceliklendirirseniz, Server B ya reddetmeli ya da beklemeli.\n - Eğer Erişilebilirliği önceliklendirirseniz, Server B cevap verir ama balance = 80 gibi eski bir değeri dönebilir.CAP, kalıcı bir “sürekli olarak sadece iki tanesini seç” kuralı değildir. Anlamı şudur: bölünme sırasında, hem Tutarlılık hem de Erişilebilirlik aynı anda garanti edilemez. Bölünme dışında, çoğu sistem çoğu zaman her iki garantiye de yakın davranabilir—ta ki ağ yanlış davranana kadar.
Tutarlılığı seçmek, veritabanının “herkes aynı gerçeği görsün” ilkesini “her zaman cevap ver” önceliğinin üstünde tutması demektir. Pratikte bu genellikle güçlü tutarlılık (linearizable) davranışa işaret eder: bir yazma onaylandığında, daha sonraki herhangi bir okuma (herhangi bir yerden) o değeri döner, sanki tek bir güncel kopya varmış gibi.
Ağ bölünmesi olduğunda ve replikalar güvenilir şekilde konuşamadığında, güçlü tutarlı bir sistem bağımsız güncellemeleri her iki tarafta da güvenli şekilde kabul edemez. Doğruluğu korumak için genelde:
Kullanıcı perspektifinden bu, bazı makineler hâlâ çalışıyor olsa bile bir kesinti gibi görünebilir.
Ana fayda düşünmeyi sadeleştirir. Uygulama kodu sanki tek bir veritabanıyla konuşuyormuş gibi davranabilir; replikalar arasında çelişkiler olacağı korkusu azalır. Bu, şu gibi tuhaf durumları azaltır:
Ayrıca faturalama, denetim ve ilk seferde doğru olması gereken her şey için daha temiz zihinsel modeller elde edersiniz.
Tutarlılığın gerçek maliyetleri vardır:
Ürününüz kısmi kesintiler sırasında başarısız istekleri tolere edemezse, güçlü tutarlılık pahalı gelebilir—ancak doğruluk için doğru seçim olabilir.
Erişilebilirliği seçmek, basit bir vaadi optimize etmek demektir: sistem yanıt verir, altyapının bir kısım sağlıksız olsa bile. Pratikte “yüksek erişilebilirlik” hiç hata olmayacağı anlamına gelmez—anlamı, düğüm hataları, aşırı yüklenmiş replikalar veya bozuk ağ bağlantıları sırasında çoğu isteğin yine de yanıt aldığıdır.
Ağ ayrıldığında replikalar güvenilir şekilde konuşamaz. Erişilebilirliğe öncelik veren bir veritabanı genellikle ulaşılabilir taraftan hizmet vermeye devam eder:
Bu uygulamaları hareket halinde tutar, ancak farklı replikaların geçici olarak farklı gerçeklikleri kabul etmesine neden olur.
Daha iyi çalışır halde kalma süresi elde edersiniz: kullanıcılar hâlâ göz atabilir, sepete ürün ekleyebilir, yorum yapabilir veya olayları kaydedebilir—bir bölge izole olsa bile.
Ayrıca stres altındayken daha yumuşak bir kullanıcı deneyimi elde edersiniz. Zaman aşımı yerine uygulamanız “güncellemeniz kaydedildi” gibi davranıp sonra senkronize edebilir. Birçok tüketici ve analiz iş yükü için bu ödün değer.
Fiyatı, veritabanının eski okumalar döndürebilme olasılığıdır. Bir kullanıcı bir replikada profilini güncelleyip hemen başka bir replikadan okursa eski değeri görebilir.
Ayrıca yazma çatışmaları riski vardır. İki kullanıcı (veya aynı kullanıcı iki konumdan) aynı kaydı farklı tarafta güncelleyebilir. Bölünme iyileştiğinde sistem farklı geçmişleri uzlaştırmalıdır. Kurallara göre bir yazı “kazanabilir”, alanlar birleştirilebilir veya çatışma uygulama mantığı gerektirebilir.
Erişilebilirlik odaklı tasarım, geçici anlaşmazlığı kabul edip daha sonra onu tespit edip onarma üzerine yatırım yapmaktır.
Quorumlar, çoğaltılmış veritabanlarının tutarlılık ile erişilebilirlik arasında denge kurmak için kullandığı pratik bir “oylama” tekniğidir. Sisteme tek bir replika yerine yeterli replikanın katılımı istenir.
Quorumlar genellikle üç sayı ile anlatılır:
Basit bir kural: R + W > N ise her okuma en az bir replika üzerinden en son başarılı yazıyla kesişir; bu da eski veri okuma şansını azaltır.
Eğer N=3 replika varsa:
Bazı sistemler daha güçlü tutarlılık için W=3 (tüm replikalar) seçer; ancak bu herhangi bir replika yavaş veya kapalıysa daha fazla yazma hatasına yol açabilir.
Quorumlar bölünme sorunlarını ortadan kaldırmaz—ama ilerleme yapan tarafı tanımlar. Eğer ağ 2–1 şeklinde bölünürse, 2 replikanın olduğu taraf R=2 ve W=2 şartlarını sağlayabilirken izole tek replika sağlayamaz. Bu çakışan güncellemeleri azaltır, ama bazı istemcilerin hata veya zaman aşımı görmesi anlamına gelir.
Quorumlar genelde daha yüksek gecikme (daha fazla düğüme dokunma), daha yüksek maliyet (düğüm arası trafik) ve daha nüanslı hata davranışı (zaman aşımının kullanılabilirlik kaybı gibi görünmesi) demektir. Faydası ise ayarlanabilir bir orta yol olmasıdır: R ve W değerlerini daha taze okumalar veya daha yüksek yazma başarısı lehine ayarlayabilirsiniz.
Nihai tutarlılık, replikaların geçici olarak senkron olmayabileceğini, ancak sonunda aynı değere yakınsaması gerektiğini kabul eder.
Bir zincir kahveci mağazası ortak bir “tükendi” tabelasını güncelliyor gibi düşünün. Bir mağaza tükendi diye işaretler ama bu güncelleme diğer mağazalara birkaç dakika sonra ulaşır. O pencere boyunca başka bir mağaza hâlâ “var” gösterip sonuncuyu satabilir. Sistemde bir bozukluk yok—güncellemeler sadece yetişiyor.
Veriler henüz yayılırken istemciler şu davranışları görebilir:
Nihai tutarlılık sistemleri genelde tutarsızlık penceresini azaltmak için arka plan mekanizmaları ekler:
Erişilebilirliğin tutarlı olmaktan daha önemli olduğu durumlarda iyidir: etkinlik akışları, görüntüleme sayaçları, öneriler, önbelleğe alınmış profiller, günlükler/telemetri ve “birkaç saniye içinde doğru olacak” verilerin yeterli olduğu diğer kritik olmayan veriler.
Bir veritabanı birden fazla replikada yazmaları kabul edince, bölünme sırasında aynı öğeye bağımsız olarak yapılmış iki veya daha fazla güncelleme ile çatışmalar ortaya çıkabilir.
Klasik örnek: bir kullanıcı bir cihazında gönderim adresini değiştirirken diğer cihazında telefon numarasını değiştiriyor. Her güncelleme farklı replika üzerinde kabul edildiyse, replikalar veri alışverişi yaptığında sistem “gerçek” kaydı nasıl belirleyecek?
Birçok sistem last-write-wins ile başlar: en yeni zaman damgasına sahip olan güncelleme diğerlerini geçersiz kılar.
Uygulaması kolay ve hesaplaması hızlı olduğu için caziptir. Dezavantajı, veri kaybına yol açabilmesidir. “En yeni” olan kazanırsa, daha eski ama önemli bir değişiklik sessizce silinebilir—özellikle iki güncelleme farklı alanlara dokunduysa bile.
Ayrıca zaman damgalarının güvenilir olduğu varsayılır. Makine/istemci saatleri arasında kayma (clock skew) yanlış güncellemenin kazanmasına sebep olabilir.
Daha güvenli çatışma işleme genellikle nedensel geçmişi izlemeyi gerektirir.
Kavramsal olarak, versiyon vektörleri (ve daha basit varyantları) her kayda hangi replikaların hangi güncellemeleri gördüğünü özetleyen küçük bir metadata eki ekler. Replikalar versiyonları değiş tokuş ettiğinde, bir versiyonun diğerini içerip içermediğini (çatışma yok) veya ayrıştığını (çatışma var) algılayabilir.
Bazı sistemler, gerçek zaman saatine bağımlılığı azaltmak ama yine de sıralama ipucu sağlamak için Lamport saatleri veya hibrit mantıksal saatler kullanır.
Çatışma tespit edildiğinde seçenekleriniz vardır:
En iyi yaklaşım, veriniz için “doğru”nun ne anlama geldiğine bağlıdır—bazen bir yazının kaybolması kabul edilebilir, bazen bu iş açısından kritik bir hata olur.
Tutarlılık/erişilebilirlik duruşunu seçmek felsefi değil, ürün odaklı bir karardır. Önce şu soruyu sorun: kısa süreli yanlış bir sonuç ne kadar maliyetli, ve "lütfen tekrar deneyin" demek ne kadar maliyetli?
Bazı alanlar yazma anında tek ve otoriter bir cevaba ihtiyaç duyar çünkü “neredeyse doğru” bile yanlış sayılır:
Kısa süreli uyumsuzluğun etkisi düşük veya geri döndürülebilirse, genellikle daha erişilebilir tarafa eğilebilirsiniz.
Pek çok kullanıcı deneyimi biraz eski okumayla çalışır:
Açıkça belirtin ne kadar eskime kabul edilebilir: saniyeler, dakikalar veya saatler. Bu zaman bütçesi replikasyon ve quorum seçimlerinizi yönlendirir.
Replikalar anlaşamazsa genellikle üç UX sonucu ortaya çıkar:
Özelliğe göre en az zararlı olanı seçin; bu kararı tüm sisteme genelleştirmeyin.
C (tutarlılık) eğilimi gösterin eğer: yanlış sonuçlar finansal/kanuni risk, güvenlik sorunları veya geri döndürülemez işlemler yaratıyorsa.\n A (erişilebilirlik) eğilimi gösterin eğer: kullanıcılar hız ve yanıt almayı tercih ediyor, eski veri tolere edilebilir ve çatışmalar sonradan güvenli şekilde çözülebiliyorsa.
Şüphede kaldığınızda sistemi bölün: kritik kayıtları güçlü tutarlı tutun, türetilmiş görünümler (akışlar, önbellekler, analizler) için erişilebilirliği önceliklendirin.
Tüm sistem için tek bir “tutarlılık ayarı” seçmek zorunda değilsiniz. Modern dağıtık veritabanlarının çoğu işlem başına tutarlılık seçmenize izin verir—ve akıllı uygulamalar bunu kullanarak kullanıcı deneyimini düz tutup ödün gerçeğini gizlemez.
Tutarlılığı kullanıcı eylemine göre bir düğme gibi düşünün:
Böylece her şey için en güçlü maliyeti ödemek zorunda kalmazsınız; gerçekten gerekli işlemleri korumuş olursunuz.
Yaygın bir desen: yazmalarda güçlü, okumalarda zayıf:
Bazı durumlarda tersine de çalışır: hızlı yazmalar (sıraya alınmış/nihai) artı güçlü okumalar ile sonucu onaylamak (“Siparişim verildi mi?”).
Ağlar sallandığında istemciler tekrar dener. Tekrarları güvenli kılmak için idempotency anahtarları kullanın ki “siparişi gönder” iki kez çalıştırılsa iki sipariş oluşmasın. Aynı anahtar tekrar görüldüğünde ilk sonucu saklayın ve yeniden döndürün.
Hizmetler arası çok adımlı işlemler için saga kullanın: her adımın bir telafi edici işlemi (iade, rezervasyonu serbest bırakma, gönderimi iptal etme) olsun. Bu, parçalar geçici olarak uyumsuz veya başarısız olduğunda sistemi kurtarılabilir tutar.
Tutarlılık/erişilebilirlik ödününü yönetemezsiniz eğer onu göremezseniz. Üretim problemleri genellikle “rastgele hatalar” gibi görünür; doğru ölçümler ve testler ekleyene kadar.
Kullanıcı etkisine doğrudan bağlanan küçük bir metrik setiyle başlayın:
Mümkünse metrikleri tutarlılık modu (quorum vs lokal) ve bölge/zon ile etiketleyin ki davranışın nerede farklılaştığını görün.
Gerçek kesintiyi beklemeyin. Staging'de kaos deneyleri yapın:
Sadece “sistem ayakta kalıyor”u doğrulamakla kalmayın; hangi garantilerin korunduğunu da doğrulayın: okumalar taze mi kalıyor, yazmalar bloklanıyor mu, istemciler net hatalar mı alıyor?
Şunlar için uyarılar ekleyin:\n
Son olarak, garantileri açıkça dokümante edin: sisteminizin normal durumda ve bölünme sırasında ne vaat ettiğini yazın; ürün ve destek ekiplerini kullanıcının neler görebileceği ve nasıl yanıt verecekleri konusunda eğitin.
Yeni bir ürün üzerinde çalışıyorsanız, özellikle hata modları, tekrar davranışı ve "eski"nin UI'da nasıl gözüktüğünü erken doğrulamak faydalıdır.
Pratik bir yaklaşım, iş akışının (yazma yolu, okuma yolu, tekrar/idempotentlik ve bir uzlaşma işi) küçük bir versiyonunu prototiplemektir. Koder.ai ile ekipler sohbet odaklı bir iş akışı üzerinden web uygulamaları ve backend'ler hızlıca ayağa kaldırabilir, veri modelleri ve API'ler üzerinde hızlıca yineleyebilir ve farklı tutarlılık desenlerini (örneğin sıkı yazmalar + gevşek okumalar) geleneksel bir derleme hattının yükü olmadan test edebilir. Prototip istenen davranışla eşleştiğinde kaynak kodu dışa aktarabilir ve üretime doğru evriltmeye başlayabilirsiniz.
Bir çoğaltılmış veritabanında aynı veri birden fazla makinede yaşar. Bu dayanıklılığı ve gecikme düşürmeyi artırır ama koordinasyon sorunlarını da beraberinde getirir: düğümler yavaşlayabilir, ulaşılamaz olabilir veya ağ tarafından bölünebilir; dolayısıyla her zaman en son yazıyı anında eşleştiremezler.
Tutarlılık şöyle demektir: başarılı bir yazmadan sonra, sonraki herhangi bir okuma aynı değeri döner—hangi replika olursa olsun. Pratikte sistemler bunu sağlamak için okumaları/yazmaları yeterli replika (veya lider) onayı gelene kadar geciktirir veya reddeder.
Erişilebilirlik şu anlama gelir: bazı düğümler kapalı olsa veya iletişim kuramasa bile sistem her isteğe bir hata olmayan yanıt döner. Yanıt güncel olmayabilir veya yerel bilgiye dayanabilir ama sistem kullanıcıları bloklamaktan kaçınır.
Ağ bölünmesi, tek sistem gibi davranması gereken düğümler arasındaki iletişimin kopmasıdır. Düğümler hâlâ sağlıklı olabilir; ancak mesajlar güvenilir şekilde geçemez. Bu durum veritabanını şu seçeneklerden birini seçmeye zorlar:
Bir bölünme sırasında her iki taraf da güncellemeleri kabul edebilir; bunlar hemen paylaşılmaz. Bunun sonucunda görülenler şunlardır:
Bunlar, replika koordinasyonu geçici olarak sağlayamadığında kullanıcıların deneyimlediği sonuçlardır.
Hayır, CAP "kalıcı olarak sadece iki tanesini seç" demek değildir. Anlamı şudur: bir bölünme olduğunda hem:
aynı anda garanti edilemez. Bölünme dışında birçok sistem çoğu zaman her iki özelliğe çok yakın davranabilir—ta ki ağ hatası olana kadar.
Quorumlar, çoğaltılmış veritabanlarının tutarlılık ve erişilebilirlik arasında denge kurmak için kullandığı bir oy verme tekniğidir:
Yaygın bir kural: ise her okuma en az bir replika üzerinden en son başarılı yazıyla kesişir ve eski veri okuma olasılığını azaltır. Quorumlar bölünmeyi ortadan kaldırmaz; hangi tarafın ilerleyebileceğini tanımlar (ör. çoğunluğu olan taraf).
Nihai tutarlılık, replikaların geçici olarak senkron olmayabileceğini, ancak zamanla aynı değere yakınsaması gerektiğini kabul eder. Yaygın anomaliler:
Bunları hafifletmek için , ve periyodik (merkle ağaçları gibi) gibi mekanizmalar kullanılır.
Bölünme iyileştiğinde çatışmalar, farklı replikalarda bağımsız olarak kabul edilmiş farklı yazılar ortaya çıktığında oluşur. Çözüm stratejileri:
Doğru strateji, veriniz için “doğru”nun ne anlama geldiğine bağlıdır.
Kararınızı iş riski ve kullanıcıların hangi hatayı tolere edebileceği belirlemeli:
Pratik desenler: işlem bazında tutarlılık seviyeleri, idempotent tekrarlar, ve çok adımlı işlemler için sagalar ve telafi edici işlemler.