Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Lessons from Real Systems: CRDTs, Spanner TrueTime, CockroachDB HLC and Jepsen
Real systems live with uncertainty in two ways: data types that remove coordination (CRDTs) or clocks that measure uncertainty and wait it out (Spanner TrueTime, CockroachDB HLC). We write a G-Counter, a PN-Counter and an OR-Set in C# and fix the CAP post's cart that brought back a removed book; with ε = 4 ms, commit wait takes about 9 ms. Jepsen's PostgreSQL and etcd findings teach us to read guarantees from tests, not documentation.
Distributed Locks, Leases and Fencing Tokens: Why a Lock Is Not Enough
A time-limited lock (a lease) does not guarantee correctness on its own: if the holder hits a GC pause, the lease expires, someone else takes the lock, and the first process still writes when it wakes up. In a run with real Redis and SQLite the stale report overwrites the new one; checking a fencing token that grows with every lock in the database with WHERE token > LastToken rejects the stale write. Both sides of the Redlock debate and the database's own mechanisms are covered too.
Distributed Transactions and Two-Phase Commit: Why They Are Avoided in Microservices
Two-phase commit (2PC) lets several participants commit or abort a transaction together, but if the coordinator crashes before deciding, participants that voted YES wait while holding their locks. System.Transactions runs 2PC with volatile participants; a second durable participant throws PlatformNotSupportedException on macOS and Linux. Because of availability, coupling and missing broker support, microservices use sagas and the outbox instead.
Consensus and Raft: Leader Election, Log Replication and the FLP Result
Consensus is nodes agreeing on a value (or on the order of a log); the FLP result says no deterministic algorithm in an asynchronous network can tolerate even one crash and always terminate, while Raft provides safety through terms and majority votes and liveness through randomized timeouts. In a C# simulation a new leader is elected within 254 ms of the leader crashing; with fixed timeouts the term climbs to 13 in 2 seconds and no leader is ever elected.
Reading CAP and PACELC Correctly: Why "Pick 2 of 3" Is Wrong
CAP says that during a partition you must choose between linearizability (C) and every non-failing node answering (A); a partition (P) is not a property you choose but an event that happens to you, so "pick 2 of 3" is wrong. PACELC adds that without a partition you still trade latency for consistency. In the example the cart brings a removed book back after a partition and payment returns 503 on the minority side.
Consistency Models: Linearizability, Sequential, Causal and Eventual Consistency
A consistency model defines which histories of reads and writes a system allows: linearizability respects real time, sequential consistency only each client's own order, causal consistency happens-before, while eventual consistency only promises to converge eventually. A small C# checker evaluates five histories: a stale read after a write has finished is not linearizable but is sequential; not seeing your own write breaks both.
Replication: Leader-Based, Multi-Leader, Leaderless and Quorums
Replication comes in three topologies: a single leader (simple, with split-brain risk on failover), multi-leader (writes in every region, conflicts are unavoidable) and leaderless quorums (a read sees the latest write if R + W > N). In an N=3 quorum simulation, R=W=1 returns a stale stock value, the system refuses writes when two nodes are down, yet a "failed" write survives on one replica and becomes visible once the nodes return.
Logical Clocks: Happens-Before, Lamport Clocks and Vector Clocks
A Lamport clock gives a total order consistent with happens-before but cannot tell whether two events are concurrent; a vector clock can, at the price of a timestamp that grows with the number of nodes. We write LamportClock, VectorClock and HybridLogicalClock in C# and test them with xUnit: two events Lamport orders as 1 < 2 turn out to be concurrent, and an HLC preserves causality even on a server whose clock is 300 ms behind.
Physical Clocks: NTP, Clock Drift, Leap Seconds and Not Trusting the Wall Clock
Measure durations with a monotonic clock (Stopwatch, TimeProvider.GetTimestamp), not the wall clock (DateTime.UtcNow), and do not order events by physical timestamps: NTP can step the clock back and forth and quartz clocks drift. In the example a 300 ms NTP correction makes a 200 ms task look like -97 ms, and a server 300 ms behind makes last-write-wins silently discard the newer price update.
System Models: Synchronous and Asynchronous Networks, Crash-Stop, Crash-Recovery and Byzantine Failures
A system model is an explicit statement of what an algorithm assumes about the network, the nodes and timing: are links fair-loss, do nodes crash-stop, crash-recover or behave Byzantine, is the network synchronous or partially synchronous. A lossy Channel<T> simulation shows at-most-once losing messages and at-least-once producing one duplicate per lost ack, while a timeout-based failure detector suspects a node that never crashes 39 times an hour.
What Is a Distributed System and Why Is It Hard? Partial Failure and the Fallacies of Distributed Computing
A distributed system is several computers doing a shared job by exchanging messages over a network, and its difficulty comes from partial failure: one part breaks while the others keep running, and a timeout does not tell you whether the request was processed. In the example a 1-second timeout plus a blind retry charges the same order twice; an idempotency key brings it back to one. The post also maps the eight fallacies to concrete .NET situations.
System Design Case Study: Flash Sales and Ticketing
What prevents overselling in a flash sale is doing the stock check and the decrement in a single atomic step; a waiting room served from a CDN absorbs the spike, holds with a TTL manage the payment window, and expired holds return stock in the same statement. Real output with 2,000 concurrent buyers for 100 tickets: 2,000 reservations from naive code, a conditional UPDATE and optimistic concurrency, plus payment timeouts and bot defense.