Cloud and Managed Database Services Questions
Running databases as managed cloud services rather than self-hosting them: choosing and provisioning managed relational and NoSQL offerings (for example Amazon RDS/Aurora/DynamoDB, Azure SQL Database/Cosmos DB, Google Cloud SQL/Spanner), sizing instances and storage, and designing an architecture (read replicas, connection proxies and pooling for managed or serverless compute) to meet a latency or availability target. It covers comparing provisioned versus serverless/autoscaling pricing and operational models, forecasting capacity and cost, and migrating a database onto or between managed deployments: moving a self-hosted database to a managed service, switching a workload from provisioned to serverless (or back), changing a single-AZ deployment to multi-AZ, and the questions to ask before adopting a new managed vendor. The core question is the split of responsibility and cost between the cloud provider and the engineering team: what the provider takes on (patching, infrastructure-level HA, automated backups) versus what remains the team's job (configuration, capacity and cost tuning, security posture like encryption and key rotation). It does not cover backup and restore mechanics, RPO/RTO planning, replication or sharding internals, or SQL-level query diagnostics.
Describe encryption in transit and at rest for managed database services. For AWS RDS/Aurora: list the steps you'd take to verify TLS is enforced on connections, confirm encryption at rest is enabled using KMS, and validate that snapshots and read replicas remain encrypted. Mention potential performance impacts and key rotation considerations.
Sample Answer
Encryption at rest and encryption in transit are two separate controls on RDS and Aurora, and verifying "the database is encrypted" means checking both independently, plus confirming the encryption actually propagates to every derived artifact (snapshots, same-region replicas), since none of that is a single toggle.
Verifying TLS is enforced on connections
- Check the engine parameter that forces secure connections:
rds.force_sslfor PostgreSQL,require_secure_transportfor MySQL, in the instance's parameter group, and confirm it is set to require (not merely allow) TLS. - Connect and confirm the connection actually negotiated TLS: on PostgreSQL,
SHOW ssl;should returnon; on MySQL,SHOW STATUS LIKE 'Ssl_cipher';should return a non-empty cipher name (an empty result means the connection is not encrypted). - Confirm the application's own connection string requests TLS (for example
sslmode=requireon PostgreSQL). Enforcing the server-side parameter without updating every client is a coordinated two-sided change: once enforcement is on, a client that does not request TLS is rejected outright at connection time, not degraded gracefully, so this needs to be tested in staging before it is flipped on in production. - Confirm the client's trust store has the current
rds-cacertificate bundle. AWS periodically rotates these certificates with advance notice and a transition period; a client trusting only the old certificate will start failing to connect at the rotation deadline, which shows up as a hard cutover, not a gradual warning.
Verifying encryption at rest and confirming it propagates
- Confirm the instance itself is encrypted:
aws rds describe-db-instances --db-instance-identifier mydb --query "*[].{StorageEncrypted:StorageEncrypted}" --output text, or the Encryption field under Configuration in the console. Also note which AWS Key Management Service (KMS) key ID is attached, an AWS-managed key or a customer-managed key. - Confirm snapshots are encrypted with the same key as the source. This is enforced by RDS, not something you can misconfigure: an unencrypted instance cannot produce an encrypted snapshot directly, only via copying an existing snapshot with encryption enabled, and any snapshot of an already-encrypted instance must use the same KMS key as that instance.
- Confirm same-region read replicas use the identical KMS key as the primary, again structurally enforced (you cannot pair an encrypted primary with an unencrypted replica, or the reverse). A cross-region replica uses a key in its own destination region instead, since KMS keys are region-scoped, so verifying a cross-region replica means checking the destination region's key, not re-checking the source's.
Illustrative shape of a verification run (not a captured live run)
$ psql "host=mydb.xxxx.rds.amazonaws.com sslmode=require" -c "SHOW ssl;"
ssl
-----
on
$ aws rds describe-db-instances --db-instance-identifier mydb \
--query "*[].{StorageEncrypted:StorageEncrypted,KmsKeyId:KmsKeyId}"
[{"StorageEncrypted": true, "KmsKeyId": "arn:aws:kms:us-east-1:111122223333:key/abcd-..."}]
This is the shape of what a passing check looks like, not a run against a real instance; the actual output depends on the specific instance being checked.
Performance impact
AWS states that encryption at rest is handled transparently, using AES-256, with minimal performance impact, since the underlying hardware accelerates the cryptographic operations. In practice, at-rest encryption overhead is not a meaningful factor in sizing decisions for the vast majority of workloads. TLS in transit adds a small, mostly one-time cost at connection setup (the handshake), not a meaningful per-query cost once a connection is established; this is one more reason connection pooling matters for high-request-rate applications, since pooling means paying that handshake cost once per pooled connection rather than once per request.
Key rotation considerations
AWS-managed KMS keys rotate automatically every year with no ability to disable it. Customer-managed keys support optional automatic rotation, off by default, with a 365-day default rotation period that can be customized. The important nuance: rotation changes only the current key material used for new encryption operations going forward. It does not re-encrypt data that is already on disk, and decrypting existing data continues to transparently use whichever key material version originally encrypted it. This means rotation is not a way to "refresh" the encryption on data already written, and it does not reduce exposure from an already-compromised key, since the compromised key material remains valid for decrypting everything it originally encrypted. Genuinely rotating away from a suspected-compromised key means creating a new KMS key and re-encrypting the actual data end to end, which for RDS means the same snapshot-copy-with-a-new-key-then-restore cycle used to add encryption to a previously unencrypted instance, not simply toggling key rotation on.
Trade-offs and pitfalls
- Enforcing TLS on the server before every client is updated causes a hard outage at the moment of enforcement, not a gradual one; roll it out in a lower environment first and confirm every consumer's connection string before flipping the production parameter.
- At-rest encryption protects data on disk; it does not protect credentials or query data while they are moving between the application and the database. Treat the two as independent requirements, both need to be explicitly verified, neither implies the other.
- Assuming key rotation re-encrypts existing data is a common and consequential misunderstanding: if a key rotation cadence is being used to satisfy a compliance requirement, confirm with whoever owns that requirement whether rotating the key material is actually sufficient, or whether the requirement really means re-encrypting the data itself.
- Forgetting to check that a cross-region replica or a copied snapshot is encrypted with the correct destination-region key is an easy gap, since the source region's key ID is not valid in another region and the failure shows up as a create-time error, not a silent gap, but only if someone is actually watching for it.
You are deciding whether to move the primary database to a serverless managed database or keep it on a self-managed cluster running on VMs or containers. Discuss the connection-scaling issues serverless callers create, the proxy patterns you would consider (for example connection pooling or RDS Proxy), cold-start interactions, cost elasticity, operational overhead, and migration complexity.
Sample Answer
Serverless callers break the assumption self-managed database sizing quietly relies on: that a bounded, known number of long-lived application processes hold a bounded, known number of connections. A serverless caller like AWS Lambda instead can spin up hundreds or thousands of short-lived execution environments during a burst, and neither a self-managed cluster's fixed max_connections nor a naively provisioned serverless database survives that without a connection proxy in the path. The recommendation: put a proxy (RDS Proxy, a self-run PgBouncer or PgCat in transaction mode, or Cloud SQL's connector) in front of the database and treat it as a required architectural component, not an optional extra, whichever database you choose; with that in place, a serverless-capable managed database wins over a self-managed cluster for this specific caller shape on every axis except raw steady-state infrastructure cost, which is rarely the deciding factor once the operational cost of getting connection scaling wrong is counted.
Why serverless callers exhaust connections
Each Lambda execution environment behaves like its own short-lived process. A warm environment can reuse a connection across invocations for as long as it stays alive, but a burst of traffic spins up many new environments simultaneously, and each one that opens its own database connection on cold start has no shared, persistent pool the way a long-running application server naturally has, one pool, shared across every request that server handles. The result is that concurrency at the compute layer translates almost one-to-one into concurrent connection demand at the database layer, a relationship a traditional fixed-process application server never creates in the first place.
Proxy-pattern mitigations
- RDS Proxy: sits between the application and RDS/Aurora, pools and multiplexes connections, and is the AWS-managed default for this pattern.
- PgBouncer or PgCat in transaction mode: the self-hosted equivalent for PostgreSQL, releasing the real database connection back to the pool the instant a transaction commits rather than holding it for a client's whole session.
- Cloud SQL Auth Proxy / connectors: the equivalent authenticated, pooled path for Cloud SQL.
All three convert "many short-lived execution environments each wanting a connection" into "a small, bounded number of real database connections," which is what actually lets a serverless caller survive a real traffic burst, regardless of whether the database itself is self-managed or serverless.
Cold-start interactions
Two separate cold starts can stack unfavorably: the caller's own cold start (a new Lambda execution environment initializing, which is also where its first database or proxy connection gets established) and, if the database side is also serverless with scale-to-zero enabled, the database's own resume-from-paused delay. A request that happens to hit both a cold caller and a paused database pays both penalties in sequence. For a workload built on serverless callers, the practical mitigation is to keep the database side warm, a non-zero minimum capacity rather than scale-to-zero, even though that gives up some of serverless's cost-elasticity benefit; the alternative is a compounding latency tail on exactly the requests that are already least predictable.
Cost elasticity and operational overhead
A serverless database paired with serverless callers gives the cleanest cost-tracks-actual-usage story, genuinely valuable for spiky or unpredictable traffic. A self-managed cluster on fixed virtual machines (VMs) has no elasticity at all: the provisioned cluster is paid for whether traffic shows up or not. But "serverless removes operational work" is only half true. Self-managed adds real, ongoing operational work (patching, high availability, backups) independent of the caller side; a serverless database removes most of that, but introduces a new, smaller operational surface that did not exist before: proxy capacity planning and monitoring, minimum-capacity and cold-start tuning, and a connection-storm incident response playbook for the cases the proxy does not fully absorb.
Migration complexity is not just an infrastructure change
Adopting this pattern typically requires application-side changes, not only new infrastructure:
- Connection timeout and retry logic has to change. A connection attempt might now be queued or briefly rejected by the proxy under load, instead of always succeeding immediately the way a warm pool on a long-running app server does, so retry-with-backoff logic that previously did not exist becomes necessary.
- Anything relying on session-level state breaks under transaction-mode pooling and has to be found and rewritten, not just reconfigured: prepared statements assumed to persist across calls, session variables, or advisory locks held across requests.
- Cutover needs the same phased, rollback-capable approach as any other production database change, not a configuration flag flip, since connection behavior under real burst load is exactly the kind of thing that is hard to fully validate outside production traffic.
Worked example: what the proxy is actually absorbing
proxy_db_side_pool = 50 # real database connections the proxy maintains
concurrent_lambda_burst = 500 # simultaneous execution environments during a spike
immediately_served = min(proxy_db_side_pool, concurrent_lambda_burst)
queued = max(0, concurrent_lambda_burst - proxy_db_side_pool)
print(f"Requests served immediately from the pool: {immediately_served}")
print(f"Requests queued at the proxy, waiting for a connection to free up: {queued}")
print(f"Fraction queued: {queued/concurrent_lambda_burst:.0%}")
Requests served immediately from the pool: 50
Requests queued at the proxy, waiting for a connection to free up: 450
Fraction queued: 90%
Without a proxy, a database with a hard connection ceiling near 50 would simply reject most of those 500 simultaneous connection attempts outright. With the proxy in front, 450 of them queue briefly instead, each waiting only as long as the transaction ahead of it in line takes, typically a short OLTP (online transaction processing) transaction. That difference, hard rejection versus a brief queue, is the entire value the proxy adds, and it is exactly what neither a bare self-managed cluster nor a bare serverless database provides on its own.
Trade-offs and pitfalls
- Treating the proxy as optional, "we'll add it if connections become a problem," is the most common mistake here: connection exhaustion under a real burst is a hard failure mode, not a gradual degradation, so it needs to be designed in up front, not bolted on after an incident.
- Keeping the database warm to avoid stacked cold starts partially undercuts the cost-elasticity argument for going serverless in the first place; that is a real trade to make consciously, not a free win.
- Underestimating the application-side rework (retry logic, removing session-state dependencies) as "just an infrastructure migration" is how these migrations run over their planned timeline; budget for it as application work, not as a deployment configuration change.
A vendor offers a managed distributed SQL database that promises automatic sharding and rebalancing. List 6 operational questions you would ask before adopting it for a latency-sensitive transactional service.
Sample Answer
Direct answer
Six questions cover the ground a "handles sharding and rebalancing automatically" pitch conveniently skips: what latency the vendor will actually guarantee under your transaction shape, whether rebalancing degrades live traffic or pauses it, what the replication and consistency model implies for data loss and recovery time, how visible internal topology changes are to your own monitoring, how the system behaves when it cannot reach a quorum (a majority of replicas agreeing before a write counts as durable), and how hard it would be to leave. Ask all six framed against "latency-sensitive transactional," not as a generic vendor-diligence checklist: an answer that would satisfy an analytics workload can still be a bad fit here.
The six questions
| # | Question | Why it matters for a latency-sensitive transactional workload | Red flag in the vendor's answer |
|---|---|---|---|
| 1. Latency guarantee and measurement basis | "What 99th-percentile (P99) commit latency do you guarantee for a single-row transactional write, under a documented workload similar to mine, and is that backed by a service-level agreement (SLA) with a financial remedy?" | Distributed SQL databases add a consensus round trip (a network exchange where a quorum of replicas must acknowledge a write) on every commit. The number that matters is the tail latency of a small, single-row transaction, not an average and not a number measured on a large analytical batch. | Vendor quotes only mean or median latency, or a benchmark run on multi-row batch writes instead of the small single-row commits typical of a transactional service. |
| 2. Rebalancing impact on live traffic | "When the cluster rebalances automatically (a node joins, a hot shard splits, a failed replica is repaired), does the affected data stay fully read and write available, or does the system pause or throttle traffic on the piece being moved? Can rebalancing be rate-limited or scheduled away from peak hours?" | Rebalancing moves a shard (a contiguous chunk of the table's rows, grouped by key range) from one node to another by streaming a full copy of it across the network. Left unthrottled, that transfer competes with production traffic for network and CPU capacity right when the cluster's internal state is least predictable. This is not hypothetical: even mature distributed SQL engines have shipped rebalancing paths where an ordinary configuration change measurably degraded foreground query latency before the vendor patched it. | Vendor cannot describe a concrete rate-limiting or scheduling mechanism, or only offers "it is usually fine in practice." |
| 3. Replication, consistency, and disaster-recovery implications | "What is the default replication factor and quorum size per shard, what consistency guarantee does a client get by default (strict ordering across all replicas versus eventual convergence), and what recovery point objective (RPO, how much recent data could be lost) and recovery time objective (RTO, how long recovery takes) does that imply if a region fails mid-transaction?" | "Automatic sharding" says nothing about whether each shard's replicas live in one region (fast, but a regional outage can lose recent writes) or are kept in sync across regions by a global consensus protocol (safer, but adds real latency to every commit). | Vendor cannot state RPO or RTO as numbers, or uses "highly available" and "zero data loss" interchangeably. |
| 4. Observability into internal topology changes | "What real-time visibility exists into shard splits, leader elections (which replica currently owns the right to accept writes for a shard), and in-progress rebalancing, and can a latency spike in my own application performance monitoring (APM) tooling be correlated back to a specific internal event?" | If the database's internal reshuffling is invisible, a 2 a.m. latency spike looks identical to an application bug, and an on-call engineer burns an hour ruling out their own code before learning the database moved a shard underneath them. | Vendor offers only an aggregate cluster-health dashboard with no exportable, timestamped events for splits, elections, or rebalances. |
| 5. Failure-mode behavior | "During a network partition or a quorum loss on a shard, does the system fail closed (refuse writes, to stay consistent) or fail open (keep accepting writes on a stale replica)? Does failover for a lost leader happen automatically, or does it require a manual runbook step?" | For a transactional service, a database that fails open during a partition can accept writes that conflict or silently overwrite each other, surfacing as corrupted business state days later. That is worse than a short, honest availability gap. | Vendor cannot describe the failure mode precisely, or the answer implies writes are accepted during a partition "to keep availability high." |
| 6. Data portability and exit strategy | "If the contract ends, is export a native logical dump, a wire-protocol-compatible export another engine can read, or a proprietary snapshot only the vendor's own restore tooling understands? Who controls the encryption keys, and how long would extracting the full current data volume take at the vendor's stated export throughput?" | Automatic sharding and rebalancing are exactly the features that make a vendor's on-disk storage format the least portable. Verifying the exit path before signing is far cheaper than discovering it during a forced migration. | Vendor's export path is undocumented, or only supports restoring into their own product. |
Worked example
Take a payments authorization service: 3,000 transactions per second, a 40 ms P99 commit latency SLA of its own, and a requirement to survive a full region outage, so the team is evaluating a three-region deployment spanning, say, New York and San Francisco.
Question 1 asks the vendor for a P99 commit latency guarantee. Before even hearing their number, it is worth computing the physics floor a synchronous cross-region quorum write cannot beat, because no amount of engineering can get a commit acknowledgment back faster than light travels through fiber:
# Physics floor on cross-region consensus commit latency: a sanity check on any
# vendor SLA number, not a benchmark. All inputs are stated explicitly below.
great_circle_km = 4130 # approx. New York <-> San Francisco great-circle distance
routing_factor = 1.5 # real fiber paths run longer than the great circle
fiber_path_km = great_circle_km * routing_factor
speed_of_light_vacuum_km_s = 299_792
refractive_index_fiber = 1.5 # typical single-mode fiber
speed_in_fiber_km_s = speed_of_light_vacuum_km_s / refractive_index_fiber
one_way_ms = (fiber_path_km / speed_in_fiber_km_s) * 1000
round_trip_ms = one_way_ms * 2
print(f"fiber path length: {great_circle_km} km x {routing_factor} = {fiber_path_km:.0f} km")
print(f"speed in fiber: {speed_of_light_vacuum_km_s} / {refractive_index_fiber} = {speed_in_fiber_km_s:,.0f} km/s")
print(f"one-way propagation time: {fiber_path_km:.0f} km / {speed_in_fiber_km_s:,.0f} km/s = {one_way_ms:.3f} ms")
print(f"round trip (quorum ack floor): {one_way_ms:.3f} ms x 2 = {round_trip_ms:.2f} ms")
Output:
fiber path length: 4130 km x 1.5 = 6195 km
speed in fiber: 299792 / 1.5 = 199,861 km/s
one-way propagation time: 6195 km / 199,861 km/s = 30.996 ms
round trip (quorum ack floor): 30.996 ms x 2 = 61.99 ms
A round trip between New York and San Francisco alone costs about 62 ms, before any disk write, queueing, or server-side processing. If the vendor's answer to question 1 is "P99 commit latency under 40 ms" and question 3 reveals that every commit needs a quorum acknowledgment from a replica in the other region, those two answers contradict each other: the deployment cannot meet its own stated SLA. The honest fix is either to keep the write quorum inside one metro region (propagation delay measured in fractions of a millisecond) and replicate to the far region asynchronously for disaster recovery only, accepting a small, named RPO, or to relax the latency SLA. Either is a legitimate design choice; a vendor who does not surface this tension when questions 1 and 3 are asked together has not actually answered the question.
Trade-offs and pitfalls
The most common wrong turn is accepting a vendor's self-reported questionnaire as verification. A "yes" to all six questions from a sales engineer is not evidence: insist on a proof-of-concept load test that replays the actual read/write mix and transaction size against the vendor's cluster, sized to the real data volume, while watching P99 latency through a real rebalance (add a node, kill a replica, and observe). "Distributed" and "managed" are not synonyms for "safe for latency-critical transactions": consensus overhead, rebalancing behavior, and failure-mode defaults vary enormously between vendors, and that is exactly the corner of the evaluation a generic due-diligence checklist glosses over.
Compare provisioned capacity (reserved throughput) with serverless/autoscaling models for DynamoDB and Aurora Serverless v2. Discuss cost predictability, latency characteristics, cold-start behavior, throttling, operational overhead, and what kind of workload pattern each model suits best.
Sample Answer
Provisioned capacity means you reserve a fixed amount of throughput (how many read or write operations, or how much compute, the system can handle per second) up front and pay for it whether you use it or not; serverless/autoscaling means the service adjusts capacity to match load and you pay closer to actual consumption. The two managed products that expose this choice most directly are DynamoDB (provisioned throughput vs. on-demand) and Aurora (a fixed instance class vs. Serverless v2), and the right choice depends almost entirely on how predictable and how bursty the workload is.
DynamoDB: provisioned throughput vs. on-demand
| Provisioned | On-demand | |
|---|---|---|
| Cost predictability | High: you set read capacity units (RCU) and write capacity units (WCU) and pay a flat rate for them | Lower: billed per request, cost tracks traffic directly, which is predictable only if traffic is predictable |
| Latency | Same single-digit-millisecond latency as on-demand; capacity mode does not change per-request latency | Same latency profile as provisioned |
| Throttling behavior | Requests beyond provisioned capacity are throttled (ProvisionedThroughputExceededException) unless application auto scaling is configured, and auto scaling reacts to a CloudWatch alarm on a delay, not instantly | Scales automatically to serve the traffic, but a sudden spike well beyond the table's recent peak can still see brief throttling until DynamoDB provisions more partitions behind the scenes |
| Operational overhead | You own setting and tuning target utilization for auto scaling, and re-tuning it as traffic patterns shift | Effectively none: no capacity numbers to manage |
| Best workload pattern | Steady, forecastable traffic where the flat provisioned rate beats per-request pricing | Spiky, new, or hard-to-forecast traffic, or a small table where operational simplicity matters more than shaving cost |
Aurora: provisioned instance vs. Aurora Serverless v2
| Provisioned | Serverless v2 | |
|---|---|---|
| Cost predictability | High: fixed instance-class price regardless of load | Variable: billed in Aurora capacity unit (ACU) hours, each ACU is roughly 2 gibibytes (GiB) of memory plus corresponding CPU and networking, measured every second |
| Latency characteristics | Constant, matches the chosen instance class | Same engine, same query latency at a given capacity; latency only changes if the workload outgrows the current ACU level faster than it can scale up |
| Cold-start behavior | None: capacity is always provisioned | None for the normal 0.5 to 256 ACU scaling range, since scaling happens in place (typically the same host) without dropping connections; a cold-start-like delay only appears if you opt into "scale to zero" (available on newer engine versions with a minimum of 0 ACUs) and the cluster has to resume from a fully paused state |
| Throttling | N/A: fixed capacity either handles the load or the instance is CPU/memory saturated | Scales up automatically in increments as small as 0.5 ACU as load increases; a very sudden spike can still see brief elevated latency while capacity catches up, but there is no hard throttling wall the way DynamoDB provisioned mode has |
| Operational overhead | Manual: resizing the instance class is a deliberate, brief-outage operation you schedule | Low: you set a minimum and maximum ACU range once and the service scales within it continuously |
| Best workload pattern | Steady-state OLTP (online transaction processing) load where you can predict peak capacity and want the most predictable bill | Spiky or unpredictable workloads (promotions, seasonal traffic, dev/test environments that sit idle most of the day) where paying for idle provisioned capacity would be wasteful |
Worked example: turning a workload into numbers
DynamoDB. Say a product-catalog table needs to sustain a peak of 800 strongly consistent reads/sec (items averaging 3 KB) and 150 writes/sec (items averaging 1.5 KB). DynamoDB charges 1 RCU (read capacity unit) per strongly consistent read of an item up to 4 KB, and 1 WCU (write capacity unit) per write of an item up to 1 KB, rounding each item up to the next chunk boundary:
import math
peak_reads_per_sec = 800
peak_writes_per_sec = 150
read_item_kb = 3
write_item_kb = 1.5
rcu_per_read = math.ceil(read_item_kb / 4) # 3KB fits in one 4KB chunk -> 1 RCU
wcu_per_write = math.ceil(write_item_kb / 1) # 1.5KB needs two 1KB chunks -> 2 WCU
read_rcu_per_sec = peak_reads_per_sec * rcu_per_read
write_wcu_per_sec = peak_writes_per_sec * wcu_per_write
headroom = 1.2 # 20% buffer above measured peak
provisioned_rcu = math.ceil(read_rcu_per_sec * headroom)
provisioned_wcu = math.ceil(write_wcu_per_sec * headroom)
print(f"Peak RCU/sec needed: {read_rcu_per_sec}")
print(f"Peak WCU/sec needed: {write_wcu_per_sec}")
print(f"Provisioned RCU to reserve (20% headroom): {provisioned_rcu}")
print(f"Provisioned WCU to reserve (20% headroom): {provisioned_wcu}")
Peak RCU/sec needed: 800
Peak WCU/sec needed: 300
Provisioned RCU to reserve (20% headroom): 960
Provisioned WCU to reserve (20% headroom): 360
Under provisioned capacity, you reserve and pay for 960 RCU and 360 WCU every hour of the day, including overnight when actual traffic might fall to 50 reads/sec and 10 writes/sec (50 RCU and 20 WCU, under 6% of what is provisioned). Under on-demand, you are billed only for the RCU and WCU each request actually consumes, so that overnight trough costs proportionally less, at a higher per-unit rate for whichever units you do consume. This is the concrete version of the "idle capacity" trade-off in the table above: provisioned wins when the 800/150 peak is close to the round-the-clock average, on-demand wins when it is not.
Aurora Serverless v2. Say a workload idles near the 1 ACU minimum for 20 hours a day and spikes to 8 ACU for a 4-hour business-hours peak. An Aurora capacity unit (ACU) is billed per second, in ACU-hours:
idle_hours, idle_acu = 20, 1
peak_hours, peak_acu = 4, 8
daily_acu_hours = idle_hours * idle_acu + peak_hours * peak_acu
rate_per_acu_hour = 0.12 # AWS's published Aurora Serverless v2 rate, us-east-1 at time of writing; check current pricing for your region
daily_cost = daily_acu_hours * rate_per_acu_hour
monthly_cost = daily_cost * 30
provisioned_daily_acu_hours = 24 * peak_acu # a fixed instance sized for the peak, running all day
provisioned_monthly_cost = provisioned_daily_acu_hours * rate_per_acu_hour * 30
print(f"Serverless v2 ACU-hours/day: {daily_acu_hours}")
print(f"Serverless v2 monthly compute cost: ${monthly_cost:,.2f}")
print(f"Fixed-at-peak monthly compute cost: ${provisioned_monthly_cost:,.2f}")
Serverless v2 ACU-hours/day: 52
Serverless v2 monthly compute cost: $187.20
Fixed-at-peak monthly compute cost: $691.20
For this bursty, mostly-idle shape, Serverless v2 costs about 73% less than a provisioned instance sized to never fall short at the 4-hour daily peak, because the provisioned instance bills for 8-ACU-equivalent capacity for all 24 hours whether the workload needs it or not. A workload that instead sat near 8 ACU around the clock would flip this: Serverless v2 would bill close to the same 192 ACU-hours/day as the provisioned option, at a higher per-ACU-hour rate, making the fixed instance the cheaper choice.
Trade-offs and pitfalls
- Provisioned capacity is not "safer," it is differently risky: undersized provisioned throughput throttles real user traffic with a hard error, while serverless/on-demand's failure mode is a cost spike or brief latency bump, not a hard rejection. Which failure mode is worse depends on whether the business cares more about a predictable bill or never dropping a request.
- On-demand and Serverless v2 both have a per-unit price premium over well-utilized provisioned capacity. The trade only pays for itself when the workload's peak-to-average ratio is high enough that you would otherwise be paying for a lot of idle provisioned headroom; for a genuinely flat, 24/7 workload, provisioned is usually cheaper.
- Aurora Serverless v2's scale-to-zero option is attractive for dev/test but is a different feature from its normal 0.5 to 256 ACU scaling: only enable it where an occasional resume delay is acceptable, not on anything customer-facing.
- Mixing modes inside one system is a legitimate design, not a compromise: for example, a steady OLTP writer on a provisioned Aurora instance with Serverless v2 read replicas that scale independently to absorb bursty reporting traffic, or a DynamoDB table on provisioned capacity for its steady core traffic with on-demand reserved for a table that only exists to catch spiky, unpredictable event ingestion.
Explain what a managed database service is, and describe the primary trade-offs of using one (for example Amazon RDS/Aurora, Cloud SQL, DynamoDB) compared to self-hosting a database. For each trade-off, say what the cloud provider takes on and what stays the team's job, and give one concrete example of a choice that materially affected reliability or cost.
Sample Answer
A managed database service is one where the cloud provider operates the database engine on your behalf: it provisions the compute and storage, patches the host operating system and engine, runs automated backups, handles hardware failure and (if you turn it on) failover (automatically switching traffic to a healthy standby when the primary fails), and exposes a connection endpoint plus a control plane API instead of shell access to a box. Amazon RDS/Aurora and Google Cloud SQL are managed relational database services (structured tables, SQL, joins), while DynamoDB is a managed NoSQL key-value store (no fixed schema, no joins, items looked up by key), a fundamentally different kind of database. All three still count as "managed" in the sense used here: the provider operates the engine so your team doesn't have to. The core trade-off is that you give up low-level control (custom kernel tuning, exotic extensions, root access) in exchange for offloading undifferentiated operational work, at a price premium, and with the provider dictating the maintenance windows and upgrade cadence you have to plan around.
What the provider takes on vs. what stays your job
| Responsibility | Provider (managed service) | Still your job |
|---|---|---|
| Physical hardware, host OS patching | Yes | No |
| Engine minor-version patching | Yes, applied in a maintenance window | Choosing that window and testing compatibility first |
| Automated backups / snapshots | Yes, taken on a schedule | Verifying you can actually restore to your target recovery point objective (RPO), and testing that restore |
| High availability / failover orchestration | Yes, if you provision it (for example RDS Multi-AZ) | Deciding whether to pay for it, and making the app reconnect cleanly after a failover |
| Storage durability | Yes | Choosing storage type, size, and IOPS (input/output operations per second) for the workload |
| Schema design, indexing, query tuning | No | Entirely yours |
| Connection management | No | Pooling, sizing max connections, avoiding connection storms |
| Capacity planning / instance sizing | No | Entirely yours |
| Encryption mechanics (turning it on, managing keys) | Yes, once requested | Key policy, network exposure, credential rotation |
| Cost | You pay for the abstraction | Rightsizing and ongoing cost control are still yours |
The one-line version: the provider owns keeping the box alive. Your team still owns making the database correct, fast, and affordable for your specific workload. Nothing about "managed" removes the need for someone who understands query plans, isolation levels, or the data model.
Worked example: a concrete reliability and cost trade-off
A team running Amazon RDS for PostgreSQL decides against enabling Multi-AZ to save the roughly 2x compute cost of running a synchronous standby, reasoning that "RDS already takes automated backups, so we're covered." RDS's automated backups upload transaction logs to S3 (Amazon's object storage service) every 5 minutes, so in the single-AZ configuration the real RPO after an availability zone (AZ, an isolated data center within a cloud region) impairment is up to 5 minutes of lost writes, plus however long it takes to notice the instance is down and restore from the latest restorable point. The recovery time objective (RTO, how long recovery takes) is however long a full restore-from-snapshot takes for that data volume, easily tens of minutes for a large database. With Multi-AZ enabled, the standby is kept current by synchronous replication (the primary does not acknowledge a write until the standby has it too), so failover loses effectively no committed data, and AWS states that a Multi-AZ DB instance failover happens "as quickly as 60 seconds," with most failovers completing within one to two minutes. Skipping Multi-AZ was a deliberate cost/reliability trade: it saved money every month, but it converted "a few minutes of trouble" into "a real outage with real data loss" the one time an AZ actually failed. Neither choice is universally wrong: for a staging database that trade is probably fine; for the primary store behind checkout, it usually is not.
Trade-offs and pitfalls
- Managed does not mean hands-off. Query performance, index design, and data modeling determine most of what actually breaks in production, and none of that is automated away by the provider.
- "It's backed up" is not the same as "it meets our RPO." Point-in-time recovery from 5-minute log shipping is a materially weaker guarantee than a synchronous standby. Know which one you are actually relying on before an incident, not during one.
- Self-hosting keeps some levers a managed service takes away: custom compiled extensions, OS-level tuning (filesystem choice, kernel parameters), and full superuser access. If a workload genuinely needs one of those, that is a real reason to self-host, not just inertia.
- The cost model shifts from mostly fixed infrastructure and ops spend to a metered bill driven by instance size, storage, IOPS, and backup retention. A managed service can be cheaper than the fully loaded cost of an in-house operations team, or more expensive than a lean self-hosted setup at very large, steady scale. The crossover point depends on team size and existing operational maturity, not a universal rule.
Unlock Full Question Bank
Get access to all 20 Cloud and Managed Database Services interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.