All Posts
18 Jun 202516 min readAdvanced

Designing a Highly Available API Platform

Part of AWS

  • AWS
  • System Design
  • APIs

Highly available does not mean nothing ever breaks. It means when something breaks, users still get served within your SLO. For an API platform that means designing for failure at every layer: AZ loss, bad deploy, dependency timeout, and traffic spikes.

At Edmingle our API tier sits behind AWS ALB, runs on Kubernetes across multiple AZs, talks to MySQL primary/replica, Redis for cache and streams, and several internal services. This post is how I think about HA as explicit failure modes with mitigations-not as a checkbox on an architecture slide.

Define Availability in Numbers

99.9% allows ~43 minutes downtime per month. 99.95% allows ~22 minutes. Pick a target per tier: auth and payments tighter than internal admin APIs.

Measure availability from the client perspective (synthetic checks + real traffic success rate), not just pod Running status. A pod can be Running and useless if readiness is wrong.

Multi-AZ Is the Baseline

Region: ap-south-1
├── AZ-a: ALB targets, EKS nodes, RDS subnet
├── AZ-b: ALB targets, EKS nodes, RDS subnet
└── AZ-c: ALB targets, EKS nodes, RDS subnet

Single AZ loss → reduced capacity, not total outage

Spread Pod replicas with topologySpreadConstraints or pod anti-affinity. ALB health checks should hit endpoints that validate critical dependencies lightly-not a deep DB query on every probe.

Failure Matrix

Every HA design should be a table you can walk through in a review.

FailureImpactMitigationResidual risk
Single pod crashMinimal if replicas > 1Deployment replicas, restart policyBrief error blip during rollout
AZ outageCapacity drop ~33%Multi-AZ nodes + PDB + over-provisionLatency spike if not enough headroom
Bad deployErrors or latency on new versionRolling update + readiness + quick rollbackBad config passes probes
Primary DB failureWrite outageRDS Multi-AZ failover (~60-120s)In-flight transactions fail
Replica lag spikeStale readsRoute critical reads to primaryPrimary load increase
Redis unavailableCache miss stormGraceful degrade, circuit breakerDB load spike
Downstream API downFeature degradationTimeouts, fallbacks, async queuePartial functionality loss
Region lossTotal outageDR region (cold/warm), DNS failoverRTO/RPO trade-offs

Load Balancing and Health

ALB with cross-zone load balancing. Target type IP for pod direct routing on EKS. Deregistration delay aligned with connection draining.

Readiness probe should match real traffic readiness: can the app serve requests without blocking on a cold cache warm-up? Liveness should be dumb-only restart if deadlocked.

readinessProbe:
  httpGet:
    path: /health/ready
    port: 8080
  periodSeconds: 5
  failureThreshold: 3
livenessProbe:
  httpGet:
    path: /health/live
    port: 8080
  periodSeconds: 10
  failureThreshold: 5

Data Layer HA

RDS Multi-AZ for automatic primary failover. Test failover quarterly-DNS and connection string behavior surprises teams who never practiced.

Redis: use ElastiCache with Multi-AZ and automatic failover for cluster mode or replica promotion. Treat cache as optional; never as source of truth.

For Redis Streams consumers at Edmingle, run consumer groups with enough workers and monitor pending message age-lag is an availability concern when events drive user-visible state.

Graceful Degradation

Not every dependency deserves hard failure. Return cached data, stub non-critical fields, or queue work for async processing when billing enrichment fails but core LMS read should succeed.

Feature flags let you disable expensive code paths under load without a full rollback.

Engineering Takeaways

  • HA is an SLO with measured client-side success-not 'we run three replicas.'
  • Multi-AZ across compute, load balancer, and database is table stakes for production APIs.
  • Maintain a failure matrix and game-day each row at least once a year.
  • Readiness probes must reflect real serving ability; liveness should not restart during slow dependency.
  • Cache and async patterns are availability tools when dependencies fail or lag.
  • Region-level DR is a business decision with explicit RTO/RPO-do not pretend multi-AZ covers it.

Trade-offs I Would Consider

Option: Active-passive DR region

  • Pros: Lower cost, simpler data replication story, clear failover procedure.
  • Cons: Higher RTO (hours), cold capacity, DR drills often neglected.

Option: Active-active multi-region

  • Pros: Lower RTO/RPO, geographic latency wins for global users.
  • Cons: Conflict resolution, data replication cost, operational complexity 3-5x.

What I Would Do in Production

Run synthetic canaries every minute from outside the VPC hitting critical API flows.

Keep N+2 capacity headroom in normal conditions so one AZ loss does not breach latency SLO.

Automate rollback on error rate or latency SLO burn during deploy window.

Document and rehearse RDS failover: app reconnect behavior, connection pool flush, expected error window.

Queue critical side effects (email, webhooks) so transient dependency failure does not lose work.

FAQ

Q: How many replicas minimum?

At least two across different AZs for stateless APIs. Three if you want rolling updates with zero capacity drop during one-replica surge.

Q: Is Kubernetes required for HA?

No. EC2 ASG + ALB achieves similar compute HA. K8s adds deploy velocity and standardized ops at complexity cost.

Q: What about DDoS?

AWS Shield, WAF rate limits, CloudFront for static-availability includes abuse scenarios. Separate from app HA but related in incidents.

Q: Should we use a service mesh for retries?

Retries can amplify load during outages. Prefer bounded retries with jitter in app code or mesh with strict budgets.

Q: How do we measure HA?

SLI: successful requests / total requests over rolling window. SLO: 99.9% monthly. Error budget drives release aggressiveness.