Specific Technologies8 min · 53 of 64

Cloud Platforms

Map generic components onto AWS, GCP and Azure equivalents, then argue the trade-off a managed service makes: failover time, connection limits, lock-in.

Every design in this course is drawn in generic components: a load balancer, a cache, a queue, an object store. On a cloud platform each has a managed equivalent with a brand name, a bill, and limits that become your constraints. An L5 interview asks you to name a relevant service, say what it does for you, and say what it takes away.

The mapping

The categories transfer and only the names change, so one provider is enough to learn: the second costs a lookup, not a redesign. What does not transfer is what sits inside a row — a delivery guarantee, a failover time, a connection ceiling.

Generic components and their managed equivalents on AWS, GCP and Azure.
Generic components and their managed equivalents on AWS, GCP and AzurecomponentAWSGCPAzureLoad balancerALB / NLBCloud Load BalancingAzure Load BalancerRelational databaseRDS · AuroraCloud SQLAzure DatabaseCacheElastiCacheMemorystoreAzure Cache for RedisQueue / streamSQS · KinesisPub/SubService Bus · Event HubsObject storageS3Cloud StorageBlob StorageContainersEKSGKEAKSSay the component in the interview; name the product only if asked. The trade-offs live in the component.

Scroll to zoom · drag to pan · 0 fits · Esc closes

CategoryAWSGCPAzure
Compute (VMs)EC2Compute EngineVirtual Machines
ContainersECS / EKSGKEAKS
Serverless computeLambdaCloud Run functions (was Cloud Functions)Azure Functions
Object storageS3Cloud StorageBlob Storage
Relational DBRDS / AuroraCloud SQLAzure SQL Database
NoSQL (key-value)DynamoDBFirestore / BigtableCosmos DB
In-memory cacheElastiCacheMemorystoreAzure Cache for Redis
Load balancingELB (ALB, NLB)Cloud Load BalancingAzure Load Balancer
Message queueSQSPub/SubService Bus
Streaming logKinesis Data StreamsPub/Sub / Pub/Sub LiteEvent Hubs
Stream processingManaged Service for Apache FlinkDataflowStream Analytics
API gatewayAPI GatewayAPI Gateway / ApigeeAPI Management
CDNCloudFrontCloud CDNAzure CDN
DNSRoute 53Cloud DNSAzure DNS
Identity / authIAM / CognitoCloud Identity / IAMMicrosoft Entra ID (was Azure AD)
Key managementKMSCloud KMSKey Vault

Two of those rows get read wrong. A streaming log is replayable transport; Dataflow, Flink and Stream Analytics are engines that run your code over it, so GCP's answer to Kinesis Data Streams is Pub/Sub, not Dataflow. Pub/Sub then appears twice because one product covers both jobs: forget-on-acknowledgement or rewindable log is a retention setting there, where on AWS it is SQS versus Kinesis and on Azure Service Bus versus Event Hubs — Kafka versus RabbitMQ wearing a vendor's name, which the table does not decide for you.

What "managed" buys, and what it costs

Take the relational row. A managed database sets up replication, retains backups, patches, and fails over without you writing the runbook. It removes control: no superuser, only the extensions on the provider's allowlist, major-version upgrades on their calendar, no tuning below the parameter groups they expose. The failure mode is late discovery — a design that assumed a particular extension or replication topology meets a platform that refuses it, after the schema is written.

Running it yourself on VMs is cheaper per instance-hour and every knob is yours, but that cost is not one-time: failover has to be rehearsed to be trusted, and a backup never restored is a guess. On a team with no database on-call rotation that work quietly does not happen, and the gap surfaces during the first incident.

Failover is not free

"We'll use a multi-AZ managed database" gets offered as an availability answer. By itself it is not one: promoting the standby and cutting the endpoint over takes 60–120 seconds, and writes fail throughout.

Put that against the budget. 99.9% availability is about 43 minutes of downtime a month; 99.99% is 4.3 minutes, or 258 seconds. One 90-second failover spends a third of a four-nines month, two spend two-thirds, and a maintenance window can trigger one on its own. Four nines behind a single leader is arithmetic that does not close.

What closes it is taking the failover off the request path: clients retry with backoff, reads come from a follower that never went down, and writes buffer in a queue for the ~90 seconds the leader is absent. The reads have a price — a follower lags, so read-your-writes breaks and a user watches an update they just made disappear from the next page load. That trade is the substance of redundancy; the managed service only automates its mechanics.

Zones are cheap, regions are not

An availability zone is a separate failure domain in the same metro, a 0.5 ms round trip away. Three app instances across three zones cost well under a millisecond per hop and buy independence from one building losing power. Take it by default.

A region hop is a different order of magnitude. India to US East is roughly 200 ms round trip, so three sequential cross-region queries spend 3 × 200 ms = 600 ms on the wire before a single query executes — three times a 200 ms p99 budget, with nothing left for the work. Multi-region is a durability and disaster-recovery decision, not a latency one; the exception is static bytes, which a CDN moves close to the user by relocating the response, not the query.

The service limits are the design

Managed services fail in ways that come from their limits, not from your code.

Little's Law sets the fan-out, max_connections sets the wall. The database is not slow, it is out of slots.
500 QPS at 200 ms keeps about 100 serverless instances alive, each holding one database connection, against a Postgres max_connections near 100; a connection proxy multiplexes the same load onto about ten server connectionsrequests100 clientconnections≈ 10 serverconnections100 direct connections: at the wall500 QPS200 ms per callServerlessinstances≈ 100 alive · 500 ×0.2 sConnection proxyPgBouncer · RDS ProxyPostgresmax_connections ≈100Concurrency = arrival rate × time in system = 500 × 0.2 s = 100 instances, one connectioneach. That equals the default limit, so the next scale-up fails on "too many connections",not on CPU. The proxy holds the 100 client sockets and shares ten real ones.

Scroll to zoom · drag to pan · 0 fits · Esc closes

Serverless in front of a relational database. 500 QPS × 200 ms = 100 requests in flight, so about 100 function instances, each its own process holding its own connection — ~100 connections at steady state and more at peak, against a default max_connections near 100. The database does not get slower, it refuses to connect, so the symptom is a wall of errors rather than rising latency. And 500 QPS is far under the ~5,000 simple QPS a commodity Postgres box serves: the bottleneck is the connection model, not the database. The fix is a proxy that multiplexes many client connections onto few server ones, or long-lived containers sharing a pool. The general form is Little's Law.

Managed queues. The standard tiers of SQS and Pub/Sub are at-least-once. A consumer that holds a message past its lease — the visibility timeout on SQS, the acknowledgement deadline on Pub/Sub, extended with modifyAckDeadline — gets a second copy while still working on the first. At-least-once means duplicates, and duplicates mean the consumer must be idempotent: a deduplication key, or a write safe to repeat. That is a property of the service you picked, not an edge case you can defer.

Lock-in is priced by distance to your data model

Managed compute and networking are cheap to leave: containers and load balancers have near-equivalents everywhere, and the migration is configuration. Managed data stores are not. Moving off DynamoDB, Firestore or Cosmos DB means rewriting access patterns, because the data model — partition keys, single-table layouts, the queries the engine will and will not serve — was designed around that engine. Not an argument against choosing one, only for knowing which decision you are making.

In an interview

What is tested is whether you can turn an abstract box into an operable system, and whether you know the constraint that comes attached.

Name the service, then immediately name what it does for you: "a managed relational database like RDS, so replication, backups and patching are the provider's problem — and I accept a 60 to 120 second failover, which is why the client retries and reads come off a follower." That second clause is the whole signal.

The mistake that loses points is reciting service names instead of designing. ALB to EC2 to RDS to ElastiCache to S3, with no numbers and no limit acknowledged, is a shopping list; it collapses the moment the interviewer asks why an ALB rather than an NLB, or what happens to in-flight writes during failover. A candidate who says "a managed layer-7 load balancer, so it routes by path and terminates TLS" outscores one who says ALB and cannot say why.

Check yourself

1. Your SLO is 99.99% and your only stateful component is a managed database whose failover takes 90 seconds. How many failovers a month can you absorb, and what does that force?

258 seconds a month ÷ 90 ≈ 2.8, so fewer than three — and that assumes nothing else ever fails. One maintenance window can trigger a failover on its own, so the database alone would spend most of the budget. Either state 99.9% instead (43 minutes, where 90 seconds is noise), or take the failover off the request path with retries, follower reads and buffered writes. A multi-AZ service is not by itself an availability answer.

2. Your p99 budget is 200 ms, the service runs in Mumbai, the team wants one relational leader in us-east-1, and a request makes three sequential queries. Does it fit?

No. India to US East is ~200 ms round trip, so three sequential queries cost 600 ms of network alone — three times the budget, before any work; the same three in-region cost about 1.5 ms. Either the leader moves to Mumbai, or Mumbai gets a follower and serves reads from it, accepting that replication lag breaks read-your-writes. Writes still pay the 200 ms, a product decision to state out loud.

3. 500 QPS hits a serverless function calling a managed Postgres at 200 ms per call. How many database connections does it need, and is the database the problem?

500 × 0.2 s = 100 concurrent invocations, each holding its own connection: ~100 at steady state and more at peak, against a default max_connections near 100 — refused connections, errors rather than slowness. The database is fine at 500 QPS, an order of magnitude under the ~5,000 simple QPS a commodity Postgres box serves. The constraint is the connection model, so the fix is a multiplexing proxy or containers sharing a pool, not a bigger instance.