Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Gerçek Sistemlerden Dersler: CRDT, Spanner TrueTime, CockroachDB HLC ve Jepsen
Gerçek sistemler belirsizlikle iki yoldan yaşar: koordinasyonu kaldıran veri tipleri (CRDT) ya da belirsizliği ölçüp bekleyen saatler (Spanner TrueTime, CockroachDB HLC). C# ile G-Counter, PN-Counter ve OR-Set yazıp CAP yazısındaki sepetin silinen kitabı geri getirme sorununu çözüyoruz; ε = 4 ms ile commit wait yaklaşık 9 ms sürüyor. Jepsen'in PostgreSQL ve etcd bulguları da garantiyi dokümantasyondan değil testten okumayı öğretiyor.
Distributed Lock, Lease ve Fencing Token: Kilit Neden Yetmez?
Süreli bir kilit (lease) tek başına doğruluk sağlamaz: kilidi alan process GC duraklamasında kalırsa lease dolar, başkası kilidi alır ve uyanan ilk process yine yazar. Gerçek Redis ve SQLite ile yapılan denemede eski rapor yenisinin üstüne yazılıyor; her kilitle artan bir fencing token'ı veritabanında WHERE token > LastToken ile kontrol edince eski yazma reddediliyor. Redlock tartışmasının iki tarafı ve veritabanının kendi mekanizmaları da yazıda.
Distributed Transaction ve Two-Phase Commit: Neden Microservice'lerde Kullanılmaz?
Two-phase commit (2PC), birden fazla participant'ın bir transaction'ı birlikte commit ya da abort etmesini sağlar, ama coordinator karar vermeden çökerse YES oyu veren participant'lar kilitleri tutarak bekler. System.Transactions'ın 2PC'si volatile participant'larla çalışıyor; ikinci durable participant ise macOS ve Linux'ta PlatformNotSupportedException veriyor. Microservice'lerde availability, coupling ve broker desteği yüzünden yerine saga ve outbox kullanılır.
Consensus ve Raft: Leader Election, Log Replication ve FLP Sonucu
Consensus, node'ların bir değer (ya da bir log sırası) üzerinde anlaşmasıdır; FLP sonucu asynchronous network'te tek bir çökmeye bile dayanıp her zaman sonlanan deterministik bir algoritma olmadığını söyler, Raft ise safety'yi term ve çoğunluk oylarıyla, liveness'ı rastgele timeout'larla sağlar. C# simülasyonunda leader çökünce 254 ms içinde yeni leader seçiliyor; sabit timeout'larda ise 2 saniyede term 13'e çıkıp hiç leader seçilemiyor.
CAP ve PACELC'i Doğru Okumak: "3'ten 2'sini Seç" Neden Yanlış?
CAP, partition sırasında linearizability (C) ile her sağlam node'un cevap vermesi (A) arasında seçim yapmak gerektiğini söyler; partition (P) seçilen bir özellik değil, başa gelen bir olaydır, bu yüzden "3'ten 2'si" özeti yanlıştır. PACELC, partition yokken de latency ile consistency arasında seçim yapıldığını ekler. Örnekte sepet partition'da silinen kitabı geri getiriyor, ödeme azınlık tarafında 503 dönüyor.
Consistency Model'leri: Linearizability, Sequential, Causal ve Eventual Consistency
Consistency model, bir sistemin hangi okuma/yazma geçmişlerine izin verdiğinin tanımıdır: linearizability gerçek zamana uyar, sequential yalnız her client'ın kendi sırasına, causal happens-before'a; eventual consistency ise yalnız sonunda aynı değere varmayı vaat eder. Küçük bir C# checker'ı beş geçmişi değerlendiriyor: yazma bittikten sonraki eski okuma linearizable değil ama sequential; kendi yazmasını görmemek ikisini de bozuyor.
Replication: Leader-Based, Multi-Leader, Leaderless ve Quorum
Replication üç topolojide yapılır: tek leader (basit, failover'da split brain riski), multi-leader (her bölgede yazma, conflict kaçınılmaz) ve leaderless quorum (R + W > N ise okuma son yazmayı görür). N=3 quorum simülasyonunda R=W=1 eski stok değerini döndürüyor, iki node düşünce sistem yazmayı reddediyor, ama "başarısız" yazma bir replica'da kalıp node'lar dönünce okunuyor.
Logical Clock'lar: Happens-Before, Lamport Clock ve Vector Clock
Lamport clock, happens-before ilişkisine uyan bir total order verir ama iki olayın concurrent olup olmadığını söyleyemez; vector clock bunu söyler, bedeli node sayısı kadar büyüyen bir timestamp'tir. C# ile LamportClock, VectorClock ve HybridLogicalClock yazıp xUnit ile test ediyoruz: Lamport'un 1 < 2 dediği iki olay vector clock'a göre concurrent, HLC ise 300 ms geride kalan sunucuda bile causality'yi koruyor.
Physical Clock'lar: NTP, Clock Drift, Leap Second ve Wall Clock'a Güvenmemek
Süre ölçmek için wall clock (DateTime.UtcNow) değil monotonic clock (Stopwatch, TimeProvider.GetTimestamp) kullanılır, olayları sıralamak için de fiziksel timestamp'e güvenilmez: NTP saati ileri geri atabilir, quartz saatler kayar. Örnekte NTP'nin 300 ms'lik düzeltmesi 200 ms'lik bir işi -97 ms gösteriyor ve 300 ms geride kalan bir sunucu yüzünden last-write-wins daha yeni fiyat güncellemesini sessizce siliyor.
System Model'leri: Synchronous, Asynchronous Network, Crash-Stop, Crash-Recovery ve Byzantine Failure
System model, bir algoritmanın network, node ve zamanlama hakkında neyi varsaydığının açık tanımıdır: link'ler fair-loss mı, node'lar crash-stop mu crash-recovery mi Byzantine mi, network synchronous mu partially synchronous mu. Kayıplı bir Channel<T> simülasyonu at-most-once'ın mesaj kaybettiğini, at-least-once'ın kaybolan her ack kadar duplicate ürettiğini gösteriyor; timeout tabanlı failure detector ise hiç çökmeyen bir node'dan saatte 39 kez şüpheleniyor.
Distributed System Nedir ve Neden Zordur? Partial Failure ve Fallacies of Distributed Computing
Distributed system, ortak bir işi network üzerinden mesajlaşarak yapan birden fazla bilgisayardır ve zorluğu partial failure'dan gelir: bir parça bozulurken diğerleri çalışır, timeout ise isteğin işlenip işlenmediğini söylemez. Örnekte 1 saniyelik timeout ve körlemesine retry aynı siparişi iki kez tahsil ediyor; idempotency key ile tahsilat bire iniyor. Sekiz fallacy'nin .NET'teki karşılıkları da yazıda.
System Design Case Study: Flash Sale ve Bilet Satışı
Flash sale'de overselling'i önleyen şey stok kontrolü ile azaltmanın tek atomik adımda yapılmasıdır; ani trafiği CDN'den sunulan bir waiting room emer, ödeme süresini TTL'li hold'lar yönetir, süresi dolan hold stoğu aynı statement'ta geri verir. 2.000 eşzamanlı alıcıyla 100 bilete naif kodun 2.000 rezervasyonu, koşullu UPDATE ve optimistic concurrency'nin gerçek çıktıları, ödeme timeout'u ve bot savunması.