Distributed systems are hard because the network is unreliable and time is messy: partial failures, latency, and inconsistent views of the world. These notes focus on the core concepts that show up in production: consistency tradeoffs, messaging, coordination, and failure handling. Example: CAP is not a slogan; it explains why a partition forces you to pick between availability and strong consistency.

Quality attributes and measurable targets

The four labels are an orientation mnemonic, not independent boxes. Logging does not create reliability, and load balancing alone does not create availability. Turn each attribute into a workload, target, failure model, and measurement window:

AttributeConcrete targetMechanism question
ScalabilitySustain 10,000 checkout RPS with p99 below 400 ms, errors below 0.1%, and cost below $0.002/requestWhich resource saturates first, and how much capacity does one added unit buy?
Availability99.95% successful eligible checkout requests over 30 daysWhich zone, region, dependency, or control-plane failures remain in the request path?
ReliabilityNo duplicate charges; committed ledger entries survive a zone loss; RPO 0 and RTO 15 minutes for payment writesWhat correctness, durability, detection, and recovery evidence proves this?
Performancep50/p95/p99 latency plus completed throughput and CPU, memory, I/O, and network per unit of workWhich stage consumes the latency and resource budget under the declared traffic mix?

Targets conflict. Synchronous multi-region replication may improve durability and recovery while raising write latency and reducing partition-time availability. Caching may improve latency and origin efficiency while weakening freshness. State the business invariant that wins, then test the counter-cost.

Map symptoms to mechanisms, then test the tradeoff

Treat the visual as diagnostic prompts, not prescriptions:

SymptomCandidate mechanismCondition that must holdCounter-cost and proof
Read-heavy originCache, read replica, or indexReads repeat, tolerate a freshness budget, or scan avoidable dataInvalidation/lag/write amplification; compare hit ratio, query plan, and p99
High write loadBatch, partition, append log, or queueWrites can be grouped, distributed by a stable key, or acknowledged asynchronouslyHot partitions, delayed visibility, replay; load-test the real key distribution
Single point of failureReplication plus Failure Detection and tested failoverReplicas do not share the same failure domainCoordination, lag, split brain; inject the failure and measure RTO/RPO
High request latencyTrace the critical path, then cache, index, colocate, or defer workThe measured slow stage matches the chosen mechanismStaleness, coupling, or async complexity; compare end-to-end percentiles
Large immutable payloadsObject storage plus a claim-check referenceConsumers can fetch by durable ID and checksumExtra fetch, authorization, lifecycle; test loss and expired credentials
Poor diagnosisCorrelated traces, metrics, and logsContext propagates through sync and async boundariesTelemetry cost/cardinality; reconstruct one failed request from evidence

Decision table for recurring system tradeoffs

Ask the same four questions for every choice: what is the workload, what fails, what consistency is required, and who operates the added machinery?

ChoicePrefer first side whenPrefer second side whenFollow-up note
Scale up / scale outImmediate headroom and one-node simplicity matterReplica interchangeability and failure isolation justify distributionScalability Patterns
Synchronous / asynchronousThe caller needs the result inside its latency budgetWork can complete later and bursts need bufferingMessage Queues
Strong / eventual consistencyA stale or conflicting result breaks an invariantTemporary divergence has a repair rule and UX budgetConsistency Models and CAP theorem
Normalized / denormalized readsWrite integrity and flexible queries dominateA known read shape needs predictable low latencyCQRS
Stateful / stateless serviceLocal state is intrinsic and partitioned deliberatelyAny healthy replica should serve the next requestLoad Balancing
Central orchestration / event choreographyOrdered workflow state and compensation must be explicitReactions are independent and ownership can stay distributedEvent-Driven Architecture

Do not select SQL versus key-value, REST versus GraphQL, or batch versus stream from a label alone. Start from access patterns, ordering/freshness, replay window, failure recovery, and the team’s operating skills.

Distributed identifier requirements and failure modes

Design IDs from the contract:

  • Collision domain: unique within a table, tenant, region, or the whole system?
  • Ordering scope: no order, rough creation order, or monotonic order per generator?
  • Clock behavior: what happens when time moves backward or two nodes share a timestamp?
  • Bit budget: how many years, nodes, and IDs per time unit fit before exhaustion?
  • Node allocation: static worker IDs, leased IDs, coordination service, or random space?
  • Storage locality: random IDs can fragment B-tree indexes; time-ordered IDs improve locality but create hot ranges.
  • Information leakage: timestamps, node IDs, and sequence rates can reveal creation time or volume.
  • Recovery: generator restarts must not reuse sequence state or an expired node lease.

A Snowflake-like 63-bit payload might allocate 41 bits to milliseconds, 10 to a worker ID, and 12 to a per-millisecond sequence: about 69 years from a custom epoch, 1,024 workers, and 4,096 IDs/ms/worker. Those numbers are a contract, not defaults. Clock rollback must block, switch to a safe logical time, or fail closed; silently reusing a prior timestamp and sequence can collide.

Use Unique ID Generation for the full decision. UUIDv4 buys coordination-free randomness; UUIDv7 adds time ordering with a standardized 128-bit layout; database sequences buy compact monotonic IDs inside one coordination domain. None should be judged by whether it is “numeric” or whether creation order can always be reconstructed from the identifier.

Pattern Map

The visual mixes patterns from different layers. Use this linked map to keep the problem and cost visible:

GroupPattern noteProblem solvedCost introduced
CommunicationAPI GatewayStable policy and routing boundary for many APIsCentral latency, configuration, and blast radius
CommunicationWebhooksPush events across organizational boundariesSignature, retry, replay, and reconciliation contract
ResilienceCircuit BreakerStop repeated calls to a failing dependencyThreshold tuning and open-state degraded behavior
ResilienceHigh Availability and Failure DetectionMaintain service through component failureRedundancy, detection delay, failover ambiguity
Data modelingCQRS and Event SourcingSeparate read/write models or retain authoritative event historyProjection lag, schema evolution, replay operations
CoordinationDistributed LocksSerialize one lease-scoped critical actionFencing, expiry, quorum availability, deadlock risk
MessagingMessage Queues and IdempotencyBuffer, fan out, and safely retry workDuplicates, ordering scope, backlog, DLQ ownership
PartitioningConsistent HashingLimit key remapping as nodes changeVirtual-node tuning, hotspots, membership changes

Patterns compose but are not substitutes. A leader election can choose one coordinator; a circuit breaker protects calls to it; pub/sub distributes its events; sharding partitions data. Each operates at a different boundary and needs its own failure test.

References

ByteByteGo provenance