Dağıtık Veri Sistemlerinde Eşzamanlılık
Dağıtık veri sistemlerinde izolasyon, MVCC, kayıp güncelleme, yazma sapması, çoğaltma gecikmesi ve serileştirilebilirlik arasındaki ilişkiyi inceler.
Bir işlemin diğerinden önce gerçekleşip gerçekleşmediği (happens-before ilişkisi), veri sistemlerindeki eşzamanlılığın matematiksel temelini oluşturur. Eğer iki işlem birbirinin varlığından habersizse ve aralarında nedensel bir bağımlılık yoksa, bu işlemler fiziksel zamanlarından bağımsız olarak eşzamanlı (concurrent) kabul edilir. Ortak verilere yönelik eşzamanlı okuma ve yazma işlemleri, sistemlerde veri tutarsızlıklarına ve yarış durumlarına (race conditions) yol açar. İşlemleri mantıksal bir birim olarak gruplayan (transaction) mekanizmalar, bu tür anomalileri önlemek için tasarlanmıştır ve atomiklik, tutarlılık, izolasyon ile dayanıklılık (ACID) garantilerine dayanır.
İzolasyon (isolation), eşzamanlı yürütülen işlemlerin birbirlerinin ara durumlarını görmesini engelleyerek sistemin sanki işlemler seri olarak yürütülüyormuş gibi (serializability) davranmasını sağlar. Ancak tam serileştirilebilirlik mekanizmaları ciddi performans maliyetleri getirdiğinden, modern veri tabanları genellikle daha zayıf izolasyon algoritmaları uygular.
Zayıf İzolasyon ve MVCC
En temel işlem izolasyon seviyesi olan okunmuş veriyi okuma (read committed), kirli okumaları (dirty reads) ve kirli yazmaları (dirty writes) engeller. Veri tabanları, kirli yazmaları önlemek için yazma işlemi süresince satır seviyesinde kilitler (row-level locks) kullanarak yalnızca bir işlemin veriyi güncellemesine izin verir. Kirli okumaları engellemek için ise, okuma kilitlerinin yaratacağı performans darboğazlarından kaçınılır ve bunun yerine yazma işlemi tamamlanana kadar diğer işlemlere verinin eski onaylanmış (committed) sürümü sunulur.
Buna rağmen read committed seviyesi, bir işlemin farklı zamanlarda aynı veriyi okuduğunda farklı sonuçlar elde ettiği okuma sapması (read skew) veya tekrarlanamayan okuma (nonrepeatable read) anomalilerine karşı savunmasızdır. Bu durum, uzun süren analitik sorgularda veya yedekleme (backup) işlemlerinde kalıcı tutarsızlıklara neden olabilir. Okuma sapmasını çözmek için anlık görüntü izolasyonu (snapshot isolation) devreye girer. Anlık görüntü izolasyonunda her işlem, başladığı andaki veri tabanının tutarlı bir anlık görüntüsü üzerinden okuma yapar ve diğer işlemlerin sonradan yaptığı değişiklikleri görmez.
Bu yapı genellikle Çoklu Sürüm Eşzamanlılık Kontrolü (Multi-Version Concurrency Control, MVCC) ile uygulanır. MVCC mimarisinin temel prensibi, okuyucuların yazıcıları ve yazıcıların okuyucuları hiçbir zaman engellememesidir. Veritabanı, her satırın birden fazla sürümünü tutar ve bu sürümleri her işleme atanan tekil, sürekli artan işlem kimlikleri (transaction IDs) ile etiketler. Bir verinin görünür olabilmesi için, satırı ekleyen işlemin okuyucu işlemden önce onaylanmış olması ve ilgili satırın okuyucu başladığında silinmemiş olması şarttır.
Kayıp Güncelleme ve Yazma Sapması
MVCC okuma anormalliklerini çözse de, eşzamanlı yazma işlemlerindeki yarış durumları farklı karakterlerde ortaya çıkmaya devam eder. Okuyup-değiştirip-yazma (read-modify-write) döngülerinde iki işlem aynı veriyi güncellediğinde, birinin yaptığı değişiklik diğerinin üzerine yazılarak kayıp güncelleme (lost update) problemine yol açabilir. Kayıp güncellemeleri önlemek için atomik yazma işlemleri, açık kilitleme (SELECT FOR UPDATE) veya veri tabanının çatışmaları otomatik olarak tespit edip işlemi iptal etmesi (abort) gibi yöntemler kullanılır. Ancak kaynakların sınırlı olduğu durumlarda, MySQL/InnoDB'nin "repeatable read" seviyesi kayıp güncellemeleri otomatik olarak tespit edemezken, PostgreSQL bu durumu başarılı bir şekilde yakalayabilir, bu davranış veri tabanı sürümüne ve mimarisine bağlıdır.
Daha karmaşık ve tespit edilmesi zor bir senaryo ise yazma sapmasıdır (write skew). İki işlem aynı nesneleri okuyup bu sorgu sonucuna (bir öncüle) dayanarak farklı nesneleri güncellediğinde yazma sapması meydana gelir. Örneğin, bir vardiyada en az bir doktorun nöbetçi kalmasını gerektiren bir sistemde, iki doktorun eşzamanlı olarak kendi kayıtlarını nöbetten çıkacak şekilde güncellemesi bu öncülü geçersiz kılar.
Bir işlemin gerçekleştirdiği yazmanın, diğer bir işlemin arama sorgusunun sonucunu değiştirmesi olayına hayalet (phantom) adı verilir. Anlık görüntü izolasyonu, hayaletlerin salt okunur sorguları bozmasını engellese de, okuma-yazma döngülerinde yazma sapmasına neden olmalarını durduramaz. Kilitleme yapılacak belirgin bir veri satırının bulunmadığı durumlarda, veri tabanına yapay nesneler eklenerek çatışmaları somutlaştırmak (materializing conflicts) mümkündür. Fakat bu yöntem, eşzamanlılık kontrol mekanizmasını uygulama veri modeline taşıdığı için yalnızca diğer tüm yöntemlerin tükendiği durumlarda uygulanmalıdır.
Çoğaltma Gecikmesi ve Tutarlılık
Tek düğümlü işlemlerden dağıtık çoğaltma (replication) mimarilerine geçildiğinde izolasyon problemleri, ağ kesintileri ve çoğaltma gecikmesi (replication lag) ile doğrudan etkileşime girer. Lider tabanlı (single-leader) asenkron çoğaltmada, okuma ölçeklendirmesi (read scaling) amacıyla takipçi (follower) düğümlerden yapılan sorgular güncel olmayan veriler döndürebilir ve bu durum sistemin yalnızca nihai tutarlılık (eventual consistency) sağlamasıyla sonuçlanır.
Çoğaltma gecikmesinin neden olduğu bir diğer problem, kullanıcıların kendi yaptıkları değişiklikleri hemen görememesidir. Kendi yazdığını okuma (read-after-write) tutarlılığı, kullanıcının doğrudan değiştirdiği verilerin her zaman lider düğümden veya senkron bir takipçiden okunmasını sağlayarak bu asimetriyi çözer. Eğer kullanıcı birden fazla düğümden sıralı okuma yaparsa, eski bir kopyaya denk geldiğinde zamanın geriye aktığı yanılgısına düşebilir, monotonik okumalar (monotonic reads) garantisi, kullanıcının her zaman aynı kopyadan okuma yapmasını zorunlu kılarak bu problemi önler. Ayrıca, nedensel bir bütünlüğe sahip verilerin farklı hızlarda çoğaltılması nedeniyle sonuçların sebeplerden önce görünmesi riskine karşı tutarlı önek okumaları (consistent prefix reads) kullanılarak yazma işlemlerinin doğru sırayla okunması garanti altına alınır.
Çoklu Lider ve Lidersiz Sistemlerde Çatışma
Çoklu lider (multi-leader) ve lidersiz (leaderless) çoğaltma topolojilerinde, yazma işlemleri aynı anda birden fazla düğümde gerçekleşebildiğinden küresel bir ağ sıralaması (global ordering) dayatılamaz. Bu yapılar, düğüm hatalarına ve bölgesel ağ kesintilerine karşı dayanıklı (fault-tolerant) olsalar da, eşzamanlı yazma çatışmaları kaçınılmazdır.
Çatışma çözümünde yaygın kullanılan son yazan kazanır (last write wins, LWW) stratejisi, her yazma işlemine bir zaman damgası (timestamp) atar ve en büyük zaman damgasına sahip işlemi geçerli kılar. Ancak LWW, zaman damgası sırasının eşzamanlı işlemlerde teknik olarak anlamsız olması nedeniyle arka planda başarılı olarak işlenmiş diğer yazmaları sessizce iptal eder ve kesin veri kaybına (data loss) yol açar.
Daha deterministik otomatik çatışma çözümü (automatic conflict resolution) sağlamak adına Çatışmasız Çoğaltılan Veri Tipleri (Conflict-free Replicated Datatypes, CRDTs) veya İşlemsel Dönüşüm (Operational Transformation, OT) algoritmaları devreye girer. OT, karakter indekslerini daha önce uygulanmış eşzamanlı işlemlere göre dönüştürerek metin tutarlılığını sağlarken, CRDT'ler her bir öğeye benzersiz ve değiştirilemez bir kimlik (ID) atayarak konumları bu kimlikler üzerinden matematiksel olarak hesaplar. Yerel-öncelikli (local-first) senkronizasyon motorları (sync engines), bu matematiksel yaklaşımlarla birlikte cihazların çevrimdışıyken bile yerel kopyalar üzerinde lider gibi davranmasını ve ağa bağlanıldığında tüm eşzamanlı güncellemelerin kayıpsız şekilde birleştirilmesini (merge) mümkün kılar.
2PL, Seri Çalıştırma ve SSI
Veri sistemlerinde hayaletler (phantoms) veya yazma sapması (write skew) gibi anormallikleri tamamen engellemenin tek matematiksel yolu gerçek serileştirilebilirlik (serializability) garantisi sunmaktır. Dağıtık ve tek düğümlü sistemlerde serileştirilebilirlik genellikle üç farklı algoritma üzerinden sağlanır.
Birinci yaklaşım, en eski ve geleneksel mekanizma olan İki Aşamalı Kilitleme'dir (Two-Phase Locking, 2PL). 2PL, yazıcıların diğer yazıcıları ve okuyucuları engellediği, okuyucuların ise yazıcıları beklettiği kötümser (pessimistic) bir eşzamanlılık kontrol mekanizmasıdır. İşlemler yürütülürken kilitlerin alındığı (birinci aşama) ve işlemin sonunda kilitlerin bırakıldığı (ikinci aşama) bu modelde, hayalet okumaları önlemek için tüm sorgu koşulunu kapsayan yüklem kilitleri (predicate locks) teorik olarak gereklidir. Ancak yüklem kilitlerinin performans yükü nedeniyle pratikte bunun bir yaklaşımı olan indeks aralığı kilitleme (index-range locking) kullanılır. Tüm izolasyon kusurlarını önlemesine rağmen 2PL, eşzamanlılığı ciddi şekilde düşürdüğü ve kilitlenmelere (deadlocks) yatkın olduğu için performansı dengesizleştirir.
İkinci yöntem, eşzamanlılık koordinasyonunu tamamen denklemden çıkaran gerçek seri çalıştırma (actual serial execution) yaklaşımıdır. Bütün işlemler tek bir iş parçacığı (single thread) üzerinde arka arkaya işletilir. Bu mimari, aktif veri setinin belleğe (RAM) sığdığı ve tüm işlemlerin ağ veya disk I/O işlemlerini beklemeden önceden derlenmiş saklı yordamlar (stored procedures) olarak yürütüldüğü özel durumlarda yüksek verim (throughput) sağlar.
Üçüncü ve en modern yaklaşım olan Serileştirilebilir Anlık Görüntü İzolasyonu (Serializable Snapshot Isolation, SSI), anlık görüntü izolasyonunun performans avantajlarını serileştirilebilirlik ile birleştiren iyimser (optimistic) bir algoritmadır (2008 yılında literatüre sunulmuştur). SSI'da işlemler kilit beklemek yerine hemen çalıştırılır, ancak işlem tamamlanıp veri tabanına işlenmeden (commit) hemen önce izolasyonun ihlal edilip edilmediği denetlenir. Veritabanı, bir işlemin eski bir MVCC anlık görüntüsünden okuma yapıp yapmadığını veya önceki okumaları etkileyen sonradan yapılmış bir yazma olup olmadığını tespit eder. Bir işlemin verdiği kararın dayandığı öncül (premise) eşzamanlı bir yazma ile eskimişse, işlem abort edilerek yeniden denemeye zorlanır. SSI, okuyucuların yazıcıları engellememesini garanti ettiği için özellikle ağır okuma yüküne sahip sistemlerde işlem hızlarını başarıyla ölçeklendirir.
Tasarım kararları değerlendirildiğinde veri yoğun sistemlerde izolasyon, basit bir donanım optimizasyonundan çok, veri mutasyonlarının tutarlılığını doğrulayan bir bilgi işlem dinamiğidir. Sistem mühendislerinin, disk gecikmeleri ve ağ bölümlenmeleri altında veri bozulmalarını önleyebilmesi için mantıksal nedenselliğin sınırlarını doğru analiz etmeleri gerekir. Güçlü kilit algoritmalarının veri bütünlüğünü dayattığı 2PL modeli ile, CRDT gibi çözümlerin çatışmaları gecikmeli olarak entegre ettiği çoğaltma mimarileri arasında yapılacak seçim, doğrudan fiziksel ağ kısıtları altında tolere edilebilecek hata senaryolarına bağlıdır. Sonuç olarak operasyonel kararlılık, uygulama mantığının varsaydığı izolasyon modeliyle, veri tabanının dağıtık altyapıda fiilen sağlayabildiği matematiksel garantilerin örtüşmesini zorunlu kılar.