Filter concepts by levelShowing all levels.

AWS · Section 66

AWS Interview-Level Questions

Level
intermediate
Read
50 min
Concepts
6

Twenty-six questions that recur, and the shape of an answer that lands. The opening four test blast radius and identity: a Region contains zones, and the sentence that matters is what multi-AZ fails to contain — a bad deploy, a corrupted row, a deleted bucket, all of which reach the standby as fast as the good writes do. The networking four each have one precise answer, and vagueness comes from naming a service instead of the property: a subnet is public because of its route table, a NACL differs from a security group by being stateless, a NAT gateway reaches the internet where an endpoint avoids it, and the three front doors differ by what they may read in a request. The compute four are answered by elimination on execution model rather than preference, and the two Lambda questions turn on one formula — concurrency is requests per second times duration, which is why a slower dependency throttles a function whose traffic never changed. The data-store four are four different axes, and naming the axis is most of the answer: availability against read capacity, the storage layer, whether the access patterns are known before the table, and whether the data is allowed to disappear. The messaging three are about coupling rather than throughput, and the consumer is idempotent whichever queue type wins. The last seven are open scenarios, where a structured answer to one beats a service list for all of them — each has a fixed opening move, and using it is what makes the answer sound operated rather than read.

What is true here

  1. Give the definition in one sentence, then the consequence — the consequence is the question.
  2. Name the axis before comparing: availability, storage layer, known patterns, durability.
  3. Rule compute options out on execution model before comparing cost.
  4. Concurrency is rate times duration, which is why incidents cause throttling.
  5. Every scenario question has an opening move that narrows it before any service is named.

What you will be able to do

  • Answer the recurring AWS interview questions with a definition and its consequence
  • Give the precise answer to the four networking questions rather than a service name
  • Choose between compute models by elimination and defend the choice
  • Compare data stores on the axis the question is really about
  • Structure an open scenario answer around its constraint instead of a service list
Twenty-six questions, six things being tested
once identityis settledthe path, thenthe runtimethe runtime,then the storethe store, thenwhat connects themall of it, appliedunder a constraint

Blast radius and identity

4 questions — what multi-AZ fails to contain, and who may do what

One precise answer each

4 questions — the route table, statefulness, NAT vs endpoint, the front door

Execution models

4 questions — what rules an option out, and what concurrency counts

Four different axes

4 questions — availability, storage layer, known patterns, durability

Coupling, not throughput

3 questions — who waits, who knows whom, and surviving a duplicate

The opening move

7 questions — structure and a named constraint beat a service list

  • Blast radius and identity — 4 questions — what multi-AZ fails to contain, and who may do what
    • leads to One precise answer each (once identity is settled)
  • One precise answer each — 4 questions — the route table, statefulness, NAT vs endpoint, the front door
    • leads to Execution models (the path, then the runtime)
  • Execution models — 4 questions — what rules an option out, and what concurrency counts
    • leads to Four different axes (the runtime, then the store)
  • Four different axes — 4 questions — availability, storage layer, known patterns, durability
    • leads to Coupling, not throughput (the store, then what connects them)
  • Coupling, not throughput — 3 questions — who waits, who knows whom, and surviving a duplicate
    • leads to The opening move (all of it, applied under a constraint)
  • The opening move — 7 questions — structure and a named constraint beat a service list

AWS Interview-Level Questions

The twenty-six questions grouped by what each is testing, with the one-breath answer, the follow-up that separates people, and the trap that catches a memorised reply.

Foundations and Identity — Four Questions Every Interview Opens With

coreintermediate

The first four questions test whether you understand the failure boundary and the identity model. Region versus Availability Zone is really a question about what multi-AZ does and does not protect against. The three identity questions test whether you know that a role has no password, that an explicit deny always wins, and that a credential which expires cannot be leaked permanently.

Think of it as

Answer in two moves: the one-line definition, then the consequence. "A Region is a geographic area containing multiple Availability Zones" is a definition anyone can recite. "So multi-AZ survives a data centre and does not survive a bad deployment" is the sentence that shows you have operated something.

What we're doing: Answer "what does multi-AZ protect against?" the way an operator answers it.

answer.txttext
The definition, in one sentence:
  A Region is a geographic area — eu-west-1 — containing several
  Availability Zones. A zone is one or more discrete data centres
  with their own power, cooling and network, far enough apart to
  fail independently and close enough for synchronous replication.

What multi-AZ protects against:
  A zone-scoped event. A power failure, a network partition, a
  flood in one building. The load balancer stops sending traffic
  to the failed zone, the Auto Scaling group replaces capacity in
  the surviving one, and RDS promotes the standby. The user sees
  a short error window rather than an outage.

What it does not protect against, and this is the real question:
  A bad deployment      → ships to every zone at once
  A corrupted write     → replicates to the standby immediately
  A deleted bucket      → deletion is not a zone-scoped event
  An exhausted quota    → the quota is Regional, not zonal
  A Region-wide event   → needs another Region, not another zone
  A dependency outage   → your zones are fine; the dependency is not

So multi-AZ is the baseline for infrastructure failure and does
nothing for the four failure classes that actually cause most
incidents. Those need rollback, restore, quota alarms and
degradation — which is why the answer to "are we highly
available?" is never a single zone count.
1
Lead with the definition, but keep it to one sentence — the interviewer already knows it, and the definition is not what is being tested.
6
Naming the mechanism (load balancer, Auto Scaling group, RDS promotion) is what shows the answer comes from having watched it happen.
13
This half of the answer is the one that separates candidates, and volunteering it without being prompted is what the follow-up was going to ask for anyway.

Why this works: The question looks like a vocabulary check and is a blast-radius check. Anyone can recite that a Region contains zones; the useful signal is whether you can name the failures that cross the boundary, because every one of those has bitten a team that believed multi-AZ made them safe.

Answering the definition and stopping there

Wrong

text
# "A Region is a geographic area, an AZ is a data centre inside
#  it, and multi-AZ gives you high availability."

Better

text
# Same definition, then: "It protects against losing a zone.
#  It does not protect against a bad deploy, a corrupted row or
#  a deleted bucket — those replicate to the standby too, so the
#  control for them is a tested rollback and a tested restore."

What you see: The interview moves to a follow-up you have not thought about, and the answer arrives hesitantly instead of as something you already knew.

Why: Every definition question in this list is a setup for the consequence question behind it. Giving the consequence unprompted costs one extra sentence and changes what the rest of the interview assumes about you — the interviewer stops testing whether you have read about AWS and starts asking what you have run.

What each blast radius contains, and what it does not

Multi-AZ contains the middle ring. The two failures on the right cross every ring, which is why they need a different control entirely.

  • Three nested boxes showing the containment levels, with two failure types outside them.
  • Outermost: the Region, a geographic area such as eu-west-1, containing multiple Availability Zones.
  • Inside it: two Availability Zones, each one or more discrete data centres with independent power, cooling and networking.
  • Inside each zone: subnets and the resources placed in them.
  • Multi-AZ deployment spans both zones, so losing one zone leaves the workload running in the other.
  • Two failures cross every boundary: a bad deployment, which ships to both zones at once, and data corruption or deletion, which replicates to both.
  • The control for those two is a tested rollback and a tested restore, not more zones.

The four questions, the answer in one breath, and the follow-up that separates people

The four questions, the answer in one breath, and the follow-up that separates people
QuestionAnswer in one breathThe follow-upWhat a weak answer sounds like
Region vs AZ. What does multi-AZ protect against?A Region is a geographic area holding multiple Availability Zones; a zone is one or more discrete data centres with independent power and networking. Multi-AZ survives losing a zone."And what does it not protect against?""It makes you highly available" — with no failure it fails to contain
IAM user vs role vs policy vs resource policyA user is a long-lived identity; a role is assumed for temporary credentials; an identity policy says what a principal may do; a resource policy says who may reach a resource."Which one lets an account you do not control read your bucket?"Describing all four as "permissions" without the principal-versus-resource split
How does IAM policy evaluation work?Explicit deny wins outright. Otherwise an SCP or boundary must allow, an explicit allow must exist, and anything unmatched is an implicit deny."You added an allow and access still fails — where do you look?""The most specific policy wins" — which is not how it works
Why should workloads use temporary credentials?They expire without anyone rotating them, so a leak has a bounded lifetime and there is no long-lived secret to store on the instance at all."How does a task on ECS get them without any secret?""They are more secure" with no mechanism behind it

Together

text
# The follow-up on evaluation order, answered properly.

Q: "You attached a policy allowing s3:GetObject and the call
    still returns AccessDenied. Where do you look, in order?"

1. An explicit Deny anywhere. Identity policy, resource policy,
   VPC endpoint policy, or a service control policy on the OU.
   A Deny cannot be overridden by any Allow.
2. A service control policy or permission boundary that does not
   allow the action. Neither of these grants anything; they cap
   what the identity policy is able to grant.
3. The resource policy, if the caller is in another account.
   Cross-account access needs an allow on both sides.
4. A condition that is not satisfied — aws:SourceVpce,
   aws:PrincipalOrgID, or an encryption-context condition on the
   KMS key the object uses.
5. The KMS key policy itself, for an encrypted object. The
   s3:GetObject allow is worthless without kms:Decrypt.

Point 5 is the one most candidates never reach, and it is the
most common real cause.

Remember: Multi-AZ contains a zone failure and nothing else — not a bad deploy, not a corrupted row, not a deleted bucket. A role is permissions plus a trust policy and has no credentials until assumed. Explicit deny always wins, an allow is always required, and an unexplained AccessDenied on an encrypted object is usually the KMS key policy.

See also: region az edge · policy types and trust · least privilege and evaluation · role assumption and temporary credentials · networking and traffic questions

Networking and Traffic — Four Questions With One Precise Answer Each

coreintermediate

These four have exact answers, which is why they are asked. A subnet is public because its route table sends 0.0.0.0/0 to an internet gateway — nothing else makes it public. A security group is stateful and a NACL is not. A NAT gateway reaches the internet and a VPC endpoint avoids it. And ALB, NLB and API Gateway differ by the layer they work at and what they can do with a request.

Think of it as

Each of these is a question about one property, and vague answers come from naming the service instead of the property. Public subnet: the route table. Security group versus NACL: statefulness. NAT versus endpoint: whether the traffic leaves AWS at all. ALB versus NLB versus API Gateway: what the thing is allowed to read in the request.

What we're doing: Answer "NAT gateway vs VPC endpoint" with the number that decides it.

answer.txttext
They are not two ways to do one thing.

  NAT gateway    private subnet → the public internet.
                 Outbound only. Costs per hour and per GB
                 processed. Needed for package installs, API
                 calls to third parties, OS updates.

  VPC endpoint   private subnet → an AWS service, without the
                 traffic leaving the AWS network. Two kinds:
                   gateway  (S3, DynamoDB) — a route table
                            entry, no hourly or data charge
                   interface (most other services) — an ENI
                            in your subnet, hourly + per GB

The question interviewers actually want answered:

  "The workload reads 4 TB a month from S3 and is in a private
   subnet. What happens today, and what should happen?"

  Today:  every byte is billed as NAT data processing, on top
          of the NAT hourly charge, for traffic that never
          needed to reach the internet.
  Should: an S3 gateway endpoint. Add it to the private route
          table, the traffic keeps the same S3 API calls, and
          the NAT data processing charge for it disappears.

  The endpoint also lets you attach an endpoint policy, so you
  can restrict which buckets are reachable from this VPC at
  all — a control the NAT path cannot express.
1
Opening by rejecting the framing is correct here: the question contains an assumption that they are substitutes, and they are not.
8
The gateway/interface split is the detail that shows real use — one is a route table entry and free, the other is an ENI you pay for.
16
Bringing the answer back to a bill and a policy control is what turns a definition into an architecture answer.

Why this works: This pair recurs because getting it wrong is expensive and invisible. The NAT path works perfectly, so nothing ever fails; the only symptom is a line on the bill that nobody attributes to a routing decision made once, months earlier, by whoever created the subnets.

Calling a subnet public because it is named public

Wrong

text
# "subnet-public-1a is the public subnet, so the load balancer
#  goes there."

Better

bash
# Check the route table, which is the only thing that decides it.
aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=subnet-0a1b \
  --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'
# Empty result → the subnet is private, whatever its name is.

What you see: A load balancer or NAT gateway is placed in a subnet with no internet gateway route, and the failure looks like a health check problem rather than a routing one.

Why: Subnet names are tags, and tags are set by whoever created the subnet — including by a copied template that was never adjusted. The route table is the mechanism, so it is the only thing that can be checked. This is the same rule as the review pass: ask the account, not the label.

One packet, four decisions

Each of the four questions is a different point on the same path. Answering by property rather than by service name is what makes each answer precise.

  • A VPC drawn with a public subnet above a private subnet, showing where each of the four answers applies.
  • At the top, the internet and an internet gateway.
  • Front door choice: an Application Load Balancer reads HTTP and routes on host and path; a Network Load Balancer forwards TCP at layer 4 with a static IP; API Gateway adds authorization and throttling in front of an API.
  • The public subnet is public only because its route table sends 0.0.0.0/0 to the internet gateway, and it also contains the NAT gateway.
  • Between the subnet edge and the instance sit two filters: a network ACL, which is stateless and evaluated in rule order at the subnet boundary, and a security group, which is stateful and attached to the interface.
  • The private subnet has no internet gateway route. Outbound internet traffic goes through the NAT gateway and is billed per gigabyte; traffic to S3 and DynamoDB goes through a gateway endpoint, which stays on the AWS network and has no data processing charge.

The four questions, the precise answer, and the trap in each

The four questions, the precise answer, and the trap in each
QuestionThe precise answerThe follow-upThe trap
What makes a subnet public?Its route table has a 0.0.0.0/0 route to an internet gateway. Nothing else does."It has that route and the instance is still unreachable — why?"Answering "it has a public IP" — that is required as well, and it is not what makes the subnet public
Security group vs NACLSecurity group: stateful, allow-only, attached to an interface. NACL: stateless, allow and deny, evaluated in rule-number order at the subnet edge."Outbound works and the reply never arrives. Which one is it?"Saying NACLs are "a second layer of security groups" — the statelessness is the whole difference
NAT gateway vs VPC endpointNAT gives private subnets a route out to the internet. An endpoint reaches an AWS service without the traffic leaving the AWS network."Your workload pulls 4 TB a month from S3. Which do you use?"Treating them as alternatives for the same job — they solve different problems and one of them is often free
ALB vs NLB vs API GatewayALB reads HTTP and routes on host, path and header. NLB forwards TCP, UDP and TLS at layer 4, with a static IP per zone. API Gateway is an API front door with authorization, throttling and usage plans."Your backend needs 60 seconds to respond. Which one is out?"Picking API Gateway by default — the REST API integration timeout caps at 29 seconds

Together

text
# The NACL follow-up, answered.

Q: "The security group allows 443 inbound. The request goes out
    and the response never comes back. What is it?"

A: The NACL. A security group is stateful — it remembers the
   outbound connection and lets the reply back in automatically.
   A NACL does not remember anything, so the reply is evaluated
   as a brand new inbound packet, on an ephemeral source port.

   The reply to an outbound request arrives on a port in the
   ephemeral range, so the NACL needs:

     inbound  ALLOW  TCP  1024-65535  from 0.0.0.0/0

   Without that rule the outbound request succeeds and the
   response is dropped at the subnet edge, which reads exactly
   like a timeout in the application.

Q: "So when do you use a NACL at all?"
A: When you need a deny. Security groups cannot express one, so
   blocking a specific CIDR at the subnet edge is the case NACLs
   are actually for.

Remember: A subnet is public because of its route table. A security group is stateful and a NACL is not, which is why NACLs need ephemeral-port return rules. NAT reaches the internet; an endpoint avoids it, and the S3 gateway endpoint is free. ALB reads HTTP, NLB forwards TCP with a static IP, API Gateway adds authorization and stops at 29 seconds.

See also: public vs private subnets · ephemeral ports and statefulness · vpc endpoints · alb vs nlb · timeout and payload limits

Compute — Choosing a Model, and the Two Lambda Questions

coreintermediate

The compute questions test two different things. The first two ask what you give up and what you get back at each level of abstraction — an instance, a scheduled container, an invoked function. The last two are specific: concurrency is invocations in flight rather than requests per second, and throttling happens when that number hits a limit you or AWS set.

Think of it as

Read the three models as a trade of control for operational surface. EC2 gives you the whole machine and the whole job of maintaining it. ECS gives you the container and hands over placement, replacement and rollout. Lambda gives you a function and hands over everything else, in exchange for accepting its execution model — no long requests, no persistent connections, and concurrency as the unit of capacity.

What we're doing: Answer "EC2 vs ECS vs Lambda" as a set of eliminations rather than a preference.

answer.txttext
Do not start from a favourite. Start from what rules each out.

LAMBDA IS OUT WHEN
  the request can exceed 15 minutes            (hard limit)
  the workload holds long-lived connections    (WebSockets, pools)
  the service needs predictable low latency and
    provisioned concurrency does not pay for itself
  a heavy runtime makes cold starts unacceptable
  utilisation is high and steady — then it is the expensive option

ECS IS OUT WHEN
  the work is genuinely spiky and idle most of the time
    (you are paying for tasks that do nothing)
  the team cannot own a container image and its base updates
  the workload needs a machine-level feature: a kernel module,
    a licence tied to a host, a specific instance store layout

EC2 IS OUT WHEN
  nothing about the workload needs the machine, and you would be
  taking on patching, AMI pipelines, capacity and placement to
  gain nothing you will actually use

WHAT IS USUALLY LEFT
  a request/response service with steady traffic  → ECS on Fargate
  an event handler, spiky, short, stateless       → Lambda
  a licensed database or a GPU workload           → EC2

Then, and only then, compare cost — between the options that
are still standing.
3
The 15-minute ceiling and long-lived connections rule Lambda out on execution model, which is a stronger argument than any cost comparison.
10
Spiky and mostly idle is the shape that makes always-on tasks wasteful, and it is the honest case against ECS rather than against containers.
18
Naming what EC2 costs you — patching, images, capacity, placement — is what shows the choice is about operational surface rather than familiarity.

Why this works: Eliminations are checkable and preferences are not. An interviewer can disagree with "I like Fargate" and cannot disagree with "this holds connections for hours, so Lambda is out". It also produces the right answer more often, because most real workloads are ruled into one option by a constraint nobody thought to state.

Sizing Lambda by request rate

Wrong

text
# "We do 500 requests per second and the limit is 1,000
#  concurrent, so we have plenty of headroom."

Better

text
# Concurrency = rps × duration.
# 500 × 0.2 s = 100 concurrent — fine.
# 500 × 3.0 s = 1,500 concurrent — throttled.
# A dependency slowing from 200 ms to 3 s changes nothing about
# the request rate and everything about the concurrency.

What you see: A function that has run comfortably for months starts throttling during an unrelated incident, because a downstream dependency got slower and every in-flight execution now lives fifteen times as long.

Why: Duration is the term people drop, and it is the term that moves during an incident. Request rate is usually stable; duration is what a slow database, a retrying dependency or a large payload changes. Sizing on rate alone means the concurrency limit is reached exactly when the system is already degraded.

What you hand over at each level, and what Lambda concurrency counts

The top half is the trade you make. The bottom half is the arithmetic behind every Lambda concurrency question.

  • Top: three columns comparing EC2, ECS and Lambda by what you still operate and what AWS operates.
  • EC2: you operate the operating system, patching, capacity, placement and the application. AWS operates the hardware.
  • ECS: you operate the container image and the task definition. AWS operates placement, replacement and rollout. On Fargate it also operates the instances; on EC2 capacity you keep them.
  • Lambda: you operate the function code and its configuration. AWS operates everything else, and in exchange the execution model is fixed.
  • Bottom: the concurrency formula, concurrency equals requests per second multiplied by average duration in seconds.
  • Worked example: 500 requests per second at 200 milliseconds is 100 concurrent executions, comfortably under the 1000 default.
  • Second example: the same 500 requests per second at 3 seconds is 1500 concurrent, above the default, so requests are throttled with a 429.

The four compute questions, the answer, and the follow-up

The four compute questions, the answer, and the follow-up
QuestionAnswer in one breathThe follow-upThe trap
EC2 vs ECS vs LambdaDecreasing control and decreasing operational surface. EC2 for full machine control, ECS for containerised services you still shape, Lambda for event-driven work that fits its execution model."Your service holds WebSocket connections for hours. Which is out?"Answering by cost — the execution model rules options out long before price does
Fargate vs ECS on EC2Fargate removes instance management and charges per task. EC2 capacity keeps instance choice, GPUs, daemon tasks and higher density, in exchange for patching and capacity planning."When is EC2 capacity clearly right?""Fargate is always simpler" — true, and not an argument on its own
How does Lambda concurrency work?Concurrency is executions in flight — requests per second times average duration. The account default is 1,000 per Region; reserved concurrency caps and guarantees; provisioned concurrency pre-warms."Your function got slower. What happens to concurrency?"Describing it as a request rate, which makes the duration term disappear
What causes Lambda throttling?Demand above the available concurrency: the account limit, a reserved limit on the function, or burst capacity. The response is a 429, and what happens next depends on the invocation type."Who sees the 429, and who does not?"Forgetting that async and event-source invocations retry, so throttling can be invisible in the caller

Together

text
# The throttling follow-up, answered by invocation type.

Synchronous (API Gateway, an SDK Invoke call)
  → the caller receives 429 TooManyRequestsException immediately.
  → the user sees an error, so this is the loud case.

Asynchronous (S3 event, SNS, EventBridge)
  → Lambda queues the event and retries, by default twice, with
    a delay. Nothing is lost quickly and nothing surfaces either.
  → the symptom is latency, not errors. Set a destination or a
    dead-letter queue, or the failure is silent after the retries.

Event source mapping (SQS, Kinesis, DynamoDB Streams)
  → the poller backs off and retries. For SQS the message
    returns to the queue after its visibility timeout.
  → the symptom is a growing queue depth, which is why queue
    depth is the alarm that catches this and error rate is not.

# The mistake this catches: "we would see the errors". You would
# see them for one of the three, and the other two are the ones
# that page you at 3 a.m. as a backlog.

Remember: Rule options out by execution model before comparing cost. Lambda concurrency is requests per second times duration, not a rate — the account default is 1,000 per Region, and duration is what moves during an incident. Reserved concurrency caps as well as guarantees; only provisioned concurrency removes cold starts.

See also: cold starts and concurrency · when lambda fits · ecs on ec2 vs fargate · when not to use serverless · data store questions

Data Stores — Four Comparisons, Four Different Axes

coreintermediate

Each of these four pairs is compared on a different axis, and naming the axis is most of the answer. Multi-AZ versus read replica is availability versus read capacity. RDS versus Aurora is the storage layer. RDS versus DynamoDB is whether your access patterns are known in advance. Redis versus DynamoDB is whether the data is allowed to disappear.

Think of it as

Say what each option is for before saying which is better. Multi-AZ is a standby you cannot read; a read replica is a copy you can read that is not a standby. Answering "which is better" for a pair that solves two different problems is the wrong shape of answer, and interviewers ask these pairs precisely because they invite that mistake.

What we're doing: Answer "Multi-AZ vs read replica" so the difference is unmistakable.

answer.txttext
They are not two settings on the same dial.

MULTI-AZ (instance deployment)
  A standby in a second Availability Zone, kept in sync
  synchronously. You cannot read from it. You cannot connect to
  it. Its only job is to become the primary automatically when
  the primary fails, behind the same endpoint.
  Buys: availability. Costs: roughly double the instance.

READ REPLICA
  A separate readable instance fed asynchronously from the
  primary. It has its own endpoint. It can lag — seconds
  normally, minutes under write pressure. It can be promoted to
  a standalone primary, which is a manual, one-way action.
  Buys: read capacity, and a cross-Region DR component.

WHERE PEOPLE GO WRONG
  Sending read traffic to "the standby" — there is no endpoint
  for it, and the assumption survives interviews because the
  diagram draws two boxes that look alike.

  Treating replicas as HA — the promotion is not automatic and
  the lag is real, so a failure can cost you the writes that
  were still in flight.

MOST PRODUCTION SYSTEMS HAVE BOTH
  Multi-AZ for the failure, replicas for the read volume, and
  application code that knows a replica read may be stale — which
  is the part that has to be designed rather than configured.
1
Rejecting the shared-dial framing is the answer: they buy different things and are commonly used together.
8
That the standby is unreadable is the concrete fact that settles the comparison, and it is the one most often got wrong.
16
Naming the two failure modes — reading a standby that has no endpoint, and trusting promotion as failover — shows the difference has consequences rather than being terminology.

Why this works: The pair is asked because the two features look symmetric on a diagram and are not symmetric at all: one is invisible and automatic, the other is visible, manual and lagging. Answering with what each buys, then what most systems actually run, shows the comparison has been made against a real workload rather than a documentation page.

Using a read replica for a read-after-write flow

Wrong

text
# POST /orders   → writes to the primary
# GET  /orders/1 → reads from the replica
# The user creates an order and the next page says it is missing.

Better

text
# Route reads that follow a write in the same user journey to
# the primary; send reporting, search and list views to the
# replica. Replica lag is a property to design around, not a
# setting to tune to zero.

What you see: An intermittent "record not found" immediately after creating something, which never reproduces locally and disappears on retry — because by the time anyone checks, the replica has caught up.

Why: Asynchronous replication means the replica is behind by an amount that varies with write load, so the bug appears under exactly the conditions that make it hardest to reproduce. The fix is routing, not tuning: some reads are allowed to be stale and some are not, and that decision belongs in the application rather than in the database configuration.

Four pairs, four axes

Each row names the axis first. Once the axis is named, the answer is a statement of what the workload needs rather than a preference between products.

  • Four rows, each comparing a pair of data stores on a named axis.
  • Row 1, axis availability versus read capacity: Multi-AZ is a synchronous standby in another zone that serves no reads and fails over automatically; a read replica is an asynchronous readable copy that can lag and can be promoted.
  • Row 2, axis the storage layer: standard RDS runs community engines on ordinary volumes; Aurora keeps six copies across three zones and lets up to fifteen replicas read the same storage.
  • Row 3, axis are the access patterns known: a relational database lets you write the query later; DynamoDB requires the access patterns before the table is designed.
  • Row 4, axis may the data disappear: Redis is memory and can lose data on failover; DynamoDB is durable and can be the system of record.
  • Footnote: the first pair is the one most often answered as if both options solved the same problem.

The four pairs, the axis, and the follow-up that catches a memorised answer

The four pairs, the axis, and the follow-up that catches a memorised answer
QuestionThe axisAnswer in one breathThe follow-up
RDS Multi-AZ vs read replicaAvailability vs read capacityMulti-AZ is a synchronous standby for failover and serves no reads. A read replica is an asynchronous readable copy for scaling reads, and it can lag."Can a read replica be your high-availability story?"
RDS vs AuroraThe storage layerAurora replaces the storage engine — six copies across three zones, replicas reading shared storage, faster failover. RDS runs the community engine as it is."When would you deliberately not use Aurora?"
RDS vs DynamoDBAre the access patterns known in advance?Relational lets you write the query later. DynamoDB wants the patterns before the table and gives predictable latency at any size in return."Product asks for a new report next week. What changes?"
Redis vs DynamoDBMay the data disappear?Redis is memory: sub-millisecond, rich structures, and may lose data on failover. DynamoDB is durable storage with single-digit millisecond reads."Where do you keep a shopping cart, and why?"

Together

text
# The follow-ups, answered.

"Can a read replica be your HA story?"
  No. Replication is asynchronous, so promoting one can lose the
  writes that had not replicated yet, and promotion is a manual
  or scripted action rather than an automatic failover. It is a
  reasonable disaster-recovery component and it is not Multi-AZ.

"When would you deliberately not use Aurora?"
  When you need an extension or engine behaviour Aurora does not
  carry; when the workload is small enough that the smallest
  sensible Aurora footprint costs more than the RDS instance it
  replaces; or when you want a plain engine you can move off AWS
  without a migration.

"Product asks for a new report next week."
  Relational: write the query, add an index if it is slow.
  DynamoDB: if the pattern is not covered by the key or an
  existing index, you add a GSI — or you export to S3 and query
  it elsewhere. That is the flexibility you traded for the
  latency guarantee, and saying so is the answer.

"Where do you keep a shopping cart?"
  In the durable store, with Redis in front of it if the read
  volume needs it. A cart in Redis alone disappears on a
  failover, and the user experience of that is a lost cart with
  no error message anywhere.

Remember: Name the axis first. Multi-AZ is availability and its standby is unreadable; a replica is read capacity and it lags. Aurora is a different storage layer. DynamoDB wants the access patterns up front. Redis may lose data on failover, so it accelerates a system of record and never is one.

See also: multi az vs read replicas · when aurora vs standard rds · dynamodb core vocabulary · cache is not the system of record · messaging questions

Messaging — Three Services, Two Queue Types, One Idempotent Consumer

standardintermediate

SQS holds work until one consumer takes it. SNS pushes one message to every subscriber at once. EventBridge routes events to targets by matching their content. Standard queues trade ordering for throughput, FIFO trades throughput for ordering, and either way the consumer has to survive receiving the same message twice.

Think of it as

Ask who is waiting. A queue exists because the producer must not wait for the work; a topic exists because several consumers need the same fact; an event bus exists because the producer should not know who the consumers are. Choosing between them is a coupling decision rather than a throughput one.

text
queue = one consumer, work buffered · topic = every subscriber, pushed · bus = content-matched routing + replay · consumer = idempotent either way
Who is waiting, and who knows about whom

The bottom row is the composition used most often in production: the topic fans out, and each queue gives its consumer an independent buffer and retry story.

  • Three panels comparing SQS, SNS and EventBridge, followed by the combined pattern.
  • SQS: a producer writes to a queue and one consumer pulls from it. The producer does not wait. Delivery is at least once, so the consumer must be idempotent.
  • SNS: a publisher sends to a topic and every subscription receives its own copy at the same time. Push-based, and the publisher does not know the subscribers.
  • EventBridge: a source emits an event to a bus, rules match on the event content, and matching rules deliver to their targets. Supports archive and replay.
  • Combined: a publisher sends one message to an SNS topic, which delivers to three SQS queues, each with its own consumer, its own retry behaviour and its own dead-letter queue.

Using the SQS MessageId as the idempotency key

Wrong

python
key = record["messageId"]   # unique per delivery attempt group,
                            # not per business event

Better

python
key = sha256(f"{body['order_id']}:{body['event_type']}")
# stable when the producer retries and sends the same logical
# event as a new message with a new MessageId

What you see: Duplicate charges appear despite an idempotency table that shows no repeated keys, because each duplicate arrived as a genuinely new message.

Why: The MessageId identifies a delivery, not a fact. A producer that times out and resends creates a second message with a second id carrying the same business event, and the deduplication table treats them as unrelated. Deriving the key from the event itself is what makes it survive the retry path that actually produces most duplicates.

The three messaging questions, the answer, and the follow-up

The three messaging questions, the answer, and the follow-up
QuestionAnswer in one breathThe follow-upThe trap
SQS vs SNS vs EventBridgeQueue: one consumer pulls work. Topic: every subscriber is pushed a copy. Bus: rules route on event content, with archive and replay."Two teams need the same event. Which do you reach for?"Comparing them on throughput instead of on coupling
Standard vs FIFO SQSStandard is effectively unlimited throughput with best-effort ordering. FIFO orders strictly within a MessageGroupId and defaults to 300 requests per second per action, or 3,000 messages per second with batching."Your FIFO queue is throttling. What is the first thing to check?"Choosing FIFO for "safety" when nothing in the workload needs ordering
How do you make an SQS consumer idempotent?Derive a stable key from the message body, record it with a conditional write before the side effect, and treat a duplicate as a successful no-op."Where does the key come from, and how long do you keep it?"Using the message id, which changes when a producer resends the same logical event

Together

python
# An idempotent consumer, with the key derived from the event.

import hashlib
import boto3
from botocore.exceptions import ClientError

table = boto3.resource("dynamodb").Table("processed-events")

def idempotency_key(event: dict) -> str:
    # Derived from the business fact, not from the delivery.
    # order_id + event type is stable across producer retries;
    # the SQS MessageId is not.
    basis = f"{event['order_id']}:{event['event_type']}"
    return hashlib.sha256(basis.encode()).hexdigest()

def handle(event: dict) -> None:
    key = idempotency_key(event)
    try:
        table.put_item(
            Item={"pk": key, "ttl": event["occurred_at"] + 7 * 86400},
            ConditionExpression="attribute_not_exists(pk)",
        )
    except ClientError as exc:
        if exc.response["Error"]["Code"] == "ConditionalCheckFailedException":
            return          # already processed — a successful no-op
        raise

    charge_customer(event)  # the side effect, guarded by the write above

# Two details that matter:
#  1. The conditional write happens BEFORE the side effect, so a
#     crash between them leaves the key claimed. Recovering from
#     that needs a status field, not a bare marker.
#  2. The TTL is longer than any plausible redelivery window, and
#     the record is cheap, so err long.

Remember: Queue for work one consumer takes, topic for a fact several consumers need, bus for routing you do not want the producer to know about — and SNS into SQS when you want both fan-out and per-consumer buffering. FIFO costs throughput for ordering. The consumer is idempotent either way, keyed on the business event rather than the message id.

See also: sqs queues and delivery modes · at least once delivery and duplicate handling · sns sqs fanout pattern · event buses rules and targets · idempotency mechanisms on aws

The Seven "How Would You…" Questions

coreadvanced

The scenario questions are open on purpose. They are not testing whether you know the services — they are testing whether you answer in a defensible order, name the constraint that shapes the design, and say what you would check first. A structured answer to any of these beats a longer answer to all of them.

Think of it as

Every one of these has a fixed opening move, and using it is what makes the answer sound operated rather than read. Secure a bucket: start from Block Public Access. Serve React: start from what is dynamic. Deploy Django: start from where migrations run. Migrate a schema: expand then contract. Multi-Region DR: start from RPO and RTO. A 5xx spike: start at the edge and work inward. Reduce a bill: group by usage type.

What we're doing: Answer "a sudden 5xx spike" as an investigation order, not a list of guesses.

answer.txttext
First, is it real? Error RATE can rise because traffic fell.
  ALB → HTTPCode_ELB_5XX_Count and RequestCount together.
  A count that is flat with a falling denominator is not an
  incident, and starting here has saved several hours.

Second, edge or origin?
  CloudFront 5xx with ALB clean  → the edge or the distribution
  ALB 5XX with target 5XX clean  → the load balancer could not
                                   reach a healthy target at all
  Target 5XX rising              → the application itself

Third, one target or all of them?
  HTTPCode_Target_5XX split by target, and UnHealthyHostCount.
  One  → an instance or task problem; replacement fixes it and
         the finding is why the health check did not catch it
  All  → shared: a deploy, a dependency, a quota, or the database

Fourth, what changed in the window?
  Deployments, feature flags, configuration changes, an expiring
  certificate, a quota crossed. CloudTrail answers this one, and
  it answers it faster than reasoning about the code does.

Fifth, the dependencies.
  DatabaseConnections against max_connections, cache evictions,
  downstream latency, throttling metrics on anything you call.
  Connection exhaustion is the single most common shared cause.

Then: take ONE failing request, get its correlation id, and
follow it through the load balancer log, the application log
and the trace. One real example beats another ten minutes of
dashboards, and it is the step people skip because it feels
slower than looking at graphs.
1
Confirming the signal before investigating it is the step that separates a practised responder from a fast one.
6
The edge-versus-origin split is what stops the investigation searching the application for a problem that is in front of it.
13
One target versus all is the highest-value branch in the whole order — it decides whether this is a replacement or an incident.
21
CloudTrail answers "what changed" as a fact rather than a recollection, and most spikes correlate with something in that window.

Why this works: Interviewers ask this one because it cannot be answered from documentation. A candidate who has done it moves in a fixed direction and can say why each step comes before the next; a candidate who has not lists plausible causes in no particular order. The order also happens to be the right one in practice, which is why it is worth learning as an order rather than a list.

Answering a scenario question by listing services

Wrong

text
# "For DR I would use Route 53, CloudFormation, S3 replication,
#  DynamoDB global tables, and Aurora Global Database."

Better

text
# "First: what RPO and RTO has the business agreed? An hour of
#  data loss and four hours to recover is pilot light. Five
#  minutes and fifteen is warm standby, which costs several
#  times more. The number picks the architecture — so I would
#  ask before drawing anything."

What you see: The answer is complete, correct and interchangeable with anyone else's, and the follow-up — "how much would that cost, and did anyone ask for it?" — has no answer.

Why: Every service in the wrong answer might appear in the right one; what is missing is the constraint that selects between them. Naming the requirement first shows the design is derived rather than recalled, and it is also the honest position: without an RPO, four different architectures are all defensible and none of them can be recommended.

The opening move for each of the seven

The opening move is the whole difference between a structured answer and a list of services. Each one narrows the problem before any component is named.

  • Seven rows, each pairing a scenario question with the move that should open the answer and the reason.
  • Secure an S3 bucket: open with Block Public Access at the account level, because it makes every later mistake non-fatal.
  • Serve React from CloudFront and S3: open by asking what is actually dynamic, because that decides whether you need a server at all.
  • Deploy Django on ECS: open with where migrations run, because it is the one step that cannot be rolled back with the image.
  • Zero-downtime migrations: open with expand and contract, because both old and new code must run against the same schema.
  • Multi-Region disaster recovery: open with the agreed RPO and RTO, because those numbers select the strategy.
  • Investigate a 5xx spike: open at the edge and work inward, because the first branch is one target failing versus all of them.
  • Reduce the bill: open by grouping by usage type, because it separates capacity you chose from architecture that accumulated.

The seven scenarios, in the order the answer should come out

The seven scenarios, in the order the answer should come out
ScenarioThe answer, in orderThe detail that marks experience
Secure an S3 bucketBlock Public Access at the account and the bucket → Object Ownership set to bucket-owner-enforced so ACLs stop mattering → a bucket policy denying `aws:SecureTransport` false → default encryption, KMS if the data warrants it → versioning → server access or CloudTrail data events → a VPC endpoint policy if access should only come from your networkMentioning that `kms:Decrypt` on the key is a separate grant, so an `s3:GetObject` allow alone still fails
Serve React with CloudFront and S3Build to static output → private bucket, no website hosting → CloudFront with origin access control → ACM certificate in us-east-1 → 403 and 404 mapped to `/index.html` with a 200 so client-side routes resolve → long cache on hashed assets, no-store on `index.html` → invalidate `/index.html` on deployThe certificate Region and the SPA error mapping — both are the things that fail on a first attempt
Deploy Django on ECSImage to ECR → task definition with the web command, a second one for workers → Fargate behind an ALB in private subnets → RDS and ElastiCache in data subnets → secrets injected from Secrets Manager by ARN → static and media on S3 behind CloudFront → migrations as a one-off task before the new revision rolls → deep health check → task role for the app, execution role for the pullRunning migrations once as their own task rather than in every container's entrypoint
Zero-downtime database migrationsExpand: add the new column or table, nullable, no destructive change → deploy code that writes both and reads the old → backfill in batches with a bounded rate → switch reads to the new shape → contract in a later release once nothing references the old oneSaying that expand and contract must be separate deploys, because a rollback in between has to still work
Multi-Region disaster recoveryGet the agreed RPO and RTO first → pick the strategy those numbers allow: backup and restore, pilot light, warm standby, or active/active → replicate the data accordingly → same infrastructure code in both Regions → Route 53 health checks for the switch → decide the failback path → drill it on a scheduleNaming the data as the hard part — global tables and cross-Region replication have their own consistency behaviour
Investigate a sudden 5xx spikeIs it the edge or the origin → one target or all targets → did anything deploy or change in the window → dependency health: database connections, cache, downstream APIs → quotas and throttling → pick one failing request and follow its correlation id end to endChecking whether the error rate is a rate or a count — a traffic drop can raise the percentage with no new failures
Reduce the bill without blind downsizingGroup by usage type, not by service → separate capacity you chose from architecture that accumulated → remove the accumulated first: gateway endpoints, log retention, storage class, orphaned volumes and snapshots → then rightsize on peak, not average → then commit to what is left with Savings Plans → leave a budget alert behindNaming NAT data processing and log ingestion unprompted, and saying that removal beats shrinking

Together

text
# One scenario, answered the way it should sound out loud:
# "How would you handle a database migration with no downtime?"

The constraint that shapes everything: during a rolling deploy,
the old and new versions of the code both run against the same
database, at the same time. So every step has to be compatible
with both. That rules out one big migration and produces four
releases instead.

R1  EXPAND
    ALTER TABLE orders ADD COLUMN customer_ref uuid NULL;
    Nullable, no default that rewrites the table, no constraint
    yet. Old code ignores the column; new code has not shipped.

R2  DUAL WRITE
    Deploy code that writes both customer_id and customer_ref,
    and still reads customer_id. Rolling back to R1 is safe:
    R1 code ignores a column it does not know about.

R3  BACKFILL, THEN SWITCH READS
    Backfill in batches — 5,000 rows at a time, with a pause,
    so replication lag and lock time stay bounded. Verify the
    count matches. Then deploy code that reads customer_ref.

R4  CONTRACT
    Once nothing reads customer_id, and only once a rollback to
    R3 is no longer plausible: add NOT NULL, add the foreign
    key, drop the old column.

Why four releases: each one is independently reversible. A
single release that adds the column, backfills and drops the old
one cannot be rolled back at all — the data the old code needs
is gone.

Remember: Open with the move that narrows the problem: Block Public Access, what is actually dynamic, where migrations run, expand-then-contract, the agreed RPO and RTO, edge-to-inward, group by usage type. Then name the constraint that decides between options. A structured answer to one scenario beats a service list for all seven.

See also: least privilege and avoiding public buckets · static output vs server rendering · database migrations in deployments · the four dr strategies · the fixed investigation order

Advertisement