Please ๐Ÿ–ฑ๏ธ here for Github Blogs

High Availability Patterns Reference

  • May 27, 2025
Table of Contents

This reference collects pattern tables from the main High Availability post and adds pattern families not covered there. Each section compares strategies or patterns across dimensions relevant to availability. Sources are cited per section.

Consistency Models

Interservice consistency

When service A calls service B synchronously, A’s availability is coupled to B’s โ€” if B is slow or down, A degrades too. This is the CAP trade-off at the service boundary: synchronous propagation gives immediate consistency at the cost of availability. The patterns below decouple services by accepting eventual consistency.

The same consistency models that govern database replication apply directly to interservice communication โ€” any time state is replicated or propagated across nodes (DB replicas, caches, or microservices), the same trade-offs and vocabulary apply.

Sources: Microservices Patterns by Chris Richardson (Ch. 4, 7); Building Event-Driven Microservices by Adam Bellemare (Ch. 3, 6)

PatternHow it worksConsistencyOperational necessities
Async messagingA publishes an event (“OrderCreated”) to a broker (SQS/SNS, Kafka, EventBridge); B consumes asynchronously. A no longer blocks on B’s availabilityEventualBroker HA, DLQ, consumer lag monitoring
Transactional OutboxEvent written to an outbox table in the same local transaction as the business data; a separate relay process (or CDC) reads that table and publishes to the broker. Solves the dual-write problem โ€” crash between DB write and publish would otherwise cause divergenceAt-least-once, eventualIdempotent consumer, relay process, outbox table cleanup
Change Data Capture (CDC)/Transactional log tailingA tool like Debezium (or DynamoDB Streams / Kinesis) tails the DB commit log and emits change events automatically. Removes the outbox relay (reads from one system and writes to another similar to polling publisher); decouples propagation from app code entirelyAt-least-once, eventualCDC infra, schema change handling
Saga โ€” ChoreographyServices react to each other’s events in sequence; compensating transactions undo prior steps on failure. No central coordinator โ€” simpler but harder to trace as the chain growsEventual across stepsPer-service compensation logic, event tracing, monitoring
Saga โ€” OrchestrationCentral saga coordinator tells each service what to do next and manages compensation. Easier to reason about and debug, but adds a new component to keep availableEventual across stepsCoordinator HA, central state tracking
CQRSA owns writes; B (or several B’s) maintain eventually-consistent read models / projections built from A’s event stream. Read path independent from write pathEventual (read model lags)Projection infrastructure, schema migrations across models

How the standard consistency models map to a two-service scenario:

  • Strong consistency โ€” every reader sees the same value immediately after a write, regardless of which node or service they query. The synchronous call gave this: A waited for B to confirm before the operation was considered done, so anyone reading from B afterward saw the update. Availability suffered because enforcing this across a slow or unreachable node means blocking or failing.
  • Eventual consistency โ€” no guarantee about when B converges, only that it will given no more writes. Async messaging gives this: A returns immediately, B catches up whenever the message is processed. Availability goes up, but there is a window where A and B disagree.
  • Read-your-writes consistency โ€” the writer itself sees its own write on subsequent reads, even if other readers might not yet. This matters when the same client that triggered a change in A immediately queries B and expects to see it (e.g. a user updates a profile in service A, then the UI fetches it from service B and the update appears missing). Solved by routing that specific read back to A’s primary or a cache A writes through, rather than waiting on B’s eventual sync.
  • Causal consistency โ€” causally related operations (B’s event depends on A’s event) are seen by everyone in that order, even if unrelated operations can be reordered. If A emits “OrderCreated” then “OrderCancelled,” the consumer must see Created before Cancelled. Achieved via partition keys (Kafka partitioning by order ID guarantees ordering within that key) or version vectors.

Patterns to consistency mapping:

PatternConsistency it typically gives
Synchronous callStrong
Async messaging / outbox / CDCEventual
SagaEventual, with compensation for failures
CQRS read modelEventual (sometimes read-your-writes via a cache layer)

The practical question is not which pattern is correct in the abstract โ€” it is which guarantee the business requirement actually needs. If nothing bad happens when B lags behind A by a few hundred milliseconds to a few seconds, eventual consistency with async messaging is the right call. If the caller needs to see its own write immediately, that is a read-your-writes requirement on a specific path, not a reason to make the whole system strongly consistent again.

Operational necessities for any async pattern:

  • Idempotency โ€” consumers deduplicate by event ID because brokers offer at-least-once, not exactly-once
  • Dead-letter queues โ€” events B cannot process must not vanish silently; DLQs capture them for inspection and replay
  • Lag monitoring โ€” track the staleness window so “eventual” is measurable in practice
  • outbox pattern + SQS/SNS (or Kafka) + idempotent consumer. - This removes synchronous coupling without needing full saga orchestration โ€” save that for multi-step business transactions, not a two-hop propagation.

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 5, 9)

ModelBehaviourHA Trade-offExample
Strong consistencyAll nodes see the same data at the same timeHighest correctness, highest latency, potentially lower availabilityDynamoDB DAX, Spanner
Eventual consistencyWrites propagate asynchronously; stale reads possible until convergenceLower latency, higher availabilityDynamoDB default, S3
Read-after-write consistencyA client always sees its own writes immediately, but others may notBalances write availability with read freshnessUser session stores (S3)
Causal consistencyCausally related operations seen in order; unrelated ones can lagPreserves logical ordering without global coordinationKafka, Kinesis stream where events are ordered given a parition key

Note: eventual vs read-after-write: With eventual consistency even the writer may not see their own write immediately โ€” the read could land on a replica still catching up. With read-after-write consistency the writer always sees their own writes, but other clients may still read stale data for a while.


CAP Theorem

CAP Theorem: In a distributed data store, you can have at most two of Consistency (every read returns the most recent write), Availability (every request receives a non-error response) and Partition Tolerance (the system continues operating despite network failures).

Note โ€” two caveats to keep in mind:

  1. Writes during a partition: In a CP system the majority side keeps accepting writes but the minority side rejects writes (returns errors) to prevent divergence. Those writes fail until the partition heals โ€” they are not lost, simply denied. In an AP system both sides accept writes but data may diverge until the link is restored.

  2. Why CA is impossible: Partitions are inevitable โ€” network failures will happen. A CA-classified system is only CA when the network is perfect, which is never true at scale. The real choice in production is CP or AP.

How real systems pick their trade-off:

SystemOfficial CAPHow they engineer around the sacrificed aspectUse Cases
SpannerCATrueTime (GPS + atomic clocks) guarantees external consistency across regions; Google’s private redundant fiber network makes partitions so rare that 99.999% availability is achievable despite being CPGlobal financial ledgers, multi-region inventory, planetary-scale OLTP
DynamoDBAPDefault is eventually consistent; per-request strongly consistent reads available at higher latency/cost; DynamoDB Transactions add causal consistency on top of an AP foundationSession stores, shopping carts, gaming leaderboards, high-traffic user profiles, IoT event ingestion
CassandraAPTunable consistency per query (ONE, QUORUM, ALL) โ€” dial up when needed; no single point of failure means linear scalability at the cost of strong consistencyTime-series data, IoT sensor ingestion, messaging / chat, recommendation engines
MongoDBCPAutomatic replica-set failover; all writes go to primary; reads can be configured for eventual consistency (secondary reads) when partition tolerance matters moreContent management, catalogs, real-time analytics, mobile backends
CockroachDBCPSerializable isolation via Raft consensus; survives full region outages โ€” but drops writes if no quorum is reachableMulti-region SaaS backends, financial services requiring strong consistency with geo-distribution
Clustered PG / MySQLCPPrimary handles all writes; replica takes over on failure โ€” writes are blocked during promotion. RDBMS outside CAP’s scope entirely (CAP governs distributed systems; a single instance is not distributed)Single-region financial transactions, ERP, traditional relational workloads

Key insight: The “sacrificed” pillar is never truly zero. AP systems find ways to give you consistency when you need it (DynamoDB strongly consistent reads, Cassandra QUORUM). CP systems invest heavily in infrastructure to make partitions rare (Spanner’s private network, Raft lease mechanisms). No system fully ignores any pillar โ€” they just prioritise.

No database guarantees 100% availability. The best achievable is five 9s (99.999%) โ€” about 5 minutes of downtime per year. Even AP systems go down during a full-region outage (no replicas left) or a software/ops failure that affects all nodes simultaneously. Real-world outages happen regardless of architectural trade-off: global DNS failures, bad schema migrations, shared control-plane bugs, misconfigured firewalls.

DynamoDB-specific write behaviour (being AP): DynamoDB does not have dirty writes or dirty reads โ€” every write is atomic and there is no uncommitted state. However, its default last-writer-wins policy means concurrent writes silently overwrite each other (lost updates). To prevent this, use conditional writes (ConditionExpression) for optimistic locking, or DynamoDB Transactions for serializable isolation. The trade-off: preventing lost updates requires a read-before-write round trip, reducing throughput.

RDBMS replication modes (sync vs async): In async replication (default in PostgreSQL, MySQL) the primary commits immediately and ships the WAL to replicas asynchronously. A replica failure never stalls the primary โ€” the replica catches up when it returns. In sync replication, the primary waits for at least one replica to acknowledge before committing. If the replica is down, the primary stalls. Most production deployments use semi-sync โ€” the primary waits for a configurable timeout (e.g. 100ms), then falls back to async to avoid blocking writes on a slow or unreachable replica.

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 9); “Brewer’s Conjecture and the Feasibility of C, A, P” (Eric Brewer, PODC 2000)


Write Anomalies

Write anomalies: Types of data corruption that can occur when multiple clients read and write concurrently without proper isolation. The choice of consistency model and database architecture determines which anomalies are possible.

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 7)

AnomalyDefinitionRDBMS (PG / MySQL)AP NoSQLAvailability trade-off
Dirty writeOverwriting data that another client is still modifying (has not committed yet)Prevented at all isolation levels โ€” uncommitted writes are invisible via row-level lockingNot possible โ€” there is no uncommitted state. Every write is atomic and immediately visibleNo trade-off: atomic-write model naturally avoids this
Dirty readReading data that another client is modifying but has not committed yetPrevented at Read Committed and aboveNot possible (same reason โ€” no uncommitted state)No trade-off
Lost updateTwo concurrent writes silently overwrite each other; the last writer wins and the earlier write disappearsPrevented at all isolation levels โ€” a write locks the row until commit, so concurrent writes queueDefault: last-writer-wins. Prevented via conditional writes (optimistic locking) or transactionsPreventing requires a read-before-write round trip, reducing throughput and increasing latency. Last-writer-wins favours availability
Non-repeatable readReading the same row twice and getting different results because another client modified it in betweenPossible at Read Committed; prevented at Repeatable Read+Strongly consistent reads return the latest version every time. Eventual consistency may return stale committed data, but that’s not a phantomStrongly consistent reads cost more resources and add latency
Phantom readA search predicate returns different sets of rows on two executions because another client inserted/deleted rows in betweenPossible at Read Committed and Repeatable Read; prevented at SerializableNo equivalent concept in key-value / document stores โ€” queries reflect current committed stateโ€”

Partitioning (Sharding)

Partitioning: Splitting a dataset across multiple independent nodes so no single node holds everything. Each partition is responsible for a subset of the data. In HA terms:

  • Limits blast radius โ€” if one partition fails, only the data on that node is affected; the rest stays up.
  • Enables horizontal scaling โ€” more partitions = more nodes = more room for redundancy.
  • Determines rebalance complexity โ€” adding/removing nodes requires redistribution (e.g. consistent hashing minimises moves).

Partitioning strategies (choices):

StrategyHow it worksHA StrengthsHA Weaknesses
Range-basedSplit by key range (A-M, N-Z)Simple, efficient range queriesHot spots if distribution is skewed; rebalancing moves large ranges
Hash-basedHash(key) % N determines shardEven distribution, good load balanceRange queries hit all shards; adding/removing nodes reshuffles most data
Directory-basedLookup table maps key to shardFlexible, supports dynamic splitsLookup table is a SPOF and potential bottleneck
List-basedSplit by discrete value list (region: US, EU, APAC)Aligns with access patterns, geo-isolationUneven list sizes cause hot shards
CompositeCombine two or more (e.g. hash within range)Best of both worldsHigher routing and rebalance complexity

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 6); The Art of Scalability by Abbott & Fisher (Ch. 15)


Caching

Caching: Temporarily storing frequently accessed data in a fast, nearby layer to reduce load on slower backend systems. In HA context:

Placement choices:

PlacementArchitectureHA StrengthsHA Weaknesses
LocalIn-process per instance (Caffeine, Guava)Fastest, no network dependencyStale across instances, memory-limited per node
DistributedShared cluster (Redis, Memcached)Consistent view, replication across AZs, larger capacityNetwork latency, cache cluster is itself a SPOF

Write policy choices:

StrategyHow it worksHA StrengthsHA Weaknesses
Cache-aside (lazy loading)App checks cache; on miss, loads from DBDegrades to DB reads if cache fails; battle-testedThundering herd on cold start; stale until TTL expires
Read-throughCache fetches from DB on miss transparentlySimplified app logic, consistent stalenessCache failure causes full outage until restored
Write-throughWrite to cache + DB synchronouslyCache always freshHigher write latency; double failure surface
Write-behindWrite to cache, async flush to DBLow write latency, absorbs burstsData loss if cache fails before flush completes
Refresh-aheadCache proactively refreshes expiring entriesNo thundering herd, consistent low latencyWastes resources if predictions miss

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 12)


Replication Patterns

Replication has two orthogonal dimensions: topology (who can accept writes) and mode (when the write returns to the caller).

Topology patterns:

PatternWriteReadHA StrengthsHA Weaknesses
Single-leaderOne nodeStrong from leader; stale from replicasSimple failover, known semanticsWrite SPOF; failover has RTO
Multi-leaderMultiple nodesEventual (conflict resolution)Survives region outage; no write SPOFConflict resolution (LWW loses data); causality tracking required
Leaderless (quorum)Any node (R+W > N for strong)Configurable via quorum sizeHighest availability; linear scalabilityWeak consistency at low quorum; vector clocks needed

Replication modes (applies within any topology):

ModeBehaviourHA Impact
SynchronousPrimary waits for all replicas to ack before confirmingZero data loss; higher write latency; availability drops if a replica is slow
AsynchronousPrimary confirms before replicas ackLow latency; data loss on primary failure before replication catches up
Semi-synchronousPrimary waits for one replica to ack, rest asyncBest trade-off for most workloads; some data loss risk still present

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 5); Database Internals by Alex Petrov (Ch. 9-10)


Leader Election / Distributed Coordination

Mechanisms for electing a single leader among multiple replicas to coordinate writes, assign partition ownership or manage task distribution:

PatternHow it worksHA StrengthsHA Weaknesses
Raft / Paxos consensusMajority-based voting to elect a leader with a replicated write-ahead logStrong consistency guarantees; well-understood safety properties; no split-brainMultiple RTTs per write under leader; leader election has a blackout window
Lease-based (etcd, Zookeeper, Consul)Candidate creates an ephemeral lease; lease expiry triggers re-electionSimple lease semantics; lease renewal acts as heartbeat; widely used in service discoveryLease window must be tuned โ€” too short causes false elections, too long delays failover; clock skew sensitivity
Generation clock / fencing tokenMonotonically increasing token issued with each leader term; older tokens are rejected by the storage layerPrevents a stale leader from corrupting shared state after a split or partition healsRequires the resource layer (DB, queue, lock manager) to validate the token on every write
Bully algorithmHighest-ID node becomes leader; all others deferSimple to implement; no consensus overheadIf the highest-ID node is unstable leadership churns; O(nยฒ) message complexity

How Raft consensus works. A cluster elects a single leader by majority vote. The leader is the only node that accepts writes โ€” followers just replicate its decisions. No split-brain is possible because only one leader can exist per term.

Replicated write-ahead log (WAL). Every write is first appended to a durable log file on the leader. That log entry is replicated to a majority of followers before the leader commits it. Each follower appends the same entry to its own WAL in the same order. If the leader crashes, the new leader replays its WAL so no committed write is lost. Because the log is write-ahead (recorded before the state is updated) and replicated (copied to N servers), you get durability even if half the cluster dies. This is the foundation of Aurora, DynamoDB Global Tables, CockroachDB, Kafka’s KRaft mode and many other HA data services.

Ephemeral (in lease-based elections) means temporary โ€” the lease auto-expires if not renewed. The leader periodically renews its lease to stay alive; if it crashes, the lease expires and triggers re-election. No manual cleanup needed.

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 8, 9); Database Internals by Alex Petrov (Ch. 7-8)


Load Balancing Patterns

Distribution algorithms:

PatternHow it worksHA StrengthsHA Weaknesses
Round RobinCycles through targets in orderSimple, no stateIgnores backend load; slow instances get the same rate as fast ones
Least ConnectionsSends to backend with fewest active connectionsAdapts to varying request durationsRequires connection tracking state on LB
Least Response TimeSends to fastest-responding backendAdapts to degraded instances (slower = fewer requests)Relies on accurate latency measurements
WeightedDistributes proportionally (e.g. 3:1)Handles heterogeneous instancesStatic weights need manual tuning
IP Hash / Sticky sessionsPins client to backend via hashConsistent routing for stateful appsBreaks when backend count changes; thundering herd on failover
Consistent HashingHash-based with minimal reshuffle on node changeCache affinity; minimal rebalancing on scale eventsComplex hash ring management

Architectural patterns (LB placement):

PatternArchitectureHA StrengthsHA Weaknesses
Layer 4 (TCP)Routes on IP + portSimple, fast, no TLS overheadNo content-aware routing; limited health checks
Layer 7 (HTTP)Inspects headers, paths, cookiesContent-based routing, smart health checks, TLS terminationHigher CPU cost; more attack surface (TLS)
Active-passiveOne LB handles traffic; standby takes over on failureSimple failover, no split-brainHalf capacity idle; failover has RTO
Active-active (anycast / DNS GSLB)Multiple LBs accept traffic simultaneouslyFull capacity utilised; sub-second failover (anycast)Complex routing; DNS caching delays failover (GSLB)

Instance lifecycle / draining:

PatternHow it worksHA StrengthsHA Weaknesses
Lame Duck / Graceful ShutdownInstance deregisters from the LB or returns unhealthy, finishes in-flight requests within a configured grace period (drain window), then shuts downZero failed requests during deployments, scale-in and rolling updates; hot instances get no new trafficGrace period must exceed the longest expected request; slow clients may still see connection reset; in-flight tracking adds application complexity

Sources: Site Reliability Engineering by Beyer et al. (Ch. 20)


Connection Pooling Patterns

Size strategy:

PatternHow it worksHA StrengthsHA Weaknesses
Fixed poolConstant size regardless of loadPredictable resource usageCannot absorb traffic spikes; queue builds up
Dynamic poolGrows/shrinks with demandAdapts to varying loadRisk of connection storm cascading to backend under peak
Partitioned (separate pools)Isolated pool per workload (read / write / critical)Connection-level bulkheading โ€” one caller type cannot starve othersRequires more connections; harder to tune per-pool

Health validation:

PatternBehaviourHA StrengthsHA Weaknesses
Test-on-borrowValidate before handing to callerCatches dead connections before useAdds latency to every acquire
Test-idlePeriodic check on idle connectionsLow overhead; catches many failures earlyStale between check intervals
Test-on-returnCheck when returned to poolUseful for detecting leaky connectionsDoes not protect the next acquirer

Exhaustion behaviour:

PatternBehaviourHA StrengthsHA Weaknesses
Block / queueCaller waits until a connection is availableHighest throughput under normal conditionsCan cause cascading pileup โ€” all blocked callers cascade
Fail fastThrow error immediatelyGraceful degradation; lets caller circuit-break upstreamDrops legitimate requests under brief spikes
Timeout + retryWait up to N ms, then failBalanced โ€” absorbs brief waits without cascadingTuning window is narrow (too long = cascade; too short = false fail)

Bulkhead

Isolating system resources into isolated pools so a failure in one pool does not cascade to others โ€” named after the watertight compartments (bulkheads) on a ship:

Isolation levelHow it worksHA StrengthsHA Weaknesses
Thread pool isolationEach downstream dependency gets its own thread pool (e.g. Hystrix thread pools)One slow or hung downstream cannot exhaust all threads in the service; failure is contained per poolHigher overhead from context switching; thread pool sizing must be tuned per dependency
Semaphore isolationCaps the number of concurrent callers via a semaphore instead of a separate thread pool (e.g. Resilience4j semaphore bulkhead)Lower overhead than thread pool isolation; no thread context switching; blocks the calling thread only up to the semaphore limitNo built-in timeout โ€” a blocked caller stays blocked until a permit is acquired unless a separate timing mechanism is added; cannot interrupt a running operation
Connection pool isolationSeparate connection pools per downstream or per workload classConnection exhaustion in one pool does not block other dependenciesMore total connections needed; per-pool sizing must account for peak load independently
Process / container isolationEach service or workload runs in its own process or containerA crash, OOM or memory leak in one does not affect othersHigher resource overhead per process; inter-process communication latency
Cellular / shard isolationEach shard or cell is independent with its own resources (compute + storage)Complete blast radius containment โ€” one cell failure cannot affect others; independent deployments per cellNo cross-cell resource sharing; warm standby needed per cell for failover
Tenant / consumer-based isolationPools partitioned by caller identity (premium vs free tier, per-tenant) rather than by downstream dependencyA flood of low-priority requests cannot starve high-priority callers because each tenant draws from its own isolated poolHarder to size per-tenant pools without tenant-level traffic data; many small pools increase total resource overhead

Sources: Building Microservices by Sam Newman (Ch. 7); Site Reliability Engineering by Beyer et al. (Ch. 22)


Retry Logic Patterns

PatternBehaviourHA StrengthsHA Weaknesses
Simple retryFixed N retries immediatelySimple to implementCan amplify load on an already-stressed backend
Exponential backoffIncreasing delay between retriesReduces pressure on recovering backendClients may time out before backoff completes
Exponential backoff + jitterAdds randomness to delayPrevents thundering herd โ€” retries from all clients do not syncSlightly higher latency on the unlucky long-drawn retry
Circuit breakerStop retrying after threshold, probe periodicallyProtects backend from cascading failureFalse trip if threshold is too tight
Retry budgetLimit total retries across all requestsPrevents system-wide overload from aggregate retriesHard to tune โ€” too conservative leaves retries unused
Idempotency keyUnique key so retries do not produce duplicatesSafe to retry indefinitely without side effectsRequires application-level deduplication logic

Sources: Site Reliability Engineering by Beyer et al. (Ch. 22); Designing Data-Intensive Applications by Martin Kleppmann (Ch. 8)


Health Check Patterns

Probe type:

TypeWhat it detectsHA StrengthsHA Weaknesses
TCPPort is openFast, low overheadMisses app-level failures (process alive but pool exhausted)
HTTP endpoint/healthz returns 200Catches application failuresLogic in the handler; a slow DB can cascade and falsely trip it
gRPC health protocolStandard gRPC health serviceLanguage-agnostic, streamingOnly works for gRPC backends
Command / scriptExit code of inside-container scriptFlexible, can check anythingHigher overhead; shell dependency

Check depth:

CheckBehaviourHA StrengthsHA Weaknesses
LivenessIs the process alive? Restart if deadRecovers from hangs and deadlocksToo aggressive can restart a healthy-but-slow instance
ReadinessIs it ready to serve? Remove from LB if notDrains traffic from degraded instancesMisconfigured dependency check removes all nodes in cascade
StartupHas init completed? Delays liveness during bootPrevents premature restarts during slow startupAdds boot latency; if too short, defeats the purpose
ShallowQuick self-check onlyFast, cheapMisses dependency failures
DeepChecks dependencies (DB, cache, downstream)Catches transitive failuresA downstream blip can falsely remove a perfectly healthy instance

Aggregation:

PatternBehaviourHA StrengthsHA Weaknesses
Single /healthzOne endpoint for everythingSimple, easy to wireA degraded cache removes the entire node
Separate endpoints/live, /ready, /db, /cacheGranular โ€” decide what removes vs alertsMore endpoints to manage; orchestrators need multiple probes

Direction:

PatternBehaviourHA StrengthsHA Weaknesses
Pull (LB polls)Load balancer polls each targetLB controls check rate; no registration neededInactive instances not discovered until next poll cycle
Push (self-register)Instance registers with service registryInstant registration; registry holds stateRegistry is itself a SPOF; health becomes stale between re-registrations

Sources: Kubernetes in Action by Marko Lukลกa (Ch. 8); Site Reliability Engineering by Beyer et al. (Ch. 20)


Traffic Shifting Patterns

PatternMechanismAWS SupportHA StrengthsHA Weaknesses
Canary (weighted)Route X% to new version, increase graduallyRoute 53 weighted, ALB weighted target groups, CodeDeployGradual exposure; zero-weight rollbackNeeds metrics comparison; statistical noise can mislead
Header / cookieRoute specific users via header matchALB rule-based routing, CloudFront + Lambda@EdgeZero impact on production usersOnly tests the paths matched users exercise
Blue/greenSwap whole target pool behind LBCodeDeploy, ECS blue/green, ALB target group swapInstant rollback (revert pool swap)All-or-nothing; double capacity during cutover
Geographic / latencyShift DNS weights per regionRoute 53 geolocation, latency, geoproximityIsolates blast radius by regionSlow DNS propagation; coarse-grained control
GSLB percentageGradually shift DNS resolution %Route 53 weighted routingMulti-region failover testingDNS TTL delays each step takes minutes
Shadow / mirrorDuplicate live requests to new version silentlyAPI Gateway stage mirroring, VPC Traffic MirroringZero user impact; validates latency + correctnessBackend must handle and discard mirrored requests separately
A/B splitCanary with session persistenceALB weighted + sticky sessionsUser-consistent experience during shiftSticky sessions complicate draining old sessions

Cross-cutting rule: Never shift more traffic than you can absorb if the new version fails. Stage the rollback before the shift starts.

Sources: Continuous Delivery by Humble & Farley (Ch. 10); The DevOps Handbook by Kim et al. (Ch. 13)


TTL Management Patterns

PatternBehaviourHA StrengthsHA Weaknesses
Low TTL (30โ€“300s)DNS records expire quicklyFast failover โ€” clients pick up new IPs in secondsHigh query volume; higher cost (Route 53 charges per query)
High TTL (300โ€“86400s)DNS records cached for long periodsLow query volume; stable caching; cheaperSlow failover โ€” stale clients hit dead IPs for minutes to hours
Client-side re-resolutionApp re-resolves DNS at a shorter interval than the TTLBreak glass for critical services โ€” bypass DNS cacheNon-standard; adds application complexity

Disaster Recovery Strategies

DR strategies trade off recovery speed against cost. Each has different RTO and RPO characteristics:

StrategyRPORTOCostHA StrengthsHA Weaknesses
Backup & RestoreHoursHoursLowSimple, cheap, well-understoodHighest RTO/RPO; data loss window measured in hours
Pilot LightMinutesTens of minutesMediumCore data always current; compute provisioned on failoverCompute cold start; may need manual scaling decisions
Warm StandbySecondsMinutesMedium-HighFully functional scaled-down environment; fast scale-upDouble base infra cost at reduced capacity; not instant
Active-Passive (standby)Near-zeroSeconds to minutesHighInstant traffic switch; full capacity readyDouble full infra cost; idle resources in standby region
Active-Active (multi-region)Near-zeroNear-zeroVery HighNo failover delay; all capacity utilised; no idle wasteHighest complexity; conflict resolution for concurrent writes

Sources: Site Reliability Engineering by Beyer et al. (Ch. 29); AWS Well-Architected Framework Reliability Pillar


Auto-scaling Strategies

Auto-scaling ensures enough compute capacity is available to handle traffic without over-provisioning:

StrategyMechanismHA StrengthsHA Weaknesses
Target trackingScale on a single metric threshold (e.g. CPU at 70%)Simple to configure; AWS-managed; predictableReacts to load after it arrives โ€” no anticipation
Step scalingScale by defined increments per alarm severity levelGranular control; faster response for large swingsComplex to tune multiple thresholds; can oscillate
Predictive scalingML-based forecast of future load from historical patternsAnticipates demand before it arrives; reduces cold startRequires stable historical data; may over-provision for novel spikes
Scheduled scalingScale at known times (peak hours, marketing events, holiday sales)Zero reaction time; perfect for known patternsUseless for unexpected events; needs manual schedule maintenance
Dynamic (queue-based)Scale based on queue depth or backlog (SQS, Kinesis)Absorbs processing bursts; consumer-first scalingLag between queue growth and scale action; oscillation risk

Sources: Site Reliability Engineering by Beyer et al. (Ch. 20)


Rate Limiting / Throttling

Rate limiting protects backend services from resource exhaustion by rejecting excess requests:

StrategyHow it worksHA StrengthsHA Weaknesses
Token bucketBucket of N tokens refilled at R tokens/sec; each request consumes oneSimple, permits bursts up to bucket sizeGlobal bucket alone cannot isolate abusive clients
Leaky bucketRequest queue drained at fixed rate; excess spillsSmooths traffic to a predictable rateDrops bursts entirely; no flexibility for brief spikes
Fixed windowCount requests per time window (e.g. 100/min), reset at boundaryVery simple to implement; low memoryTraffic spike at window boundary can double throughput momentarily
Sliding windowRolling time window with sub-second granularityMore accurate rate enforcement; no boundary spikeHigher memory and computation per client
Per-client vs globalSeparate counters per API key/user or one shared counterPer-client prevents noisy neighbours from starving othersGlobal is simpler but allows one client to exhaust shared capacity
Adaptive (concurrency-limited)Limit based on backend capacity using Little’s LawProtects backend regardless of request rate patternRequires real-time saturation or latency signal from backend

Sources: Building Microservices by Sam Newman (Ch. 7); Site Reliability Engineering by Beyer et al. (Ch. 21)


Backpressure / Load Shedding

When the system cannot keep up with demand, backpressure mechanisms slow intake or shed load rather than degrading unpredictably:

PatternHow it worksHA StrengthsHA Weaknesses
Admission controlReject requests before they enter the service (at LB or API gateway)Preserves remaining capacity for in-flight workRejects legitimate requests that could have been queued
Queue depth limitsCap the internal work queue; reject when fullBounded latency; predictable degradation under loadNeed to size the cap correctly โ€” too small rejects unnecessarily
Priority queuingClassify requests by priority; process high-priority firstCritical path preserved under loadLow-priority requests may starve indefinitely
Graceful rejection (503 + Retry-After)Return 503 with a Retry-After headerClient can back off intelligently; reduces retry stormsRequires client cooperation โ€” non-compliant clients ignore the header
Load shedding by percentageDrop X% of all traffic at the edge (ALB rule or feature flag)Quick to activate; easy to undo; tested in advanceBlunt instrument; drops good traffic along with bad

Sources: Site Reliability Engineering by Beyer et al. (Ch. 21); Building Microservices by Sam Newman (Ch. 7)


Timeout Patterns

Timeouts prevent a single slow dependency from consuming resources indefinitely:

TypeWhat it setsHA StrengthsHA Weaknesses
Connection timeoutMax time to establish TCP/TLS handshakeCatches network failures fast; frees resources quicklyToo low causes false failures on flaky but functional networks
Read timeoutMax time to receive the complete response bodyPrevents a slow downstream from holding a thread/connection indefinitelyToo high delays detection; too low causes unnecessary retries
Write timeoutMax time to send the request bodyProtects against slow upstream ingestionRarely the bottleneck in practice
Deadline propagationPass the remaining timeout budget to downstream callsCoherent end-to-end timeout โ€” no downstream outlives the callerComplex to implement; clock skew between services can misalign budgets
Per-dependency timeoutIndependent timeout for each downstream service callIsolates failures โ€” one slow dependency cannot cascade to othersRequires configuration per dependency; more surface for misconfiguration
Per-request timeoutSingle timeout for the entire request end-to-endSimple; guaranteed total latency boundA brief hiccup in one dependency exhausts the whole timeout budget

Sources: Site Reliability Engineering by Beyer et al. (Ch. 22); Designing Data-Intensive Applications by Martin Kleppmann (Ch. 8)


Service Discovery

Service discovery lets clients find healthy instances of a dependency without hard-coding addresses:

PatternHow it worksHA StrengthsHA Weaknesses
Client-sideClient queries a service registry and load-balances locallyNo extra network hop; client controls retry and balancingRegistry is a SPOF; each language needs its own discovery library
Server-side (LB)Load balancer or API gateway handles discovery and routingCentralised; clients are simple HTTP callersExtra network hop; LB itself must be highly available
DNS-basedDNS returns multiple A records for healthy instances (round-robin)Simple, battle-tested, no additional infrastructureSlow propagation; TTL delays failover; limited health granularity
Registry-based (Consul, etcd, Zookeeper)Dedicated service registry with health checkingRich health metadata; fast updates; watch-based change notificationRegistry cluster is itself a complex distributed system to operate
Service mesh (sidecar proxy)Sidecar proxy intercepts all outbound traffic and handles discoveryApp-agnostic; language-independent; rich telemetryAdded latency per hop; significant operational overhead for mesh control plane

Sources: Building Microservices by Sam Newman (Ch. 8); Kubernetes in Action by Marko Lukลกa (Ch. 5)


Chaos Engineering

Chaos engineering validates that a system withstands unexpected failures by injecting faults in a controlled manner:

PatternWhat it testsHA StrengthsHA Weaknesses
Fault injectionInject specific failure (kill pod, block port, terminate instance)Validates a specific resilience mechanism end-to-endNarrow scope โ€” only tests the injected failure mode
Latency injectionAdd delay to downstream calls (e.g. +500ms on DB queries)Tests timeout and retry behaviour; validates circuit breaker thresholdsCan trigger false alarms if monitoring is too sensitive
Resource exhaustionSaturate CPU, memory, disk, or file descriptorsValidates throttling, auto-scaling, and OOM handlingRisk of real cascading failure if blast radius is not contained
Game daysFull scenario simulation with ops team respondingBuilds team muscle memory; exposes runbook and tooling gapsDisruptive; requires cross-team scheduling and stakeholder buy-in
Blast radius controlKeep experiments within bounded scope (one AZ, one cell, one service)Contains damage; safe to run in production-like environmentsMay not test cross-cell or cross-region failure propagation

Sources: Chaos Engineering by Casey Rosenthal & Nora Jones; Site Reliability Engineering by Beyer et al. (Ch. 27)


Supervisor / Watchdog

A monitoring process that detects failures in a worker process and restarts it or triggers escalation:

PatternHow it worksHA StrengthsHA Weaknesses
Process supervisor (Erlang OTP, systemd, supervisord)Parent process monitors child; restarts it on crash or hangFast local restart; no external dependency; battle-tested in Erlang/ElixirDoes not protect against infrastructure-level failures (host, network, AZ)
Kuberentes ReplicaSet / DeploymentController ensures N replicas are running; replaces terminated podsDeclarative; self-healing across nodes; integrates with readiness and liveness probesRestart takes seconds (pull image, init); does not handle stateful failures (corrupted data)
Sidecar health proxy (Envoy, Istio sidecar)Sidecar monitors the application process and reports health to the control planeLanguage-agnostic; integrates with service mesh observabilityAdds latency for health check proxying; sidecar can become a SPOF for the pod
External watchdog (separate monitoring system)Out-of-process system (e.g. Prometheus + Alertmanager, Datadog) that alerts when a process is unreachableIndependent of the monitored process; can trigger escalations and page humansDetection latency includes scrape interval + alert evaluation time

Sources: Kuberentes in Action by Marko Lukลกa (Ch. 8); Site Reliability Engineering by Beyer et al. (Ch. 11)


Saga / Compensating Transactions

Sagas manage data consistency across multiple services without distributed transactions. Each step has a compensating action to undo it:

PatternHow it worksHA StrengthsHA Weaknesses
ChoreographyEach service emits events; the next service reacts to the eventNo central coordinator; simple topology; no SPOFHard to trace the full workflow; no central view of state
OrchestrationCentral coordinator calls each service in sequence and manages stateTraceable; compensatable on failure; central state trackingCoordinator is a SPOF and a potential bottleneck
Backward recoveryCompensating actions undo completed steps on failureEventual consistency with full rollback capabilityCompensations may fail themselves, requiring manual intervention
Forward recoveryRetry or continue from the failure point without rolling backNo rollback needed; can complete if the failure is transientMay leave partially-committed data in an inconsistent state

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 9); Microservices Patterns by Chris Richardson (Ch. 4)


Feature Flags / Toggles

Feature flags separate deployment from release, enabling instant kill-switches, gradual rollouts, and operational flexibility:

TypePurposeHA StrengthsHA Weaknesses
Release toggleGate new features behind a flag; enable when readySeparate deploy from release; instant kill-switch without rollbackFlag debt โ€” stale flags accumulate and increase code complexity
Ops toggleControl operational behaviour (disable caching, enable debug logging)Emergency lever for operational issues; no code deploy neededMust be tested pre-production; can cause surprise behaviour if toggled live
Experiment toggleA/B test or canary release with percentage-based exposureGradual rollout with data-driven go/no-go decisionsStatistical noise can mislead; needs careful metric design
Permission toggleEnable features for specific users, tenants, or rolesTargeted rollouts; tenant isolation; staged enterprise rolloutsComplexity grows with permission matrix size
Kill switchEmergency disable of a non-critical feature under loadLast line of defence before full outage; proven in game daysMust be pre-built and tested; useless if created during the incident

Sources: Continuous Delivery by Humble & Farley (Ch. 14); The DevOps Handbook by Kim et al. (Ch. 14)


Circuit Breaker

Prevent cascading failures by failing fast when a downstream service is unhealthy, then probing periodically for recovery:

Circuit breaker states:

StateBehaviourHA StrengthsHA Weaknesses
ClosedNormal operation; all calls pass throughZero overhead when healthyNo protection until failure threshold is reached
OpenCalls fail immediately without reaching downstreamProtects downstream from cascading failure; gives it time to recoverRejects all calls even if the downstream has already recovered
Half-openLimited probe requests pass through to test recoveryEnables automatic recovery without full exposureMay overload a still-recovering downstream if probe count is too high

Configuration dimensions:

DimensionOptionsHA StrengthsHA Weaknesses
Failure thresholdCount or percentage over a time windowCount is simpler; percentage adapts to varying traffic volumePercentage requires more events to trigger; count can false-trip on brief spikes
Cooldown / sleep windowDuration before transitioning from open to half-openShorter = faster recovery; longer = more protection for the downstreamToo short risks repeated failures; too long delays availability unnecessarily
Probe countNumber of successful probes required to close the breakerHigher = more confidence in recovery; lower = faster restoration of normal operationToo few probes may miss intermittent failures; too many delays service restoration
Per-dependency vs sharedOne breaker per downstream vs a single breaker for all downstream callsPer-dependency isolates failures precisely; shared is simpler to configureGlobal breaker means one slow dependency opens the breaker for all downstream calls

Sources: Site Reliability Engineering by Beyer et al. (Ch. 22); Building Microservices by Sam Newman (Ch. 7); Microservices Patterns by Chris Richardson (Ch. 4)


Graceful Degradation / Fallback

When a dependency fails or degrades, the system continues operating at reduced functionality rather than failing entirely:

StrategyHow it worksHA StrengthsHA Weaknesses
Stale data fallbackReturn the last cached value when the primary data source is unavailableUsers see something meaningful rather than an error; buys time for recoveryStale data may be incorrect for time-sensitive operations
Functional degradationDisable non-critical features while keeping critical paths workingPreserves core user experience under partial failureUsers may be confused by partial functionality; needs clear UI signalling
Default value fallbackReturn a safe default when the real value cannot be fetchedSimple to implement; fastDefault may be wrong for the specific request context
Null object / no-opReturn an empty result or no-op instead of throwing an errorCaller does not need to handle the error path; clean semanticsHides real failures from monitoring; delays detection
Prioritised degradationDrop lower-priority requests first as resources become scarcePreserves SLOs for the most critical trafficRequires classification of all request types by priority

Sources: Building Microservices by Sam Newman (Ch. 7); Site Reliability Engineering by Beyer et al. (Ch. 22)


API Gateway / Backend for Frontend (BFF)

A single entry point for client requests that handles cross-cutting concerns, reducing round-trips and centralizing HA policy enforcement:

PatternHow it worksHA StrengthsHA Weaknesses
Single API GatewayOne gateway for all clientsCentralized auth, rate limiting, routing; single place to enforce HA policiesSPOF if not deployed with HA (multi-AZ, multiple replicas); can become a throughput bottleneck
Backend for Frontend (BFF)Dedicated gateway per client type (web, mobile, IoT)Client-specific optimizations; failure in one BFF does not affect other client typesMore infrastructure to manage; duplicated cross-cutting configuration across BFFs
Gateway AggregationGateway aggregates responses from multiple downstream services for a single client callReduces client round-trips; hides internal service topology from clientsGateway becomes a chatty orchestrator; increased latency per aggregated request
Gateway OffloadingGateway handles TLS termination, compression, caching on behalf of servicesReduces per-service CPU for TLS; consistent compression and caching across all servicesGateway must be provisioned for CPU-intensive TLS termination

Sources: Building Microservices by Sam Newman (Ch. 8); Microservices Patterns by Chris Richardson (Ch. 8)


CQRS (Command Query Responsibility Segregation)

Separating read and write data models so each can be optimized independently for its workload:

PatternHow it worksHA StrengthsHA Weaknesses
Separate read/write storesWrite model uses normalized OLTP store; read model uses denormalized views or search indexesRead path can remain available even if write path fails; independent scaling on each sideEventual consistency between write and read; read model can lag behind writes
Separate read/write servicesDistinct services for commands (writes) and queries (reads)Write service can degrade without affecting reads; independent deployment and scalingDuplicated business logic across services; read model must be rebuilt on schema changes
Materialized viewsPre-computed read models updated asynchronously from the write modelFast reads; no expensive joins at query timeStale data until the view is refreshed; storage grows with the number of views
Separate read replicasRead-only database replicas serving query trafficSimple to implement; strong consistency with sync replicas or low latency with asyncReplica lag under high write throughput; writes still bottlenecked on the primary

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 11); Microservices Patterns by Chris Richardson (Ch. 11)


Transactional Outbox

Ensures reliable message or event publishing by writing the message to the same database as the business data within the same transaction, eliminating the need for distributed transactions:

StrategyHow it worksHA StrengthsHA Weaknesses
Polling publisherSeparate process polls the outbox table for unprocessed messages and publishes themSimple to implement; no additional infrastructure beyond the databasePolling latency between write and publish; risk of duplicated delivery (at-least-once semantics)
Transactional log tailing (CDC)Read from the database’s commit log via CDC tooling (Debezium, AWS DMS)Near-real-time delivery; no table contention between writers and publisherRequires CDC infrastructure and operational expertise; schema changes must be handled carefully
Outbox table with TTLWrite message to outbox; publish via background worker; clean up processed records via TTLControlled retry semantics; visibility into pending messages and failuresTable can grow under high volume if publishing stalls; needs cleanup process
Saga + outbox combinedOutbox entries feed into a saga coordinator for multi-step workflowsReliable saga step execution with full traceability; supports compensationHigher complexity โ€” outbox publishing and saga coordination must be managed together

Sources: Microservices Patterns by Chris Richardson (Ch. 7); Designing Data-Intensive Applications by Martin Kleppmann (Ch. 11)


Dead Letter Queue (DLQ)

A holding area for messages or events that cannot be processed successfully after repeated retries:

StrategyHow it worksHA StrengthsHA Weaknesses
Simple DLQFailed messages moved to a separate queue after max retries exhaustedProtects the main queue from poison-pill messages; preserves message order in the main queueDLQ is a dead end without monitoring; messages sit there unless manually re-driven
DLQ with alertingDLQ message arrival triggers an alert or incidentEnsures human attention on processing failures before data loss accumulatesAlert fatigue if retry policy is too lenient and DLQ fills frequently
DLQ with replayDLQ messages can be re-driven to the main queue after the root cause is fixedZero data loss for poison-pill messages; enables post-mortem analysis and replayRe-driven messages may arrive out of order; may cause duplicate processing downstream
DLQ with TTL + archivalDLQ messages expire after a TTL and are archived to object storageBounded DLQ storage; audit trail for all failed messagesArchived messages require a separate retrieval process for replay

Sources: Building Event-Driven Microservices by Adam Bellemare (Ch. 6); AWS Well-Architected Framework Reliability Pillar


Event Sourcing

Storing the full sequence of state-changing events as the authoritative source of truth rather than only the current state:

StrategyHow it worksHA StrengthsHA Weaknesses
Full event logAppend-only log of every state change; current state is derived by replaying eventsComplete audit trail; can rebuild state from any point in time; zero data lossReplay can be slow for high-volume entities; storage grows unboundedly
Snapshot + event logPeriodic snapshots of current state; replay from the last snapshot on recoveryFaster recovery than full replay; bounded replay timeSnapshot management adds complexity; stale snapshots waste storage
Projection / read modelSeparate read models built asynchronously from the event stream (often used with CQRS)Read path can be optimized independently; projections can be rebuilt from the log if corruptedProjections lag behind the event log; eventual consistency between write and read
Temporal versioningEvery event carries a timestamp and version, enabling time-travel queriesFull historical visibility; supports point-in-time reconstruction for audit and debuggingComplex query model; storage and indexing overhead for version metadata

Sources: Designing Data-Intensive Applications by Martin Kleppmann (Ch. 11); Microservices Patterns by Chris Richardson (Ch. 10)


This reference is part of the High Availability series.

Share :
comments powered by Disqus

Related Posts

System Design Principles and Concepts

System design is a critical aspect of software engineering that involves creating scalable, reliable and efficient systems.

Read More

High Availability

Designing highly available microservices on AWS using multi-AZ deployment, stateless services, circuit breakers and chaos engineering.

Read More

Practising System Design - Youtube

Practical approach to System Design interviews, followed by a deep-dive into designing a scalable video platform like Youtube.

Read More