genaipros← The path
Line D · CloudC5 · Storage & Data
Cloud for GenAI · Line D · C5 of the curriculum

Storage & Data

Where the state goes once C3 made your compute stateless. Four sessions: the neutral taxonomy and the consistency axes, then object/block/file across three clouds, then relational, then NoSQL & analytics. Concepts before consoles, always.

Vendor-neutral firstAWS · Azure · GCP3-pass teaching Grounded July 2026GenAI-infra apply-it
00 What this stage is for

There is no “best” storage. There is only fit — and the bill follows the fit.

Every storage service on every cloud exists because some workload has an access shape: how big the unit of data is, how often you touch it, whether many machines touch it at once, whether readers must agree, and how fast you need it back. Match the shape and things are cheap and fast. Mismatch it and you get one of two failure modes, and only one of them is visible on a dashboard:

Failure mode 1 · loud

Broken latency

You put a database's write-ahead log on object storage, or you serve interactive reads from an archive tier. The application is slow or simply doesn't work. You find out in minutes.

Failure mode 2 · silent

10× cost

You keep 400 TB of never-read logs on the hot tier, or you archive backups you delete after 30 days and pay the 90-day minimum on every one. Nothing breaks. You find out at month end, or never.

Callback · C3 Stateless compute pushed all state off the instances. This stage is where that state landed. Every “the container is disposable” claim you made in C3 is a promise that something in this tier is durable, reachable, and consistent enough. Block storage attaches to those C3 VMs; buckets and databases are reached over C4 private endpoints and governed by C2 IAM.
01 The framing visual · taxonomy + database zoo

Two maps you will use for the rest of your career. The top row is raw storage — three access shapes. The bottom block is the database zoo — engines that add concurrency control and query on top of that raw storage so your application doesn't have to. Hover or tap any box for what it is.

Interactive — hover / tap a box
RAW STORAGE — three access shapes BLOCK a raw disk · one machine unit: 512 B – 4 KiB block, by number wins: lowest latency, random I/O, IOPS loses: not shared, capped size, per-GB dear blocks 0,1,2,3 … addressed by offset FILE a shared tree · many machines unit: a file at a path, byte-range writes wins: POSIX semantics, concurrent mounts loses: protocol latency, metadata at scale /models/gemma/weights.safetensors OBJECT key → blob · anything with HTTP unit: whole object + metadata, by key wins: infinite scale, cheapest GB, tiers loses: no partial write, per-request fees GET s3://weights/gemma-2-9b/model.safetensors databases sit on top of raw storage and add concurrency control + query THE DATABASE ZOO — five shapes of managed state RELATIONAL rows · schema · joins · ACID AWS RDS / Aurora Azure SQL Database Cloud SQL / AlloyDB Spanner (global) DOCUMENT JSON records · flexible schema DynamoDB · DocumentDB Cosmos DB (NoSQL API) Firestore KEY–VALUE hash map · one access path DynamoDB · ElastiCache Azure Managed Redis · Table Memorystore (Valkey/Redis) WIDE-COLUMN sorted row key · sparse columns Keyspaces (Cassandra) Cosmos DB (Cassandra API) Bigtable ANALYTICS columnar · scan-optimised Redshift · Athena Fabric / Synapse BigQuery THE THREE AXES YOU TRADE ON DURABILITY will I lose the data? bought with: replica count & spread AVAILABILITY can I reach it now? bought with: failure domains + failover CONSISTENCY will every reader agree? bought with: coordination = latency
Hover or tap a box above for a one-line definition.
The single most useful habit from this stage: before naming any service, say the shape out loud — “this is a whole-object, write-once, read-rarely access pattern” — and the service almost picks itself.
02 How the four sessions build

Each tab is self-contained and follows the same five beats: why it exists → core concepts (neutral, then three clouds) → reality check with real numbers → apply it to your GenAI stack → bridge.

03 The materials · verified against their own tables of contents
SourceYou saidActual section titleVerdict
the cloud application patterns catalog
a cloud patterns catalog
§7§7 — Cloud-Native StorageCorrect. Root pattern is Cloud Database; thirteen patterns. It is the neutral spine for S1.
AWS architecture guidance
AWS guidance
§5§5 — AWS Service OverviewCorrect number, but §5.3 Storage / §5.4 Databases is a service catalogue, not a depth section. Supplemented — see note below.
Mastering Azure
vendor guidance, vendor guidance, vendor guidance
§6 + §11§6 — Storage; §11 — Databases and Big Data SolutionsCorrect. §6 is the strongest storage section of the four (accounts, tiers, LRS/ZRS/GRS/GZRS, disks, Elastic SAN).
Ultimate Google Professional Cloud Architect
GCP guidance
§3 + §9–10§3 — GCP Storage Infrastructure (Block, File, and Object); §9 — Databases in GCP Overview; §10 — Relational, NoSQL, and Caching DatabasesCorrect. One addition: §13 — Exploring Data Warehousing and Data Lifecycle on GCP is the natural source for the S4 analytics section, so I pulled from it too.
Numbering needed no corrections. Titles above are as printed in each source's own contents.
Declared up front · AWS §5 depth You anticipated this and you were right. AWS §5 introduces S3, EBS, Glacier, FSx, RDS, DynamoDB and Aurora at roughly a paragraph each; it never enumerates the S3 storage classes, never mentions EFS in the storage section (it covers FSx instead), and predates S3 Express One Zone and Aurora DSQL entirely. Everywhere S2 and S3 go past that catalogue depth, the source is current AWS documentation and pricing, not the material, and I've flagged it in-tab.
04 What has drifted since the materials were written

Cert guides age fastest on exactly the three things this stage is about: storage class names, database product names, and per-GB / per-request prices. Here is the stage-level ledger; each tab repeats the relevant rows with sources.

AreaWhat a 2024-era source saysCurrent as of July 2026
GCP blockPersistent Disk types (pd-standard, pd-balanced, pd-ssd, pd-extreme)Hyperdisk is the recommended family and Persistent Disk is not available on the newest machine series at all. Types: Balanced, Balanced High Availability, Extreme, Throughput, and Hyperdisk ML — a read-only volume attachable to many instances, built for model weights and training data.
GCP objectFour classes: Standard / Nearline / Coldline / ArchiveStill four for the temperature ladder, plus a zonal Rapid storage class (Rapid Bucket) aimed at AI/ML, plus Rapid Cache (the renamed Anywhere Cache) and Autoclass. Multi-region Nearline went up and multi-region Archive went down in 2026 — old lifecycle policies may no longer be optimal.
AWS relationalRDS, Aurora, Aurora ServerlessAurora Serverless v2 now scales to 0 ACUs, and Aurora DSQL — a serverless, active-active, multi-region-strongly-consistent PostgreSQL-compatible distributed SQL database — went GA on 27 May 2025. It is AWS's answer to Spanner and it is not in any of the materials.
AWS NoSQLProvisioned is much cheaper than on-demandAWS cut on-demand throughput prices by 50% (Nov 2024) and added Database Savings Plans (Dec 2025). The old “always start provisioned” advice is now wrong for most spiky workloads. DynamoDB global tables also gained multi-region strong consistency (GA June 2025).
Azure cacheAzure Cache for RedisAzure Managed Redis is the successor. Azure Cache for Redis Enterprise retires 30/31 March 2027; Basic, Standard and Premium retire 30 Sept 2028. Any exam answer or design that names “Azure Cache for Redis” for new build is already stale.
Azure analyticsAzure Synapse Analytics is the warehouseSynapse is supported but is maintained, not evolved; Microsoft Fabric is where net-new investment goes. Specific components are already retired (Synapse Data Explorer → Fabric Eventhouse; Synapse Link for Cosmos DB → Cosmos DB mirroring in Fabric).
GCP databasesCloud Spanner, Firestore, Memorystore for Redis/MemcachedSpanner now sells in editions (Standard / Enterprise / Enterprise Plus) and is multi-model (graph, full-text, vector). Firestore has Standard and Enterprise editions with MongoDB compatibility. Memorystore for Valkey joined Redis and Memcached.
Sources cited per row inside the relevant session tab.
05 Where you should be at the end

You can decide

  • Block, file or object for a given piece of data — from the access shape, not from habit.
  • SQL vs document vs key-value vs wide-column vs cache for a given workload.
  • Regional vs multi-region vs global for a database, deliberately, knowing the write-latency price.
  • Which object storage class, including whether the retrieval and minimum-duration rules kill the saving.

You can translate

  • S3 ⇄ Blob ⇄ Cloud Storage · EBS ⇄ Managed Disks ⇄ Hyperdisk · EFS ⇄ Files ⇄ Filestore.
  • RDS/Aurora ⇄ Azure SQL ⇄ Cloud SQL/AlloyDB · DynamoDB ⇄ Cosmos DB ⇄ Firestore/Bigtable.
  • Durability/availability/consistency claims into replica topology.
  • Your own stack: weights, datasets, checkpoints and pipeline state onto the right service on each cloud.
Start here →

Session 1 is entirely vendor-neutral on purpose. Everything in S2–S4 is a dialect of it; if S1 lands, the other three tabs are mostly vocabulary.

S1 · 01 Why this session exists

Storage is dumb on purpose. Databases are the thing that makes it usable.

the patterns catalog's Cloud-Native Storage section opens with the problem you inherited from C3: a stateless application still has state, so where does it go? His answer is blunt — raw storage looks tempting, and it is ultimately where every byte lands, but raw storage fails applications on two counts.

Concurrency

Storage handles one reader or one writer beautifully. Two threads writing the same region at once corrupt it; a reader mid-write sees a torn value. And you always have concurrency, because C3's replicas of your service all share the same data.

Querying

Storage can hand you a thing if you know exactly where it is. Ask it “which rows match this predicate” and the only implementation is: read everything, filter in your app. That is fine at 10 MB and ruinous at 10 TB.

So this session teaches two layers at once — the raw storage taxonomy (block / file / object), and the database zoo that sits on top of it — plus the three axes (durability, availability, consistency) you trade along in both. Vendor-neutral throughout. No console, no service names except as illustrations, until Session 2.

Source note The spine of this tab is the cloud application patterns catalog — its Cloud Database root pattern, its Replicated Database / Application Database / polyglot-persistence framing, and its CA/AP/CP summary. The block/file/object anatomy and the PACELC extension are supplemented, because §7 treats raw storage briefly on its way to databases.
S1 · 02 Core concept 1 · block vs file vs object
Pass 1 Intuition

Three ways to be given somewhere to put things.

Block

An empty warehouse floor with numbered bays. Nobody organises it for you. You bring your own shelving system (a filesystem), you decide what goes in bay 4,192, and you're the only tenant with a key. Fastest possible access because there's no middleman.

File

A shared office filing cabinet. Folders, labels, a rule that two people can't scribble on the same page at once. Everyone in the building can walk up and use it. Slower than your own drawer, but everyone speaks the same language.

Object

A coat check. You hand over a whole coat and get a ticket. To change a button you take the whole coat back, sew, and hand in a whole new coat. Unlimited racks, dirt cheap, and there's a cheaper long-term room out back with a delay to fetch from it.

Pass 2 Mechanism

The difference is what the API's unit of work is, and that single fact cascades into everything else.

Interactive — hover / tap a lane
CLIENT PROTOCOL WHAT THE SERVICE STORES ONE VM · its own kernel app → filesystem (ext4/XFS/NTFS) → device NVMe / iSCSI · block protocol "write 4 KiB at LBA 102 400" — no filenames A VOLUME = an array of blocks replicated inside ONE zone (usually) sized + performance-provisioned up front measured in IOPS and MB/s one writer · lives or dies with its zone MANY VMs / PODS all mount the same path, concurrently NFS / SMB · file protocol open · stat · lock · write bytes 900–1400 A FILESYSTEM = a tree + locks service owns metadata & arbitrates writers grows elastically, no pre-sizing POSIX semantics your software expects many writers · metadata ops are the tax ANY CLIENT, ANYWHERE SDK, curl, a browser, a training job HTTPS · REST PUT /bucket/key · GET /bucket/key A BUCKET = flat key → blob whole-object writes, atomic, versioned replicated across zones by default priced per GB + per request + per retrieval unlimited · no partial write · tiered
Hover or tap a lane for how the write actually travels.
Terms defined at first use
IOPS
Input/output operations per second — how many separate reads or writes a device sustains. The metric that matters when operations are small and scattered (a database index lookup).
Throughput
Bytes per second, usually MB/s or GB/s. The metric that matters when operations are large and sequential (streaming a 40 GB checkpoint).
Latency
Time for one operation to complete. Block ≈ tens–hundreds of microseconds; file ≈ sub-millisecond to low milliseconds; object ≈ tens of milliseconds for first byte.
LBA
Logical block address — the “bay number” in block storage. The unit the device API addresses.
POSIX
The Unix file API contract: paths, permissions, seek, partial writes, locks, rename-is-atomic. Software that expects a “real filesystem” is expecting POSIX.
Namespace
How names are organised. File storage is hierarchical (a tree). Object storage is flat — one giant dictionary of keys.
Prefix
The leading part of an object key (logs/2026/07/). Used for pseudo-folders, lifecycle scoping and request-rate partitioning.
Pass 3 Trade-offs, limits, and where it breaks
DimensionBlockFileObject
Unit of writeA block (512 B – 4 KiB)A byte range in a fileThe whole object
Concurrent writersOne machine (multi-attach exists but needs a cluster-aware filesystem)Many, arbitrated by the serviceMany, but last-write-wins on the same key
Typical latency~0.1–1 ms~0.5–10 ms~10–100 ms first byte
Order-of-magnitude cost / GB-month$0.08 – $0.13$0.16 – $0.30 hot tier$0.001 – $0.023
Capacity ceilingPer-volume cap (tens of TB)Effectively elasticEffectively unlimited
Failure domain by defaultOne zoneOne or many zones (choose)Multi-zone, often multi-region
Breaks when…You need two machines to write, or you exceed the volume's provisioned IOPS and every query stalls behind the queueYou do millions of small-file metadata ops, or you assume it's as cheap as object storageYou need to modify part of a large file, need <5 ms reads, or your access pattern is millions of tiny objects (per-request fees and per-object metadata overhead dominate)
Cost bands are order-of-magnitude for orientation only; exact 2026 numbers per cloud are in Session 2.
Advanced nuance · the three “gotcha” facts most people learn the hard way

1. Object storage is not a filesystem, and mounting it doesn't make it one. FUSE-style mounts (s3fs, Cloud Storage FUSE, BlobFuse) present a bucket as a path. They are genuinely useful — Google reports large training-throughput gains from theirs — but under the hood a partial write is still a full object rewrite and a directory listing is still a prefix scan. Never put a database, a git repo, or an SQLite file on one.

2. Provisioned block performance is a queue, not a speed limit you politely approach. If a volume is provisioned for 3,000 IOPS and your workload asks for 6,000, you don't get “half speed”; you get a queue, and queue depth turns into multi-second p99 latency. Storage saturation almost always presents as an application timeout, not a storage alarm.

3. Small objects are the silent killer. Archive tiers add fixed metadata overhead per object (on S3's Flexible Retrieval and Deep Archive, about 40 KB), and every class bills per request. A hundred million 8 KB objects can cost more in overhead and requests than the bytes themselves. Aggregate small files into shards or tar/WebDataset-style archives before tiering them.

Which raw storage class for this data?
Follow “no ↓” down the rail. First “yes” exits right. Bottom-left is the default.
  1. Does a single machine need a real filesystem it alone owns — an OS boot disk, a database's data files, a write-ahead log?
    yes →Block. Provision for IOPS if the I/O is small and random; provision for throughput (MB/s) if it is large and sequential.
    no ↓
  2. Do several machines need to read and write the same paths at the same time, with POSIX semantics and locking?
    yes →File. The usual honest reason is “the software I did not write insists on a path”. That is a legitimate reason.
    no ↓
  3. Do many readers need the same immutable artifact, with no partial updates — model weights, datasets, images, backups, logs?
    yes →Object. And now pick the class by access frequency — that is the second tree, in Session 2.
    no ↓
  4. Is the data really records you will query by attribute, update in place, and need transactionally consistent?
    yes →You are not choosing raw storage at all. Use a database — go to the second decision tree below.
    no ↓
Default
Object storage
When in genuine doubt, object storage is the right default: cheapest, most durable, most scalable, hardest to lose data on, and the only one of the three you can leave running for years without operational attention. Reach for block or file only when the access shape forces you to.
S1 · 03 Core concept 2 · durability vs availability vs consistency
Pass 1 Intuition

Three different questions that people constantly mash into the word “reliable”. Your bank:

  • Durability — will the bank still know I have £5,000 next year? (Did the bytes survive?)
  • Availability — is the ATM working right now? (Can I reach the bytes?)
  • Consistency — if I withdraw at one ATM and my partner checks the balance at another one second later, do they see the new number? (Do all readers agree?)

They are independent. A system can be perfectly durable and completely unavailable (your data is safe in a region that is on fire and unreachable). It can be highly available and inconsistent (every replica answers instantly, some with stale values).

Pass 2 Mechanism · all three are bought with copies, and copies cost coordination
Interactive — hover / tap a topology
1 · SINGLE COPY disk durability ≈ 99% availability ≈ one machine consistency trivially perfect 2 · 3 COPIES, ONE ZONE zone A survives: disk, host does NOT survive: zone loss write ack: local, fast 3 · ACROSS ZONES ABC survives: a whole datacentre cost: ~1–3 ms added per write 11 nines of durability lives here 4 · ACROSS REGIONS EU US 80 ms async → fast writes, RPO > 0 sync → RPO = 0, slow writes pick one. physics does not negotiate.
Hover or tap a topology.
Terms
Replication
Keeping more than one copy of the same data. Synchronous = the write isn't acknowledged until the copies land. Asynchronous = acknowledged first, copied after.
RPO
Recovery point objective — how much recent data you accept losing in a disaster, measured in time. Synchronous replication gives RPO = 0. Asynchronous gives RPO = replication lag.
RTO
Recovery time objective — how long you accept being down. A different dial from RPO, and usually the more expensive one.
Durability target
“Eleven nines” = 99.999999999% annual. Concretely: store 10 million objects and you'd expect to lose one about every 10,000 years. It is a design target from the replication maths, not an SLA with credits.
Availability SLA
A contractual monthly uptime percentage with service credits if missed. Typically 99.9%–99.99% for storage, and it is always a lower number than the durability figure.
Pass 3 Trade-offs · the numbers, and the thing nobody tells you
AvailabilityDowntime / monthDowntime / yearWhat it typically costs you
99%7 h 18 m3.65 daysA single instance you patch by hand
99.9% (“three nines”)43 m 50 s8.77 hManaged service, single zone
99.95%21 m 55 s4.38 hZone-redundant / Multi-AZ, automatic failover
99.99% (“four nines”)4 m 23 s52.6 mMulti-zone with no single write leader, or hot standby
99.999% (“five nines”)26 s5.26 mMulti-region active-active. Expensive, and mostly bounded by your code, not the platform's
Memorise the middle three rows. Architects quote nines constantly; most people can't convert them to minutes on the spot.
The thing nobody tells you · durability ≠ “I can't lose my data”

Eleven nines of durability protects against hardware loss. It does not protect against the four things that actually destroy production data:

  1. You deleted it. A rm -rf or a bad lifecycle rule is replicated to all eleven copies, faithfully and instantly. Mitigations: versioning, soft delete, object lock / immutability, and a retention policy you tested.
  2. Your application corrupted it. Same story — perfectly durable garbage. Mitigation: point-in-time restore, which is a database feature, not a storage one.
  3. Credentials were stolen. Mitigation is C2's, not this stage's: least-privilege IAM, separate delete permissions, MFA-delete, and backups in an account the primary credentials cannot reach.
  4. You never checked the restore worked. A backup you have not restored is a hypothesis.

Rule of thumb: durability is the platform's job; recoverability is yours.

S1 · 04 Core concept 3 · ACID, BASE, CAP and PACELC
Pass 1 Intuition

ACID — the ledger

A bookkeeper with a ruler. Either the whole entry goes in or none of it does; the materials always balance; two clerks can't half-write the same line; once it's inked, it survives a fire. Slower, and worth it when the numbers are money, inventory or medication doses.

BASE — the noticeboard

Anyone can pin a note anywhere, instantly. Different corridors briefly show different notices, and within a few seconds the building agrees. Wildly scalable, and completely fine for a social feed, a view counter, or a product catalogue.

CAP is the referee: when the network splits the building in half, you may keep answering (possibly with stale notes) or stay correct (by refusing to answer). Not both. PACELC is the honest follow-up question: fine — but what do you do the other 99.99% of the time, when the network is healthy? There you trade latency against consistency, and that trade is the one you live with every day.

Pass 2 Mechanism
Definitions
ACID
Atomicity (all or nothing), Consistency (constraints never violated), Isolation (concurrent transactions don't see each other's partial work), Durability (committed means committed).
BASE
Basically Available, Soft state, Eventually consistent. Not a weaker ACID — a different contract: prioritise answering, converge later.
CAP
Under a network Partition you must choose Consistency or Availability. Brewer's theorem. Crucially it says nothing about the non-partitioned case.
PACELC
“If Partition, then A or C; Else, Latency or Consistency.” The extension that describes normal operation, which is where you actually spend your life.
Quorum
A majority of replicas. Systems that stay consistent under partition do so by requiring a majority to agree (Paxos, Raft) — which is exactly why the minority side goes unavailable.
Sharding / partitioning
Splitting data across nodes by some key so each node owns a slice. The only way to scale writes horizontally — and the source of the hot-key problem in Session 4.
Interactive — hover / tap a corner or a chip
CONSISTENCY AVAILABILITY PARTITION TOLERANCE CA single-node / non-distributed CP consistent, may refuse AP always answers, may be stale CP · refuse rather than diverge RDBMS w/ sync replicas · MongoDB (majority) Spanner · Aurora DSQL · DynamoDB MRSC AP · answer, reconcile later Cassandra · ScyllaDB · CouchDB DynamoDB global tables (multi-active) CA · only if you assume no partitions i.e. a single node. tap for why.
Hover or tap a corner, a region label, or an example chip.
Placements are for the common configuration. Almost every modern database exposes tunable consistency, so the honest statement is “this product defaults to X and can be configured toward Y” — which is exactly what the patterns catalog warns about at the end of its CAP section.
Pass 3 Trade-offs · PACELC is the one you actually use

Partitions are rare. Latency is constant. So the useful question is almost never “what happens under partition” — it is “what does a read cost me when everything is fine?”

System shapePACELCWhat that means day to day
Single-region relational, sync replicasPC/ECCorrect always; every write pays cross-zone acknowledgement (~1–3 ms). Reads from replicas may lag unless you force the primary.
Globally distributed strong SQL (Spanner-class)PC/ECCorrect across continents; commit waits out clock uncertainty and cross-region quorum, so writes cost tens of ms. You buy correctness with latency, explicitly.
Multi-active NoSQL (Dynamo-style)PA/ELSingle-digit-ms reads and writes anywhere; a read may return a value a few hundred ms out of date. Fine for carts and feeds, wrong for ledgers.
Tunable multi-model (Cosmos-style)both, per requestYou pick the level per operation, and the price list literally charges you differently for it. Strong reads cost roughly double the request units of eventual reads.
The architect's move Don't choose a consistency level for “the database”. Choose it per operation. “Debit the account” is strong. “Show the recommendation carousel” is eventual. Systems that let you mix are usually the cheapest overall, because you only pay for coordination on the small fraction of calls that need it.
Step 1 of 5 — the write

A client in Frankfurt writes balance = 300

The write is accepted by the replica nearest to it. That replica now holds 300. The replicas in Virginia and Singapore still hold the old value, 500. Nothing is wrong yet — the write simply hasn't finished travelling. Physics: Frankfurt→Singapore is ~160 ms round trip at best.

Frankfurt replica300 ✓
Virginia replica500
Singapore replica500
Step 2 of 5 — eventual consistency

A reader in Singapore asks for the balance, 1 ms later

The local replica answers immediately from its own copy: 500. Stale, and the reader has no idea. This is the deal you signed up for. It cost one local disk read and roughly 1 ms.

Correct choice when: a feed, a view count, a catalogue, a recommendation. Wrong choice when: the number is money, seats, or stock.

Step 3 of 5 — strong consistency

Same reader, same moment, but the system is configured strong

The Singapore replica cannot answer alone. It must confirm with a quorum — which means a round trip toward the leader. The reader gets 300, correctly, after roughly 80–160 ms.

You did not eliminate the trade-off. You moved it from “possibly wrong” to “definitely slow”. That is the entire content of the “else” branch of PACELC.

Step 4 of 5 — convergence

250 ms later, everyone agrees

Frankfurt replica300 ✓
Virginia replica300 ✓
Singapore replica300 ✓

The “eventually” in eventual consistency is usually milliseconds, not minutes. The engineering question is never “is it eventually consistent?” — it is “what is the p99 replication lag, and what does a user see inside that window?” Design for the window: read-your-own-writes via session tokens, or route a user's reads to the region that took their write.

Step 5 of 5 — now the network splits

Frankfurt is cut off from the other two

AP system: Frankfurt keeps accepting writes; so does the Virginia/Singapore side. When the link heals you have two divergent histories and must reconcile — last-writer-wins silently discards one, which is how “my order vanished” bugs happen.

CP system: Frankfurt is in the minority, so it refuses writes and returns errors until the partition heals. Nothing is lost; some users are down. The majority side carries on.

Neither is “safer”. Choosing AP means choosing to write reconciliation logic. Choosing CP means choosing to write graceful-degradation logic. If you write neither, you've chosen by accident.

S1 · 05 Core concept 4 · OLTP vs OLAP
Pass 1 Intuition

OLTP (online transaction processing) is a shop till: thousands of tiny, precise operations per second, each touching one or two rows, each of which must be right. OLAP (online analytical processing) is the end-of-quarter review: one enormous question — “average basket size by region by week for three years” — that reads two columns out of a billion rows. Same data; opposite physics.

Pass 2 Mechanism · row store vs column store
ROW STORE (OLTP) — a whole record lives together on disk id=1 | name=Ada | region=EU | basket=42.10 | ts=… id=2 | name=Linus | region=US | basket=17.90 | ts=… id=3 | name=Grace | region=EU | basket=88.00 | ts=… “give me customer 2” → ONE seek, one block. Perfect. “average basket across 1e9 rows” → read every byte of every column you don't want. Ruinous. optimised for: point reads, updates in place, transactions, indexes on many columns COLUMN STORE (OLAP) — one column lives together, compressed id123 regionEUUSEU basket ★42.1017.9088.00 ts “average basket” → read ONE column, highly compressed. Seconds over a billion rows. “update customer 2's name” → rewrite a chunk of a column file. Expensive, so batched. optimised for: scans, aggregates, compression, massively parallel execution The pipeline: OLTP database → change-data-capture / batch export → object storage (the lake) → warehouse (OLAP) This is why object storage sits in the middle of every data platform. It is the neutral ground between the two physics.
Pass 3 Trade-offs

Two rules that will save you repeatedly:

  1. Never point your application's request path at a warehouse. Warehouse queries are billed and engineered for seconds-to-minutes and scanned bytes. A dashboard that refreshes per page-view against a columnar engine is a bill and a latency problem at the same time.
  2. Never run big analytics on your OLTP primary. A single unindexed aggregate can evict the working set from cache and take the whole transactional workload down with it. Route it to a read replica at minimum; export it to the warehouse properly.

The modern hybrid worth knowing: HTAP-ish features — a columnar cache or engine attached to the transactional database (Spanner's columnar engine, AlloyDB's columnar engine, Cosmos DB analytical store / Fabric mirroring) — that let you run analytics on operational data without an ETL hop. Useful, but they narrow the gap rather than close it.

S1 · 06 The second decision tree · which database shape
SQL vs document vs key-value vs wide-column vs cache — for this workload
Follow “no ↓”. First “yes” exits right. Bottom-left is the default.
  1. Is this a copy of data that lives authoritatively somewhere else, read far more than written, where being a few seconds stale is fine and losing it entirely is survivable?
    yes →Cache (in-memory key-value). Put a TTL on it. Never make it the only copy.
    no ↓
  2. Must several records change together, all-or-nothing — money moving, stock decrementing, a booking?
    yes →Relational. Multi-record ACID transactions with foreign keys are what it is for. If it must also be global and strongly consistent, that's the Spanner / Aurora DSQL class in Session 3.
    no ↓
  3. Will you query it in ways you cannot fully predict today — ad-hoc joins, new filters, a reporting layer you haven't designed yet?
    yes →Relational. A schema plus a query planner is precisely the tool for unknown future questions. NoSQL trades that flexibility away for scale.
    no ↓
  4. Is the access pattern “fetch or replace one self-contained record by its id”, with a shape that varies between records?
    yes →Document. Single-digit-ms at any scale, flexible schema. You must know your access patterns up front — the key design is the schema.
    no ↓
  5. Is it a firehose of time-ordered or entity-ordered events at very high write volume, always read as a contiguous range of one sort order?
    yes →Wide-column. Petabytes, millisecond writes, one physical sort order — so the row key is the whole design. Telemetry, metrics, feature stores.
    no ↓
  6. Is the primary question “how are these entities connected”, several hops deep?
    yes →Graph. Fraud rings, recommendations, permissions. Increasingly a mode of a general database rather than a separate product.
    no ↓
  7. Is it a large volume of historical records you scan and aggregate, but rarely update?
    yes →Analytics / warehouse. Columnar. Keep it strictly off the request path.
    no ↓
Default
A managed relational database
Boring on purpose. It gives you transactions, constraints, joins, a mature ecosystem and — most importantly — the ability to change your mind about how you query the data later. Modern managed Postgres handles far more scale than most teams assume, and it now also does JSON documents, full-text and vectors. Move off it when you have a measured reason, not an anticipated one. This is the same conclusion the patterns catalog reaches via Polyglot Persistence: split by data module, and only then pick a different engine per module.
S1 · 07 Lifecycle & tiering · the idea, neutrally

Object storage is priced along three independent dimensions, and tiering trades them against each other: storage (per GB-month), requests (per thousand operations), and retrieval (per GB read back, on cold classes only). Colder classes cut dimension one and inflate dimension three — plus they add a minimum storage duration you pay for whether or not the object survives that long.

Aging timeline

Hot / Standard — accessed daily

Highest per-GB price, no retrieval fee, no minimum duration, millisecond access. Everything is born here. Live model weights, active datasets, anything a user or a GPU is waiting on.

Aging timeline

Cool / Infrequent access — roughly monthly

Storage drops by around half; a modest per-GB retrieval fee appears; a ~30-day minimum duration appears. Still millisecond access — nothing changes operationally, only the bill. This tier is nearly free money for last quarter's logs.

Aging timeline

Cold / instant-retrieval archive — roughly quarterly

Storage drops another large step; retrieval fees rise sharply; minimum duration extends to ~90 days. Access is still immediate on the instant-retrieval variants. The breakeven maths matters here: if you read the data more than about once every five or six weeks, the retrieval fees exceed the storage saving.

Aging timeline

Archive / deep archive — yearly or never

An order of magnitude cheaper again — around a dollar per TB-month at the bottom. In exchange: you must issue a restore job and wait minutes to hours before you can read anything, and the minimum duration is 180 days (AWS/Azure) or 365 days (Google Cloud). Compliance archives, tape replacement, seven-year retention.

Aging timeline

Expiration — the rule most people forget to write

The single highest-leverage lifecycle rule is not a transition, it is a deletion. Data with no retention requirement and no reader should expire. Also expire incomplete multipart uploads — abandoned upload parts are invisible in the console, count as stored bytes, and quietly bill forever.

The trap

Minimum duration turns a saving into a penalty

Classic own-goal: a team lifecycles nightly backups straight to a 90-day-minimum archive class, while their retention policy deletes them after 30 days. Every single object is billed for 90 days of storage. They are paying triple the archive rate and believe they are saving 80%.

The rule: a transition only pays off if the object's expected lifetime exceeds the destination class's minimum duration, and the expected number of reads is below the breakeven. Two conditions. Check both, in that order.

Mechanically, the rule is declarative and lives on the bucket — this is the one place a config snippet is the mechanism:

# vendor-neutral shape of every lifecycle policy on every cloud
rules:
  - filter:  { prefix: "training-logs/" }        # scope
    transitions:
      - { after_days: 30,  to: "cool" }             # age → colder class
      - { after_days: 120, to: "archive" }
    expire_after_days: 2555                        # 7 years, then gone
    abort_incomplete_multipart_after_days: 7      # the forgotten one
S1 · 08 Three clouds · the Rosetta stone for this whole stage

Learn this table once and Sessions 2–4 become vocabulary drills. Every row is the same idea in three dialects.

Neutral conceptAWSAzureGoogle Cloud
Object storageAmazon S3Blob Storage (in a Storage account)Cloud Storage (GCS)
Block storageAmazon EBSAzure Managed DisksHyperdisk (Persistent Disk on older series)
Shared file storageAmazon EFS (NFS) · FSx (Windows/Lustre/ONTAP)Azure Files (SMB+NFS) · NetApp FilesFilestore · Managed Lustre
Managed relationalRDS (MySQL/Postgres/SQL Server/Oracle/MariaDB)Azure SQL Database · Azure Database for PostgreSQL / MySQL flexible serverCloud SQL · AlloyDB (Postgres, HTAP)
Cloud-native relationalAurora (MySQL/Postgres-compatible)Azure SQL HyperscaleAlloyDB
Global strongly-consistent SQLAurora DSQL(no direct equivalent — closest is Cosmos DB strong + failover groups)Spanner
Document / key-value NoSQLDynamoDBCosmos DB (NoSQL API)Firestore
Wide-columnKeyspaces (Cassandra)Cosmos DB (Cassandra API)Bigtable
In-memory cacheElastiCache (Redis OSS / Valkey / Memcached) · MemoryDBAzure Managed RedisMemorystore (Valkey / Redis / Memcached)
Warehouse (OLAP)Redshift · Athena (query-in-place)Microsoft Fabric (Synapse in maintenance)BigQuery
Zone-redundant storagedefault for S3 Standard; Multi-AZ for RDSZRS / GZRS on the storage accountdefault for regional buckets; regional/HA disks
Vendor equivalents are approximate by design — the point is the shape, not feature parity. Quirks and current prices per row are in the session tabs.
S1 · 09 Reality check

Worked example · 1 TB for a year — hot, or archived?

Neutral arithmetic, using representative 2026 US-region list prices. A media company has 1 TB (1,024 GB) of finished renders. They must keep it 12 months. They expect to pull back 50 GB once during the year for a re-edit.

Option A · leave it on Standard / Hot
Storage · 1,024 GB × $0.023 × 12$282.62
Retrieval fee$0.00
Restore jobsnone needed
Year 1 total$282.62

Access: milliseconds, any time. Operationally invisible.

Option B · lifecycle to Deep Archive on day 30
Standard · 1 month$23.55
Transition · 1 request per object
(2,000 objects × $0.05/1,000)
$0.10
Deep Archive · 11 months × $0.00099/GB$11.15
Retrieval · 50 GB bulk × $0.0025$0.13
…and the 12-hour wait before the editor can open the file
Year 1 total$34.93

Saving: $247.69/year per TB — 88%. At 500 TB that is ~$124k a year.

Now break it · the early-deletion penalty Same 1 TB, same lifecycle rule, but the retention policy says delete after 90 days. Deep Archive's minimum billable duration is 180 days. So the objects are deleted on day 90 and you are still billed for days 91–180 at the archive rate — plus you paid the transition requests. You did not save 88%; you paid double the archive storage you consumed and gained a 12-hour retrieval delay in exchange. The lifecycle rule was worse than doing nothing at 90-day retention.

The check, every time: is expected object lifetime > destination minimum duration? If not, stop at the previous tier.

Three real, current examples

Cost blow-up · retrieval

“$1/TB to store, $20K to retrieve”

A 2026 analysis works the numbers on a full petabyte in Deep Archive: about $1,013/month to keep — genuinely astonishing — but restoring the whole petabyte runs roughly $21K in retrieval fees plus ~$52K of egress, and takes 48 hours on the bulk tier. The moral is not “don't archive”; it is that a DR tier whose full restore takes 48 hours cannot satisfy a 12-hour RTO, and the restore cost belongs in the DR plan, not the storage plan.

Prices move · relearn them

Google re-priced its tiers in 2026

Multi-region Nearline went up (about $0.010 → $0.015 per GB-month) while multi-region Archive came down in US/EU (about $0.004 → $0.0024). Concretely: lifecycle policies written before 2026 may now be transitioning data into a class that is no longer the cheapest fit. Storage-class economics are not a “decide once” problem — put a calendar reminder on your tiering rules.

The vendors' own guidance

Well-Architected says the same thing

All three clouds publish a “performance efficiency” / “cost optimisation” pillar whose storage advice reduces to this session's first tree: select the storage service that matches the access pattern, then continuously re-evaluate as the pattern changes. The re-evaluation half is the half teams skip — data gets colder on its own; storage classes do not.

S1 · 10 Apply it · your context

Mapping this onto what you already run

Thing you already haveIts access shapeThe class it belongs in
Modal Volume caching Gemma weightsWrite once, read many, whole-file, read by every cold-starting replicaObject, hot — this is object storage with a filesystem face on it. Never tier weights cold: a cold-start that has to restore from archive is an outage.
Training / fine-tuning datasetSequential, high-throughput, read repeatedly across epochsObject, hot for the active dataset; cool for previous versions you might reproduce from
Training checkpoints mid-runLarge sequential writes, frequent, latency-sensitive because GPUs idle during themBlock throughput or a low-latency object tier — this is the one place in your stack where MB/s, not IOPS, is the number to provision
Finished checkpoints after the runWrite once, read approximately never, but you dare not delete themArchive — the reference text case, provided you keep them past the minimum duration (you will)
Inference request / response logsAppend-only firehose; queried later in aggregate for evalsObject then a warehouse — OLAP, never OLTP
Pipeline state: job records, model registry, eval runs, usersSmall records, relational, must be correct, queried in ways you'll invent laterA managed relational database. Default-tree answer, and it's the right one. Session 3.
Flagged · adjacent, not this stage Vector databases belong to your RAG track. They are a genuinely different access shape — approximate nearest-neighbour over high-dimensional embeddings — and every cloud now bolts it onto an existing engine rather than selling a separate box (Cosmos DB's DiskANN index, Spanner and BigQuery vector search, pgvector on managed Postgres, S3 Vectors). Note the adjacency and move on; we'll touch it once more in S4 and leave it there.
Optional hands-on · 15 minutes, $0.00

Lab S1 — the taxonomy audit (no cloud resources, no bill)

This session is concepts-only, so the lab is deliberately paper. Take one system you already run — the vLLM-on-Modal deployment is ideal — and write out the table above for your own artefacts:

  1. List every persistent artefact. Weights, tokeniser, dataset, checkpoints, logs, config, secrets, metrics.
  2. For each, write one line: unit of access · read:write ratio · reads per month · who reads it · what breaks if it's 5 seconds stale · what breaks if it's gone.
  3. Run each one down the block/file/object tree, then the database tree. Write down where it exits.
  4. Circle every artefact where the answer differs from where it lives today. That circled list is your Session 2 and 3 to-do list.

Do this before Session 2 and the service names in S2 will land on hooks that already exist.

Teardown · nothing to tear down, but read this now Every hands-on lab from Session 2 onward creates things that keep billing after you stop looking. The three that catch people: (1) stored bytes — an object never stops costing until it is deleted, and versioning means “deleted” objects may still be stored; (2) provisioned database instances and throughput — an idle database costs the same as a busy one, and provisioned NoSQL capacity bills per hour whether or not a request arrives; (3) archive minimum durations and early-deletion fees — deleting an archived test object can cost more than leaving it. From S2 on, every lab lists an explicit teardown. Do it the same day.
Bridge → S2

You now have the shapes and the axes. Session 2 puts real names, real classes and real 2026 prices on the top row of the taxonomy — object, block and file across all three clouds — and answers the question you'll ask on every project: exactly which class do my model weights go in, and what does the wrong answer cost?

S2 · 01 Why this session exists

Same three shapes. Three dialects. And the price list is where the design actually gets decided.

Session 1 said object, block, file. This session says which product, which class inside that product, and what the class costs you when you read the data back. That last clause is the whole game: a storage class is a bet about future access frequency, and the cheaper the bet, the harder the penalty for being wrong.

the thermal ladder — one row per temperature, all three clouds
ACCESS FREQUENCY → dailymonthlyquarterlyyearly / never HOT COOL COLD ARCHIVE AWS S3 Standard · $0.023 Standard-IA · $0.0125 · 30d min Glacier Instant · $0.004 · 90d Deep Archive · $0.00099 · 180d Azure Blob Hot · ~$0.018–0.023 Cool · ~$0.010–0.013 · 30d min Cold · ~$0.0036–0.004 · 90d Archive · ~$0.0009–0.002 · 180d Google Cloud Storage Standard · $0.020 (regional) Nearline · $0.010 · 30d min Coldline · $0.004 · 90d min Archive · $0.0012 · 365d min
US-region list prices per GB-month, July 2026, for orientation. Two things to notice immediately: the three clouds are within a rounding error of each other at every temperature, and Google's Archive minimum duration is 365 days, double the other two — the single most commonly missed cross-cloud difference on this ladder.
S2 · 02 Object storage · AWS S3 as the anchor
Pass 1 Intuition

S3 is a bucket per namespace, a key per object, and a class per object that you can change at any time — by hand, by lifecycle rule, or automatically. Everything else in S3 is a feature bolted to that: versioning keeps old copies, replication copies to another bucket, and the classes are the temperature dial from Session 1.

Source note: AWS guidance covers S3, EBS and Glacier at catalogue depth and doesn't enumerate the classes. From here on this section is AWS documentation and current pricing.

Pass 2 Mechanism · the class table, and what each column actually charges you
S3 class$/GB-moRetrievalMin durationFirst byteReach for it when…
Standard0.023nonemsAnything active. The default, and correct far more often than cost-optimisers admit.
Express One Zone0.111 hsingle-digit msLatency-critical, high-request workloads co-located in one AZ — ML training loops over millions of small files. ~10× faster access, ~80% cheaper requests, 5× the storage price, and only one zone of durability.
Standard-IA0.0125$0.01/GB30 dmsRead about monthly. 128 KB minimum billable object size.
One Zone-IA0.01$0.01/GB30 dmsOnly for data you can recreate — derived thumbnails, secondary copies. One AZ means an AZ loss is data loss.
Glacier Instant Retrieval0.004$0.03/GB90 dmsQuarterly access that must be instant when it happens: medical imaging, news archives, ML datasets you pull a few times a year. Breakeven vs Standard-IA is roughly one access every 5–6 weeks.
Glacier Flexible Retrieval0.0036$0.01 std / free bulk90 d1 min – 12 hBackups you restore only in anger. Expedited (1–5 min) is best-effort unless you buy Provisioned Capacity Units at ~$100/unit/month.
Glacier Deep Archive0.00099$0.02 std / $0.0025 bulk180 d12–48 hTape replacement. 7–10 year compliance retention. ~$1 per TB-month.
Intelligent-Tieringautononenonems (top 3 tiers)Unknown or changing access patterns. Monitors each object and moves it between Frequent ($0.023) → Infrequent ($0.0125, 30 d) → Archive Instant ($0.004, 90 d) plus two opt-in deep tiers. Pays a small per-object monitoring fee, but no retrieval fees and no transition charges.
us-east-1 list prices, July 2026. Flexible Retrieval and Deep Archive add ~40 KB of metadata overhead per archived object — material if your objects are small.

The lifecycle rule is the mechanism, so here it is at S3's actual API shape:

// S3 lifecycle configuration — the config IS the mechanism
{ "Rules": [{
    "ID": "logs-age-out", "Status": "Enabled",
    "Filter": { "Prefix": "inference-logs/" },
    "Transitions": [
      { "Days": 30,  "StorageClass": "STANDARD_IA" },
      { "Days": 180, "StorageClass": "DEEP_ARCHIVE" }],
    "Expiration": { "Days": 2555 },
    "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}]}
Not in the material S3 Express One Zone (directory buckets, single-AZ, single-digit-ms) and S3 Tables / S3 Vectors (Iceberg tables and vector indexes as first-class S3 constructs, with their own pricing dimensions) post-date AWS guidance entirely. Express One Zone matters to you directly: AWS positions it for ML training data, checkpoints and model outputs.
Pass 3 Trade-offs · where the S3 bill actually comes from

Storage is often not the biggest line. The four others:

  • Requests. PUTs cost roughly 10× GETs, and archive-class PUTs cost more again (~$0.05/1,000). A pipeline writing millions of tiny objects pays more in requests than in bytes.
  • Retrieval. Only on IA and colder — but at $0.03/GB (Glacier Instant), reading 10 TB back costs $300 on top of everything else.
  • Egress. Data out to the internet is ~$0.09/GB for the first 10 TB, falling in tiers. Serving public assets straight from a bucket instead of through a CDN is a classic unforced error — CloudFront-to-origin transfer is free.
  • Minimum billable object size. IA classes bill a 128 KB floor per object; archive classes add ~40 KB metadata. Ten million 20 KB objects in Standard-IA bill as if they were 128 KB each.
Callback · C4 Egress is a networking cost that shows up on your storage bill. Reaching a bucket from inside the VPC over a gateway/interface endpoint keeps traffic off the internet path and avoids NAT gateway data-processing charges — which for a training job pulling terabytes is not a rounding error.
S2 · 03 Object storage · the same idea in Azure and Google Cloud
AWS · Amazon S3
Bucket → key → object
Flat global-ish namespace; bucket names are unique per partition. Class set per object.
quirk Storage class is a per-object property, and the bucket only holds a default. Two objects side by side can be in different classes — which is what makes Intelligent-Tiering possible and lifecycle rules granular.
Durability model
≥3 AZs by default (except One Zone classes and Express One Zone). 11 nines design target; 99.9%–99.99% availability SLA depending on class.
watch Versioning is off by default. Turn it on and “deleted” objects become noncurrent versions that still bill — add a NoncurrentVersionExpiration rule at the same time.
Azure · Blob Storage
Storage account → container → blob
One extra level than S3. The storage account is the billing, redundancy, networking and endpoint boundary — get it wrong and you re-create everything.
quirk Redundancy is an account setting, not a per-object one: LRS / ZRS / GRS / GZRS / RA-GRS / RA-GZRS. Access tier is per-blob (Hot/Cool/Cold/Archive) with an account default.
Three blob types
Block blobs (normal objects), append blobs (logging), page blobs (the 512-byte-page format that backs unmanaged VM disks). No S3 equivalent — genuinely Azure-specific.
watch Rehydrating from Archive is a tier change that takes hours; the blob is unreadable until it completes. Standard priority is up to 15 hours, high priority is faster and dearer.
Data Lake Storage Gen2
Blob storage with hierarchical namespace switched on — real directories, atomic renames, POSIX-ish ACLs. The right choice for analytics; must be enabled at account creation.
Google Cloud · Cloud Storage
Bucket → object
Flat, like S3. Bucket names are globally unique across all of Google Cloud.
quirk Location type is the big decision, not just the region: regional, dual-region (two named regions, synchronous-ish turbo replication available) or multi-region. Multi-region costs more per GB but reads inside it don't pay inter-region transfer.
Autoclass
Bucket-level automatic tiering with no retrieval fees and no early-deletion charges — the direct analogue of S3 Intelligent-Tiering. Costs a management fee per 1,000 objects per 30 days; objects under 128 KiB aren't managed.
watch Archive's minimum storage duration is 365 days, not 180. A 200-day-lifetime object archived on GCS is billed for 365.
Rapid storage & Rapid Cache new
A zonal, very-low-latency class (Rapid Bucket) aimed squarely at AI/ML and analytics, plus Rapid Cache — the renamed Anywhere Cache — an SSD read cache you attach to a bucket. Reads served from the cache skip retrieval fees and cross-zone transfer.
Redundancy Rosetta stone — the one table Azure candidates always lose marks on
Protection levelAWS S3Azure Storage accountCloud Storage
One datacentre onlyOne Zone-IA / Express One ZoneLRS — 3 copies, one datacentre(no single-zone bucket except Rapid Bucket)
Across zones, one regionStandard and most classes (≥3 AZs)ZRS — 3 zones, synchronousRegional bucket
Two regions, asyncCross-Region Replication (you configure it)GRS — async to a paired region, not readable until failoverDual-region bucket
Two regions, readable secondaryCRR + read the second bucket yourselfRA-GRS — secondary readable at any timeDual-region (both readable)
Zones + regionsStandard + CRRGZRS / RA-GZRS — ZRS in primary, async to secondaryMulti-region bucket
Azure's §6 quotes 11 nines for LRS and 12 nines for ZRS. The exam-relevant nuance: GRS replication is asynchronous, so a regional failure has a non-zero RPO, and with plain GRS you cannot read the secondary until Microsoft (or you) initiate failover.
Which object storage class for this data?
Follow “no ↓”. First “yes” exits right. Bottom-left is the default.
  1. Is a GPU, a user, or a request path waiting on this read?
    yes →Hot / Standard. If it's also latency-critical, high-request and single-AZ-tolerant, consider S3 Express One Zone / GCS Rapid. Do not tier this data. Ever.
    no ↓
  2. Is the access pattern genuinely unknown, or does it change over time?
    yes →Intelligent-Tiering (AWS) / Autoclass (GCS) / lifecycle-with-last-access-tracking (Azure). No retrieval fees, no early-deletion charges — you buy away the risk of guessing wrong for a small monitoring fee.
    no ↓
  3. Will this object be deleted or overwritten before the destination class's minimum duration (30 / 90 / 180 / 365 days)?
    yes →Stay hot. The early-deletion penalty exceeds the saving. This is the single most common tiering mistake — check it before anything else.
    no ↓
  4. Read roughly monthly, and must be instant when read?
    yes →Standard-IA / Cool / Nearline. Watch the 128 KB minimum billable size if your objects are small.
    no ↓
  5. Read roughly quarterly or less, but a wait of hours would be unacceptable when it happens?
    yes →Glacier Instant Retrieval / Cold / Coldline. Cheap to hold, dear to read — model the read volume, not just the GB.
    no ↓
  6. Read once a year at most, and you can wait hours, and you'll keep it past 180 days (365 on GCS)?
    yes →Deep Archive / Archive. Now put the full-restore cost and time in your DR runbook, because it is not free and it is not fast.
    no ↓
  7. Does anyone actually need this data at all?
    yes →Then it's in one of the tiers above.
    no ↓
Default
Standard / Hot, plus an expiration rule
Hot storage with a working deletion policy beats clever tiering with no deletion policy, almost every time. Tiering saves a percentage of the bytes you keep; expiration removes the bytes entirely. Write the expiry rule first, then optimise what's left.
S2 · 04 Block storage · disks for the C3 VMs
Pass 1 Intuition

You are renting a disk over the network and pretending it's local. Two dials: how big and how fast. The generational shift across all three clouds has been decoupling those two dials — older volume types tied speed to size (want more IOPS? buy more GB you don't need); modern ones let you provision capacity and performance independently.

Pass 2 Mechanism · the performance plane
THROUGHPUT (MB/s) — big sequential I/O → IOPS → HDD / throughput st1 · sc1 · HD Throughput GENERAL-PURPOSE SSD gp3 · Premium SSD v2 · HD Balanced the right default PROVISIONED IOPS SSD io2 Block Express · Ultra · HD Extreme expensive, sub-ms, 5 nines LOCAL NVMe ephemeral · fastest · volatile
Hover or tap a family.
Pass 3 Trade-offs and the three-cloud specifics
AWS · Amazon EBS
gp3 — the default
$0.08/GB-mo. Baseline 3,000 IOPS + 125 MiB/s free at any size, up to 80,000 IOPS / 2,000 MiB/s for extra.
quirk gp2 tied IOPS to size (3 IOPS/GB) — people bought 1 TB volumes to get 3,000 IOPS. gp3 gives that baseline free and is ~20% cheaper per GB. If you still run gp2, migrating is nearly free money.
io2 Block Express
$0.125/GB-mo + tiered IOPS ($0.065/IOPS-mo for the first 32,000). Up to 256,000 IOPS, 99.999% durability, sub-500 µs.
st1 / sc1
HDD, ~$0.045 / ~$0.015 per GB-mo. Throughput yes, IOPS no.
watch An EBS volume bills from creation to deletion — attached or not, running or not. Terminated instances routinely leave orphaned volumes billing for months. Encryption is on by default via KMS with no measurable performance cost.
Azure · Managed Disks
Premium SSD v2 — the modern default
Capacity, IOPS and throughput each provisioned independently, per-GiB granularity. The direct gp3 analogue.
quirk Premium SSD v1 uses fixed size tiers (P10, P30, P40…) where performance is welded to the tier — ask for 5,000 IOPS and you buy a 1 TiB disk whether or not you need the space. v2 removes that; v1 still shows up everywhere in older material and templates.
Ultra Disk
Up to 400,000 IOPS, sub-ms, adjustable live. SAP HANA, top-tier OLTP.
Standard SSD / Standard HDD
Dev, test, backup, low-traffic web.
watch Disks are billed on provisioned size rounded up to the tier, not used size. And the VM's “temporary disk” (D:) is ephemeral — wiped on deallocate. People still lose data to that one.
Google Cloud · Hyperdisk changed
Hyperdisk Balanced — the default
Up to 160,000 IOPS and 2,400 MiB/s per volume; performance adjustable every 4 hours; sub-ms.
big change Persistent Disk is not available on the newest machine series at all — on those, the boot disk must be Hyperdisk Balanced or Balanced High Availability. Any source or course that teaches pd-ssd/pd-balanced as the current model is out of date.
Hyperdisk Balanced High Availability
Synchronous replication across two zones — the successor to Regional Persistent Disk.
Hyperdisk Extreme / Throughput
The io2 and st1 analogues.
Hyperdisk ML GenAI-relevant
A read-only volume you can attach to many instances at once — built for exactly the “every inference replica needs the same 40 GB of weights” problem. Set access mode to read-only at creation; it cannot be changed afterwards, and it does not support multi-writer.
watch Hyperdisk ML volumes created before 4 Feb 2026 can't attach to 4th-gen machines (C4, G4) — snapshot and recreate. Storage Pools let a fleet of disks share provisioned capacity and performance, cutting TCO substantially for database fleets.
Which block volume type?
Follow “no ↓”. First “yes” exits right. Bottom-left is the default.
  1. Is the data pure scratch — shuffle spill, a re-downloadable weight cache, temp files — that you can lose on reboot?
    yes →Local/ephemeral NVMe. Fastest thing available, and it's often already included in the instance price.
    no ↓
  2. Do many instances need to read the same large immutable blob concurrently at high throughput?
    yes →On GCP, Hyperdisk ML (read-only, multi-attach). Elsewhere, this is usually a file-storage or object-storage question, not a block one.
    no ↓
  3. Is the I/O large and sequential — logs, batch scans, media — with low IOPS need and a big capacity bill?
    yes →HDD-class: st1 / Standard HDD / Hyperdisk Throughput. Roughly half the per-GB price of SSD.
    no ↓
  4. Have you measured a need for more than ~16,000 IOPS, sub-millisecond latency, or five-nines volume durability?
    yes →io2 Block Express / Ultra Disk / Hyperdisk Extreme. Measured, not anticipated — this tier is several times the price.
    no ↓
  5. Does the volume need to survive the loss of an entire zone without a restore?
    yes →Hyperdisk Balanced High Availability (GCP) or zone-redundant equivalents; on AWS the pattern is application-level (Multi-AZ database) rather than a cross-AZ volume.
    no ↓
Default
General-purpose SSD — gp3 / Premium SSD v2 / Hyperdisk Balanced
Then measure, then adjust the IOPS and throughput dials independently. Over-provisioning IOPS “to be safe” is one of the most common silent line items on a cloud bill, and on modern volume types it is also the easiest to undo — you can turn the dial down without recreating the disk.
S2 · 05 File storage · the compatibility layer

You reach for file storage for one of two honest reasons: several machines must share a mutable working directory, or software you didn't write demands a POSIX path. It is the most expensive of the three shapes per GB, so use it deliberately.

AWS · EFS (+ FSx)
Amazon EFS
Elastic NFS. Grows and shrinks automatically; no capacity to provision. Storage classes: Standard $0.30/GB-mo, One Zone $0.16, Infrequent Access $0.016, Archive $0.008.
quirk With the default Elastic Throughput you also pay per byte moved — about $0.03/GB read and $0.06/GB written — and IA/Archive access charges stack on top. AWS quotes an effective blended TCO as low as $0.0315/GB with lifecycle management, but only if most data is cold.
watch Metadata always bills at the Standard rate even when 95% of your data has tiered down.
Amazon FSx
Managed third-party filesystems: Lustre (HPC/ML, hundreds of GB/s, links to an S3 bucket), Windows File Server (SMB), NetApp ONTAP, OpenZFS. FSx for Lustre is the AWS answer for feeding GPU clusters.
Azure · Files (+ NetApp)
Azure Files
The only one of the three that speaks SMB and NFS natively — the reason it wins Windows workloads outright. Lift-and-shift file shares, AD integration, drive-letter mounts.
quirk Billing model matters more than tier: pay-as-you-go vs provisioned v2, where you buy capacity, IOPS and throughput separately. Provisioned SSD reaches ~100,000 IOPS; provisioned HDD v2 tops out lower but is much cheaper per GB.
Azure File Sync
Turns an on-prem Windows Server into a cached tier over an Azure file share. No real AWS/GCP equivalent; very common in hybrid enterprises.
Azure NetApp Files · Managed Lustre
The high-performance escape hatches. §6 also covers Elastic SAN — a cloud SAN presenting iSCSI targets, which is block, not file, and unique to Azure.
Google Cloud · Filestore
Filestore
Managed NFS in tiers — Basic HDD/SSD, Zonal, Regional, Enterprise — with capacity and performance provisioned per instance.
quirk You pay for provisioned capacity, not consumed, and there are sizeable minimums per tier. A “small” Filestore instance is not small on the bill. Check the minimum before you design around it.
Managed Lustre
Google's parallel filesystem for AI/HPC, the FSx-for-Lustre analogue.
alternative For read-mostly ML data, Google increasingly steers you away from file storage entirely: Cloud Storage FUSE with Rapid Cache, or Hyperdisk ML for read-only multi-attach. Both are cheaper than Filestore for the “many readers, one immutable dataset” shape.
S2 · 06 Reality check

Worked example · 40 TB of inference logs, three ways

Your service writes 40 TB/year of request/response logs as ~4 million objects averaging 10 MB. You re-read about 2% of them (800 GB) during eval work in the first three months, and essentially nothing after that. Compliance says keep 7 years. US region, S3 list prices.

A · leave everything on Standard
40,960 GB × $0.023 × 12$11,305
PUT requests 4M × $0.005/1,000$20
Retrieval$0
Year 1$11,325
Year 7 cumulative (data grows 40 TB/yr)≈ $317,000
B · Standard 30 d → IA 150 d → Deep Archive
Standard, 1 month$942
Transitions 4M × $0.01/1,000 × 2$80
Standard-IA, 5 months$2,560
Deep Archive, 6 months$243
Eval retrieval 800 GB from IA × $0.01$8
Year 1$3,833
vs option A−66%
C · Intelligent-Tiering, no rules at all
Monitoring 4M obj × $0.0025/1,000/mo × 12$120
Auto Frequent → Infrequent → Archive Instant≈ $4,900
Retrieval fees$0
Year 1≈ $5,020
…but zero risk of a wrong guess

Read the result honestly: hand-tuned lifecycle (B) beats Intelligent-Tiering (C) by about $1,200 in year one because the access pattern is genuinely predictable. If eval work were sporadic and unpredictable, C would win on retrieval fees alone — and C never gets the minimum-duration decision wrong. Choose B when you know the pattern; choose C when you're guessing.

Break it · the over-provisioned IOPS version of the same mistake Same principle, block edition. A team runs 40 × 500 GB io2 volumes, each provisioned at 20,000 IOPS “for headroom”. Actual sustained usage: under 2,000 IOPS. The storage costs 40 × 500 × $0.125 = $2,500/month; the provisioned IOPS cost 40 × 20,000 × $0.065 = $52,000/month. Moving to gp3 with 6,000 provisioned IOPS: 40 × 500 × $0.08 = $1,600 storage, plus 40 × 3,000 chargeable IOPS × $0.005 = $600. Total $2,200 versus $54,500. Nothing was broken; nobody got an alert. On modern volume types this is reversible with a dial, not a migration — which is exactly why it's worth auditing quarterly.

Three real, current examples

AI/ML checkpointing

AWS's own numbers on checkpoint storage

AWS's storage blog works a large-training example: loading 125 TB of checkpoint data in two minutes requires roughly 1,042 GB/s — about 8.3 Tbps of aggregate throughput. Their guidance is a tiered pattern — S3 (optionally Intelligent-Tiering) as the durable home, S3 Express One Zone or FSx for Lustre as the hot path — plus retries with exponential backoff and connection-pool tuning, because thousands of ranks checkpointing simultaneously create demand spikes that hit service limits regardless of which storage you chose.

Object storage is closing on file

FUSE and caches change the calculus

Google reports Cloud Storage FUSE delivering up to 2.2× faster training time and 2.9× higher throughput versus native framework dataloaders, and Rapid Cache (formerly Anywhere Cache) reaching multi-Tbps aggregate reads with reduced GPU blocked time and much faster checkpoint restores. Practical consequence: the reflex “ML training needs a parallel filesystem” is weaker than it was two years ago. Benchmark object-plus-cache before you provision Lustre or Filestore.

Cross-cloud reality

Neither provider is universally cheaper

A 2026 cross-cloud comparison finds request charges, egress and retrieval fees routinely add 30–70% on top of the theoretical per-GB storage bill, and that AWS vs Azure vs GCP flips depending on object size, access pattern and egress volume. Take the practical lesson rather than a winner: model all five dimensions — storage, requests, retrieval, egress, minimum durations — or your comparison is fiction.

S2 · 07 Apply it · your context

Your Modal Volume, translated to each cloud

A Modal Volume caching Gemma weights is doing exactly one job: make a large immutable blob available to every cold-starting replica fast enough that the cold start isn't dominated by the download. That is a distributed read cache in front of object storage. Here is the same job, natively, on each cloud:

LayerAWSAzureGoogle Cloud
Durable home for weightsS3 Standard (not IA — cold starts can't wait)Blob HotGCS Standard, regional, co-located with the GPUs
Fast read path for many replicasS3 Express One Zone directory bucket, or Mountpoint-for-S3 CSI driver on EKSBlobFuse2 with local cache on the nodeHyperdisk ML (read-only, multi-attach) or Cloud Storage FUSE + Rapid Cache
Node-local cacheInstance-store NVMeEphemeral OS/temp diskLocal SSD
Training datasetS3 + FSx for Lustre if you need POSIX at speedADLS Gen2 + Managed LustreGCS + Managed Lustre, or GCS FUSE for most cases
Checkpoints during a runS3 Express One Zone or FSx Lustre; gp3/io2 if writing locally firstPremium SSD v2 then async copy to BlobHyperdisk Balanced (provision throughput, not IOPS) then GCS
Finished checkpointsDeep Archive after 180+ daysArchive after 180+ daysArchive — remember 365-day minimum
GPU-workload stress points · why this tier is different for you
  1. Cold-start latency is a storage problem. A 9B model in bf16 is ~18 GB. At 1 GB/s that's 18 seconds of GPU sitting idle at $2–10/hour before a single token is served. This is why weight buckets stay hot and why read caches earn their keep.
  2. Checkpoint writes want MB/s, not IOPS. Nearly every default block volume is tuned for random IOPS. A checkpoint is one enormous sequential write. On gp3 and Hyperdisk Balanced you can turn the throughput dial independently — do that, and leave IOPS at baseline.
  3. Small-file datasets destroy object-storage economics. Ten million 30 KB training images = 10M requests per epoch plus per-object overhead. Shard into WebDataset/TFRecord-style archives of 100 MB–1 GB before you do anything else.
  4. Your Vertex AI T4/L4 autoscaling script is a cold-start machine. Scaling 1→3 means two nodes pulling the full weight set on every scale-out event. Where the weights live determines whether that's 20 seconds or 4 minutes.
Optional hands-on · ~20 minutes · under $0.05 if you follow the teardown

Lab S2 — lifecycle a bucket and watch the class change

Pick one cloud. Free tier / smallest SKU only. Set a budget alert before you create anything.

  1. Budget alert first. AWS Budgets / Azure Cost Management budget / GCP Billing budget — set it to $5 with an email at 50%. Do this even for a $0.05 lab; the habit is the point.
  2. Create one bucket in your nearest region. Default settings. Turn on versioning so you can see the noncurrent-version trap for yourself.
  3. Upload three small files (a few KB each) under the prefix lab/.
  4. Add a lifecycle rule scoped to lab/: transition to the cool tier after 30 days, expire after 60, and abort incomplete multipart uploads after 7 days. Add a noncurrent-version expiration of 7 days.
  5. Manually change one object's storage class to the cool tier in the console and note the timestamp — this is what starts a minimum-duration clock.
  6. Now delete that one object and look at the cost explorer line item over the next two days. You will see an early-deletion charge for the remaining days. That single sub-cent line item is the most valuable thing in this lab — it makes the penalty concrete.
  7. Open the pricing calculator for the same cloud and price 100 TB in each class for 3 years. Compare against your S1 arithmetic.
Teardown — do this the same day
  1. Empty the bucket, including all object versions and delete markers. With versioning on, deleting an object does not free the bytes — the previous version is still stored and still billed. Use “empty bucket” / “delete all versions”, not a normal delete.
  2. Delete the bucket itself.
  3. Check for incomplete multipart uploads before deleting — abandoned parts are invisible in the object list and bill indefinitely.
  4. Accept the early-deletion charge. You will be billed the remainder of the 30-day minimum on that one tiered object. It will be well under a cent. Leaving it in place to avoid the fee would cost more.
  5. If you created any disk or file share while exploring: delete the volume, not just the VM. Block volumes bill from creation to deletion regardless of attachment, and this is the single most common orphaned resource on every cloud.
  6. Leave the budget alert in place. It costs nothing and it will save you later.
Bridge → S3

Raw storage is now placed on all three clouds. Session 3 moves up one layer to the engines that add concurrency control and query on top of it — managed relational databases — and to the decision that costs the most to reverse: regional, multi-region, or genuinely global.

S3 · 01 Why this session exists

Almost every system has one relational database at its centre. Getting it wrong is the most expensive mistake in this stage to undo.

You can change an object's storage class with an API call. You can attach a bigger disk in an afternoon. Changing the database at the heart of a system means a schema migration, a data migration, a dual-write period and a cutover — months, not minutes. So this is the decision that deserves the most deliberate thought, and the one where “boring and correct” pays the largest dividend.

WHAT YOU STOP DOING WHEN YOU GO MANAGED — left to right, increasing abstraction DIY on a VM you: OS patchingyou: engine install & upgrade you: backups & restore testsyou: replication & failover you: disk sizing, HA, monitoring max control · max toil Managed instance (RDS-class) cloud: OS, engine patchingcloud: automated backups, PITR cloud: standby + failoveryou: schema, indexes, queries you: instance size, replicas the sweet spot for most systems Cloud-native (Aurora-class) + storage decoupled from compute+ storage auto-grows, 6 copies/3 AZ + replicas share one storage layer+ seconds-scale failover you: still size the compute same SQL, cloud-shaped internals Serverless / distributed + capacity scales automatically+ can scale to zero (Serverless v2) + multi-region active-activeyou: model data for the engine you: accept its SQL limitations Aurora DSQL · Spanner
Moving right removes toil and adds constraints. The most common architecture error here is jumping straight to the right-hand column for a workload that a single managed Postgres instance would serve happily for years.
S3 · 02 Core concept 1 · what “managed” actually changes
Pass 1 Intuition

Renting a flat versus owning a house. The landlord fixes the boiler, replaces the roof and re-paints the exterior (patching, backups, failover). You still choose the furniture and you're still responsible for the mess you make inside (schema, indexes, queries, connection handling). And there are things you're simply not allowed to do — no knocking through walls: no OS shell, no arbitrary extensions, no superuser.

Pass 2 Mechanism · the four things you configure, on every cloud

1 · Engine and version

PostgreSQL, MySQL, SQL Server, Oracle, MariaDB. Pick the engine your team knows. Version matters more than people expect — managed services force major-version upgrades on a schedule, and the extensions available are a curated list, not whatever's on PGXN.

2 · Compute size

vCPU and memory, either as an instance class or as an abstract unit (Azure DTUs/vCores, Aurora Capacity Units, Spanner processing units). Memory is usually the binding constraint, because it determines how much of your working set stays in the buffer cache.

3 · Storage and IOPS

Everything from Session 2 applies — this is block storage underneath. Cloud-native engines (Aurora, Hyperscale, AlloyDB) hide it: storage auto-grows and is replicated many ways across zones, and you're billed for what you use plus I/O.

4 · Availability topology

Single instance, zone-redundant standby, read replicas, cross-region replicas. This is the dial that actually determines your SLA, your RPO and roughly half your bill.

Terms
Primary / writer
The one node that accepts writes. In classic relational architecture there is exactly one, and that is the fundamental scaling limit.
Standby
A synchronously-replicated copy you cannot query. It exists purely to be promoted. Doubles your cost and buys you automatic failover.
Read replica
An asynchronously-replicated copy you can query. Scales reads; lags the primary by milliseconds to seconds.
Failover
Promoting a standby to primary. Automatic in managed services; typically 30–120 seconds on instance-based services, single-digit seconds on cloud-native ones.
PITR
Point-in-time recovery — restore to any second inside the retention window, using a base backup plus the transaction log. The real protection against “someone ran the wrong UPDATE”.
Connection pooling
Reusing a small set of database connections across many clients. Relational databases handle a few hundred connections well and thousands badly; serverless compute makes this worse, which is why RDS Proxy, PgBouncer and Azure SQL's built-in pooling exist.
Pass 3 Trade-offs · when managed is the wrong answer

Managed is right almost always. The genuine exceptions:

  • You need an extension or a version the service doesn't offer. Common with exotic Postgres extensions, or engine builds pinned by a vendor application.
  • You need OS-level access — a custom collation, a filesystem-level tool, an agent that must run on the DB host.
  • Regulatory or data-residency constraints the managed service doesn't satisfy in your region.
  • Cost at very large, very steady scale, where a well-run self-managed cluster on reserved instances genuinely undercuts the managed premium — and you have the DBA capacity to run it properly. Be honest about the second half.

Everything else — “we want control”, “we already know how to run Postgres”, “managed is expensive” — is usually a decision to spend engineer-hours on undifferentiated work. The patterns catalog calls the managed option Database-as-a-Service and treats it as the default for cloud-native applications for exactly this reason.

S3 · 03 Core concept 2 · scaling reads, and why writes are different
Pass 1 Intuition

A restaurant with one kitchen. Adding more waiters (read replicas) serves more customers reading the menu and collecting food, and it's cheap. But every order still passes through one kitchen. To cook more you either build a bigger kitchen (vertical scaling — finite) or open separate kitchens each responsible for different dishes (sharding — complex) or use a fundamentally different design where every branch can cook independently and they reconcile (distributed SQL).

Pass 2 Mechanism
Interactive — hover / tap a topology
A · PRIMARY + STANDBY PRIMARY (rw) STANDBYnot readable sync reads: 1× · writes: 1× availability: 99.95% RPO 0 · RTO 30–120 s buys resilience, not throughput B · + READ REPLICAS PRIMARY (rw) read 1 read 2 read 3 reads: ~4× · writes: still 1× async lag — reads may be stale C · DISTRIBUTED SQL node rw node rw node rw consensus: Paxos / Raft (+ TrueTime on Spanner) reads: n× · writes: n× · strongly consistent cost: commit latency, narrower SQL, higher $ Spanner · Aurora DSQL · CockroachDB
Hover or tap a topology.
The one-line rule Read replicas scale reads. Only sharding or distributed SQL scales writes. If your bottleneck is write throughput, adding replicas makes it marginally worse, because the primary now also ships every change to each replica.
Pass 3 Trade-offs · failover, walked through
Step 1 of 5

Steady state

Primary in zone A, synchronous standby in zone B, two read replicas. Application connects to a DNS endpoint, not an IP — that indirection is the entire failover mechanism.

Step 2 of 5

Zone A loses power

The primary is gone mid-transaction. Because replication to the standby was synchronous, every committed transaction is already durable in zone B. RPO = 0. In-flight uncommitted transactions are lost, correctly — they were never acknowledged.

Step 3 of 5

Detection (~10–30 s)

The control plane's health checks fail repeatedly. Deliberately not instant — a single missed heartbeat must not trigger a failover, or a network blip becomes an outage. This delay is the price of not flapping.

Step 4 of 5

Promotion and DNS swap (~10–60 s)

Standby is promoted to primary; the endpoint's DNS record is repointed. Your application's cached DNS and open connection pool are now the long pole. Set a short DNS TTL, and make sure your driver actually reconnects rather than holding dead sockets — this is where most “the failover took 15 minutes” stories actually come from.

Step 5 of 5

From the application's point of view

Roughly 30–120 seconds of write errors (single-digit seconds on Aurora-class engines), then normal service. Reads from replicas continued throughout if you routed them separately.

Two design consequences, both yours not the cloud's: (1) retry with exponential backoff and jitter on transient database errors, and (2) test it — every managed service has a “force failover” button. Press it in staging, during working hours, and measure.

S3 · 04 Three clouds · managed relational
AWS
Amazon RDS
Managed MySQL, PostgreSQL, MariaDB, Oracle, SQL Server. Multi-AZ standby, up to 15 read replicas, automated backups with PITR.
quirk Multi-AZ instance deployment gives a standby you cannot read. Multi-AZ DB cluster deployment gives two readable standbys and much faster failover. Different products, confusingly similar names.
Amazon Aurora
MySQL- and PostgreSQL-compatible, rebuilt for cloud: a shared distributed storage layer holding six copies across three AZs, auto-growing to 128 TB, with replicas reading the same storage rather than replaying a log.
economics Storage ~$0.10/GB-month billed on consumption, plus I/O — and storage keeps billing while compute is paused. Aurora Serverless v2 scales in ~0.5-ACU steps at roughly $0.12/ACU-hour and, since late 2024, scales to 0 ACUs after inactivity. Excellent for dev and spiky workloads; usually dearer than provisioned for steady load.
Aurora DSQL new — GA May 2025
Serverless distributed SQL: active-active across regions, multi-region strong consistency, PostgreSQL-compatible, 99.99% single-region / 99.999% multi-region. Billed in distributed processing units (DPUs) + storage; free tier includes 100K DPUs and 1 GB monthly.
watch Not a drop-in Aurora replacement. It supports a large but incomplete slice of PostgreSQL, and the data model must suit a distributed engine. Treat it as “Spanner for AWS”, not “Aurora with better billing”.
Azure
Azure SQL Database
PaaS SQL Server — no VM, no instance to patch. Tiers: General Purpose (remote storage), Business Critical (local SSD + always-on replicas, lowest latency), Hyperscale (storage/compute separated, up to 128 TB, near-instant restore).
quirk Two purchasing models coexist: DTUs (a blended abstract unit — simple but opaque) and vCore (explicit CPU/memory/storage, supports Azure Hybrid Benefit and reservations). Choose vCore for anything new; DTU material in older courses is still everywhere.
Azure SQL Managed Instance
Near-100% SQL Server surface — SQL Agent, cross-database queries, CLR — inside a VNet. The lift-and-shift target when Azure SQL Database's PaaS restrictions bite.
Azure Database for PostgreSQL / MySQL — flexible server
The open-source engines, with zone-redundant HA, burstable SKUs and a stop/start capability that genuinely pauses compute billing. This is your open-source-first landing spot on Azure.
global Azure's cross-region story is failover groups and active geo-replication: asynchronous, readable secondaries, RPO measured in seconds. There is no Azure SQL equivalent of Spanner — for global strong consistency Azure points you at Cosmos DB, which is Session 4.
Google Cloud
Cloud SQL
Managed MySQL (to 8.4), PostgreSQL (to 17) and SQL Server (to 2025). HA is a regional configuration with a synchronous standby in a second zone; read replicas can be cross-region.
quirk Cloud SQL HA failover typically completes in about a minute and the standby is not readable — the same trade as RDS Multi-AZ instance mode. Vertical scaling requires a restart, so size with headroom.
AlloyDB
PostgreSQL-compatible with separated storage, a columnar engine for in-place analytics, and Google's claimed large speedups on transactional and analytical queries. The Aurora-equivalent slot.
Spanner the standout
Horizontally scalable relational with external consistency — the strongest guarantee available in a distributed system — across regions and continents, at up to 99.999% availability. Compute in processing units (1 node = 1,000 PU; minimum 100 PU), automatic sharding by key range.
how TrueTime: GPS and atomic clocks give every server a globally synchronised clock exposed as an interval. On commit, Spanner waits out the uncertainty (typically ~5–10 ms) before releasing locks, so transaction timestamps match real-world order everywhere. You are literally paying for the speed of light in commit latency.
changed Spanner now sells in editions (Standard / Enterprise / Enterprise Plus) and has become multi-model — Spanner Graph, full-text search and vector search in the same database — plus a managed autoscaler and SSD/HDD tiered storage. Any material describing it as “relational only, one price” is out of date.
Compare harder — the capability grid you'll actually be asked about
CapabilityAWSAzureGoogle Cloud
In-region HARDS Multi-AZ (instance = unreadable standby; DB cluster = 2 readable standbys). Aurora: 6 storage copies across 3 AZs by design.Zone-redundant configuration; Business Critical keeps always-on replicas on local SSD, one of which is readable.Cloud SQL regional HA (unreadable standby in a second zone). AlloyDB is zone-redundant by architecture.
Typical failoverRDS 60–120 s · Aurora <30 s, often single-digitAzure SQL <30 s typicalCloud SQL ~60 s · AlloyDB faster
Readable replicasUp to 15 (Aurora replicas share storage, so they add no write overhead)Geo-replicas / named replicas; Hyperscale adds up to 30 high-availability + named replicasCloud SQL read replicas incl. cross-region; AlloyDB read pools
Backups & PITRAutomated backups, PITR to the second within retention (up to 35 days), snapshots survive instance deletionAutomatic backups with PITR (1–35 days) plus long-term retention up to 10 yearsAutomated backups + PITR via write-ahead-log retention
Storage ceilingRDS 64 TiB · Aurora 128 TiBGeneral Purpose 4 TB · Hyperscale 128 TBCloud SQL 64 TB · Spanner effectively unbounded
Scale-to-zero / pauseAurora Serverless v2 → 0 ACUs; RDS instances can be stopped for up to 7 daysAzure SQL serverless auto-pause; flexible server stop/startStop the Cloud SQL instance manually (storage still bills)
Cross-regionAurora Global Database (sub-second lag, write forwarding); cross-region read replicasFailover groups & active geo-replication (async, readable secondary)Cross-region read replicas; Spanner multi-region configurations
Global strong consistencyAurora DSQL— (Cosmos DB, not Azure SQL)Spanner
Connection poolingRDS Proxy (billed per ACU/vCPU of the database)Built into the Azure SQL gateway; PgBouncer available on flexible serverCloud SQL Auth Proxy handles auth & encryption; PgBouncer for pooling
Auth without passwordsIAM database authenticationMicrosoft Entra ID authenticationIAM database authentication
Exam-trap row: “Multi-AZ” on AWS and “zone-redundant” on Azure both mean survive one datacentre — but only some of those configurations give you a replica you can read. Read capacity and availability are separate purchases on every cloud; conflating them is the most common design error in this table.

Reading it as an architect, not a memoriser: the rows split into two groups. Rows 1–4 are resilience — every cloud sells essentially the same thing at essentially the same price, so they are rarely the deciding factor. Rows 5–8 are ceilings — how far the design goes before it needs replacing. Choose on the ceilings, because those are the ones that force a migration later, and a migration is the expensive event this session exists to help you avoid.

Which managed relational option?
Follow “no ↓”. First “yes” exits right. Bottom-left is the default.
  1. Do you need an engine feature the PaaS offering forbids — an unsupported extension, SQL Agent, cross-database queries, OS access?
    yes →Managed Instance (Azure SQL MI) or, failing that, self-managed on a VM. Accept the toil deliberately.
    no ↓
  2. Do writers in multiple regions need to write the same rows with strong consistency and zero RPO?
    yes →Spanner (GCP) or Aurora DSQL (AWS). Budget for tens of milliseconds of commit latency and a narrower SQL surface. Be certain you need this — it is the most expensive answer on the tree.
    no ↓
  3. Is the workload idle most of the time — dev, test, internal tooling, a weekly batch?
    yes →Aurora Serverless v2 with a 0-ACU floor, Azure SQL serverless with auto-pause, or Cloud SQL you stop when unused. Remember storage still bills at zero compute.
    no ↓
  4. Do you need >64 TB, near-instant restore of a very large database, or read replicas that add no write overhead?
    yes →The cloud-native tier: Aurora, Azure SQL Hyperscale, or AlloyDB. Storage and compute separate, replicas share storage.
    no ↓
  5. Is read traffic the bottleneck, with writes comfortably inside one instance?
    yes →Keep the engine; add read replicas and route reporting and read-only paths to them. Cheapest real scaling move there is.
    no ↓
  6. Is write throughput the bottleneck, measured, after indexing and batching work?
    yes →Vertical scale first (it's one restart), then shard by tenant or entity, then distributed SQL. In that order — each step costs an order of magnitude more effort.
    no ↓
Default
A single managed PostgreSQL instance with a zone-redundant standby and PITR
RDS for PostgreSQL / Azure Database for PostgreSQL flexible server / Cloud SQL for PostgreSQL. Multi-AZ or zone-redundant on, backups on, retention set, and a restore you have actually tested. This carries far more load than most teams expect, costs a fraction of the fancier options, and every engineer you hire already knows it. Earn your way off it with measurements.
S3 · 05 Regional vs multi-region vs global — the deliberate choice
How far should this database spread?
Every step down this tree multiplies write latency, cost and operational complexity. Start at the bottom and justify each move up.
  1. Is there a hard regulatory requirement that data stay in one jurisdiction?
    yes →Single region, and the conversation is over. Add zone redundancy inside it.
    no ↓
  2. Would losing the last few seconds of writes in a regional disaster be acceptable?
    yes →Cross-region async replica — Aurora Global Database, Azure failover groups, Cloud SQL cross-region replica. RPO seconds, RTO minutes, cheap, and writes stay fast because they never wait for the far region.
    no ↓
  3. Do users on other continents need low-latency reads only, with writes still funnelled to one place?
    yes →Global read replicas with write-forwarding. Local reads are fast; writes pay the round trip to the home region. Covers a surprising share of “we need a global database” requests.
    no ↓
  4. Must users on multiple continents write the same records, with every reader seeing the latest value, and RPO exactly zero?
    yes →Globally distributed strong SQL: Spanner or Aurora DSQL. Genuinely remarkable engineering; you pay in commit latency and money.
    no ↓
  5. Must they write concurrently but can you tolerate conflict resolution and brief divergence?
    yes →Multi-active NoSQL — DynamoDB global tables, Cosmos DB multi-region writes. Session 4. Cheaper and faster than global SQL, and you own the reconciliation logic.
    no ↓
Default
One region, zone-redundant, with backups replicated to a second region
This gives you survival of a datacentre failure with zero data loss and no added write latency, plus a recovery path from a full regional loss measured in hours rather than seconds. For the overwhelming majority of systems — including nearly every internal platform and every AI inference stack that isn't consumer-scale — this is the correct, boring, defensible answer. “Global” is a business requirement, not an engineering aspiration; make someone state the RPO and the acceptable write latency out loud before you build for it.
S3 · 06 Reality check

Worked example · when does a read replica beat a bigger primary?

A Postgres workload on a managed 8-vCPU / 32 GB instance is at 85% CPU. Traffic is 90% reads. Two options; representative on-demand pricing, one US region.

Option A · double the primary (16 vCPU / 64 GB)
Primary compute$0.68/h
Standby (Multi-AZ)$0.68/h
Storage 500 GB gp3$0.055/h
≈ monthly$1,033
read capacity
write capacity
downtime to changeone restart
Option B · keep 8 vCPU, add two read replicas
Primary compute$0.34/h
Standby (Multi-AZ)$0.34/h
2 × read replica$0.68/h
Storage (replicas have their own)$0.165/h
≈ monthly$1,113
read capacity≈3×
write capacity1× (slightly worse)
app change requiredroute reads

Verdict: at this size the two cost almost the same, and vertical scaling wins because it needs no application change and helps writes too. The maths flips at scale and at the edges:

  • Replicas win when you've run out of instance sizes; when reads are geographically distant (a replica in-region beats a fast primary across an ocean); when you want reporting isolated so one bad analytical query can't take production down; or when read demand is spiky and you can add and remove replicas.
  • Bigger primary wins when writes are also growing, when your application can't cleanly separate read and write connections, or when replica lag would break correctness.
  • Neither wins if the real problem is a missing index or an N+1 query. Check that first — it is free, and it is the answer more often than either option above.
Second worked example · Aurora Serverless v2 vs provisioned — where's the break-even?

Aurora Serverless v2 bills roughly $0.12 per ACU-hour, where 1 ACU ≈ 2 GiB of memory plus matching CPU. A provisioned db.r6g.large (2 vCPU / 16 GiB) is roughly $0.29/hour on demand — about the capacity of 8 ACUs.

Break-even
Serverless at 8 ACUs, 24×7$0.96/h · $700/mo
Provisioned r6g.large, 24×7$0.29/h · $212/mo
Serverless at 8 ACUs for 3 h/day, 0 ACUs otherwise≈ $88/mo
Rule of thumb>~35% duty cycle → provisioned

Reserved instances push provisioned further ahead again (40–72% off for commitments). So: Serverless v2 for dev, test, demos, internal tools and genuinely spiky production; provisioned for steady load. And in both cases Aurora storage at ~$0.10/GB-month keeps billing even at 0 ACUs — a “paused” 500 GB cluster is still $50/month. Deleting the cluster is the only way to stop that.

Three real, current examples

Global database case study

Target and True Digital on Spanner

Google's 2026 customer write-up describes Target choosing Spanner Graph for product recommendations, blending graph traversals with vector search over proprietary embeddings and shipping it in time for the 2025 Black Friday / Cyber Monday peak; and True Digital Group (Thailand) consolidating a fragmented multi-database search stack onto Spanner after inconsistent tokenisation and stale data drove users away from search entirely. The recurring theme is not “we needed global writes” — it is consolidation: one strongly-consistent engine replacing several specialised ones that had each hit a scale or consistency wall.

Independent-ish validation

Analyst and TEI numbers, read carefully

Gartner ranked Google (Spanner) #1 in the Lightweight Transactions use case in its 2025 Critical Capabilities report for operational cloud DBMS — second consecutive year — and a Forrester Total Economic Impact study commissioned by Google modelled a composite organisation at 132% ROI with a nine-month payback. Worth knowing because these numbers appear in procurement decks. Worth discounting because a vendor-commissioned TEI models a composite, not your workload. Use them as evidence the category is credible, not as a forecast.

The competitive answer

Aurora DSQL exists now, and it changes the AWS answer

Aurora DSQL previewed at re:Invent 2024 and reached GA on 27 May 2025, with active-active multi-region writes, multi-region strong consistency, 99.999% multi-region availability and PostgreSQL compatibility, billed in DPUs with no upfront commitment. Practical consequence for you: “global strongly-consistent SQL means moving to GCP” stopped being true in 2025. Practical caution: it is a different engine, not Aurora with new billing — evaluate the SQL surface against your schema before assuming a migration is a lift-and-shift.

S3 · 07 Apply it · your context

Where a relational database fits in your inference pipeline

A GenAI serving stack usually has no obvious database — right up to the moment you need to answer “which model version served this request, and what did the eval say?”. Then you discover you've been keeping that state in log files, S3 keys and someone's spreadsheet. The relational database is the control plane of your inference platform:

EntityWhy relational, specificallyRough scale
Model registry — model, version, base checkpoint, quantisation, weight URI, statusForeign keys to deployments and evals; you will invent new queries about it constantlyhundreds of rows
Deployments — endpoint, replica count, GPU type, autoscaling bounds, current model versionMust be transactionally consistent with the registry: a deployment pointing at a deleted model version is a live incidenttens of rows
Eval runs — dataset version, metrics, judge model, timestampJoins across model × dataset × metric are the whole point, and you cannot predict the cuts you'll wantthousands
Jobs / batch inference — status, retries, idempotency keySELECT … FOR UPDATE SKIP LOCKED makes a managed Postgres a perfectly good job queue at your scale, and one fewer service to runthousands/day
Per-request logs — prompt, response, tokens, latencyNot here. Firehose → object storage → warehouse. Putting these in the OLTP database is the single most common way teams accidentally destroy their control plane's performancemillions/day

Concretely for your stack: Cloud SQL for PostgreSQL in the same region as your Vertex AI endpoints and L4/T4 nodes — one instance, HA enabled, PITR on, private IP so it's reachable over C4's private networking rather than a public endpoint, and Secret Manager for the credentials rather than environment variables. On AWS the identical design is RDS for PostgreSQL Multi-AZ. From GKE or Vertex, connect through the Cloud SQL Auth Proxy / IAM database authentication so there's no long-lived password at all.

One GenAI-specific note Managed Postgres on all three clouds now ships pgvector. That makes “add embeddings to the control-plane database” tempting, and for a modest corpus it is genuinely the right call — one database, transactional consistency between a document and its embedding, no extra service. It stops being right somewhere in the millions-of-vectors range, where a purpose-built index earns its keep. That threshold conversation belongs to your RAG track; here, just note that the option exists and that the default answer for a small corpus is “use the database you already have”.
Optional hands-on · ~30 minutes · a few cents on the smallest SKU

Lab S3 — stand up the smallest possible managed Postgres, then fail it over

Budget alert first, smallest SKU only, and read the teardown before you start.

  1. Budget alert: $5 with an email trigger at 50%. Non-negotiable — a database is the easiest thing in this stage to leave running.
  2. Create the smallest managed PostgreSQL available: db.t4g.micro (RDS), Burstable B1ms (Azure flexible server), or a shared-core Cloud SQL instance. Single zone to start. Public access off; connect from a small VM or Cloud Shell in the same network.
  3. Create a two-table schema: model_version and deployment, with a foreign key. Insert a handful of rows.
  4. Run a transaction that updates both tables, and deliberately roll it back. Confirm neither change persisted — that's atomicity, which is the entire reason you chose this engine.
  5. Enable HA / Multi-AZ / zone redundancy. Note the price change in the console before you confirm.
  6. Press force failover. Time it with a stopwatch while a loop runs SELECT 1 every 200 ms. Write down the number of failed attempts. That number is your real RTO — not the one in the marketing page.
  7. Take a snapshot, then do a point-in-time restore to five minutes ago into a new instance. This is the step everyone skips and the one that matters most.
Teardown — same day, in this order
  1. Delete the restored instance first, then the primary. A PITR restore creates a whole second database that bills exactly like the first — this is the most expensive thing in this lab.
  2. Turn off “retain automated backups” / delete manual snapshots. Snapshots survive instance deletion by design and keep billing for storage. Deleting the instance is not enough.
  3. Delete read replicas before the primary if you created any — some services block primary deletion until replicas are gone.
  4. Check for orphaned block volumes and static IPs left behind by the helper VM, if you used one. Volumes bill from creation to deletion regardless of attachment.
  5. Remember: provisioned database compute bills per hour whether or not a single query arrives. An idle t4g.micro is a few dollars a month; an idle instance you sized “for the demo” at 8 vCPU is a few hundred. Check the size before you walk away, and prefer to delete rather than stop.
  6. Keep the budget alert.
Bridge → S4

Session 3 assumed the answer was “rows and transactions”. Session 4 covers everything you reach for when it isn't: document, key-value and wide-column stores, the caching tier in front of all of them, and the columnar warehouses at the end of the pipeline — plus the partition-key design that decides whether your NoSQL table scales or throttles.

S4 · 01 Why this session exists

NoSQL doesn't fail slowly. It works beautifully at 10× your test load and then throttles at 11× because of one line of schema you wrote in week two.

Relational databases forgive a bad schema — the query planner works around it, and you add an index later. NoSQL does not. In a distributed key-value or wide-column store, the key is the physical layout: it decides which machine holds the data, which means it decides whether load spreads or concentrates. Choose it before you know your access patterns and you will discover the mistake in production, at scale, on a Friday.

So this session is really two things: the shapes (document, key-value, wide-column, cache, columnar) and the one design skill that makes or breaks all of them — partitioning.

Callback · S1 Every engine here is an Application Database in the patterns catalog's sense, and most are Replicated Databases that chose AP or tunable-C on the CAP triangle. Everything you learnt about eventual consistency in S1 is about to become a per-request pricing decision.
S4 · 02 Core concept 1 · the three NoSQL shapes
Pass 1 Intuition
Document

A filing box of self-contained forms. Each form carries everything about one thing — order, plus line items, plus address — so you fetch one form and you're done. Different forms can have different fields. No joins, because everything you need is already on the page.

Key–value

A cloakroom. Ticket in, bag out. There is no “find me all the blue bags” — that question simply doesn't exist in the API. In exchange it is the fastest and cheapest operation in computing.

Wide-column

A library shelf sorted by one scheme. Sources are physically ordered by call number, so “everything from A340 to A390” is one sweep of the hand. Ask for “everything by this sources” and you're walking the whole library. One sort order, chosen once.

Pass 2 Mechanism · the partition key decides everything

All three shapes distribute data the same way: hash or range the key, assign to a partition, put partitions on machines. The API you get is a direct consequence.

Interactive — hover / tap
GOOD KEY — high cardinality, evenly requested PK = USER#4B54B8PK = USER#2E7D4FPK = USER#B3641F hash → P1~33% load P2~33% load P3~33% load table throughput = sum of partitions ✓ scales linearly, no throttling HOT KEY — the failure that looks like a service outage PK = GLOBAL_COUNTERPK = GLOBAL_COUNTERPK = GLOBAL_COUNTER hash → P1100% · THROTTLED P2idle P3idle hard ceiling: ~3,000 RCU / 1,000 WCU per partition table has spare capacity · requests still fail adaptive capacity helps, cannot break the ceiling THE FIX — write sharding Append a suffix to spread one logical key across N physical partitions: PK = GLOBAL_COUNTER#0 … GLOBAL_COUNTER#9 Writes: pick a suffix at random → 10× the write ceiling. Reads: query all N and merge — you traded read complexity for write capacity. Same trick, other names: salting (Bigtable/Cassandra), synthetic partition key (Cosmos DB). Choose N deliberately; it is hard to change later.
Hover or tap a row.
Terms
Partition key
The attribute hashed to choose a partition. Determines where data lives. Also called the hash key, shard key, or (Bigtable) the leading part of the row key.
Sort key
An optional second attribute that orders items within a partition. Partition key + sort key together form the primary key and enable efficient range queries.
Cardinality
How many distinct values a key has. High cardinality is what makes load spread; tenant_id in a 5-tenant system is low cardinality and will bite you.
Hot key / hot partition
One key or partition absorbing a disproportionate share of traffic and hitting its per-partition ceiling while the rest of the table idles.
RCU / WCU · RRU / WRU
DynamoDB's capacity units. 1 WCU = one 1 KB write per second; 1 RCU = one strongly-consistent 4 KB read per second, or two eventually-consistent ones. The RRU/WRU variants are the per-request (on-demand) equivalents.
RU/s
Cosmos DB's request unit per second — a single blended currency covering CPU, IOPS and memory. A 1 KB point read costs 1 RU; everything else is priced relative to that.
GSI
Global secondary index — a second copy of the table with a different partition key, so you can query by something other than the primary key. It has its own capacity and every base-table write also writes the index.

The schema is the mechanism here, so this is the one snippet that belongs in Pass 2:

# The whole design decision, in six lines. Access pattern first:
#   "get all inference jobs for one tenant, newest first"
PartitionKey: "TENANT#{tenant_id}"       # WHERE the data lives — spreads load
SortKey:      "JOB#{iso8601_ts}#{job_id}"  # ORDER inside the partition
# → query(PK = TENANT#42, SK begins_with "JOB#14201B-07") is ONE partition read.
# → "all jobs across all tenants by status" is NOT answerable. Add a GSI, or
#   accept a full scan. Decide this now, not after launch.
Pass 3 Trade-offs · the four ways NoSQL bills surprise you
  1. Indexes multiply writes. Every global secondary index is a second table maintained synchronously. Three GSIs means a single logical write costs roughly four writes. This is the most common reason a DynamoDB bill lands at 3× the estimate.
  2. Item size is a multiplier, not a footnote. A write unit covers 1 KB. A 3.5 KB item costs 4 write units — so a schema change that adds a verbose field to a hot table can quadruple the bill without a single extra request.
  3. Consistency is priced. A strongly-consistent read costs twice an eventually-consistent one, on DynamoDB and Cosmos DB alike. Defaulting the whole application to strong is a decision to double your read bill, usually for no user-visible benefit.
  4. Cross-region replication multiplies writes again. A global table writes in every replica region; three regions means roughly 3× the write charges plus cross-region transfer.
The materials are stale on the capacity-mode advice The standard cert-guide line is “on-demand is convenient but 5–6× more expensive; use provisioned”. AWS cut on-demand throughput prices by 50% in November 2024 and added DynamoDB Database Savings Plans in December 2025 (up to ~18% further off). On-demand is now the more cost-effective choice for a much wider band of workloads, and the crossover point is well above where the old advice put it. Do the arithmetic for your own request rate — there's a worked one below.
S4 · 03 Three clouds · NoSQL
AWS · DynamoDB
What it is
A managed key-value and document store. Partition key (+ optional sort key), single-digit-millisecond latency at essentially any scale, no servers or version upgrades ever.
Capacity modes
On-demand ≈ $1.25 per million write request units, $0.25 per million read request units (strongly consistent), storage $0.25/GB-month Standard or $0.10 Standard-IA. Provisioned bills per hour for reserved RCU/WCU and supports auto-scaling and reservations.
quirk The always-free tier (25 RCU + 25 WCU + 25 GB) applies to provisioned mode only — an on-demand table gets no free capacity units.
Global tables
Multi-region, multi-active. Since June 2025 also available with multi-region strong consistency (MRSC) — RPO zero, strongly consistent reads from any replica — plus an optional witness region that joins the consistency protocol without storing a full replica, cutting cost.
watch Only writes change price on a global table (standard units become replicated units); reads and storage bill per region as normal. And GSI updates bill as standard write units even on a global table.
Adjacent
DAX — a DynamoDB-native microsecond cache. Keyspaces — managed Cassandra (wide-column). MemoryDB — Redis-compatible with durability, so it can be a primary database rather than only a cache.
Azure · Cosmos DB
What it is
One engine, several wire protocols: NoSQL (native JSON), MongoDB, Cassandra, Gremlin (graph) and Table APIs. Pick the API at account creation; it is effectively permanent.
Five consistency levels S1 made concrete
Strong → Bounded staleness → Session → Consistent prefix → Eventual. Set a default per account and override per request. Session is the default and usually the right answer: a client always reads its own writes, others may lag.
quirk This is the clearest commercial expression of PACELC anywhere: the consistency level you pick literally changes the request-unit price of a read.
Throughput
Everything is RU/s — provisioned manually, autoscaled between a floor and 10× ceiling, or serverless (pay per request). Free tier now grants 1,000 RU/s and 25 GB permanently.
watch RU/s is allocated per physical partition, so an uneven partition key wastes provisioned throughput exactly like a DynamoDB hot key. The 20 GB logical-partition size limit is a hard one — design so no single partition-key value can grow past it.
Vector search
DiskANN-based vector indexing in the NoSQL API, plus hybrid search combining vectors with BM25 full-text and semantic ranking, priced in the same RUs as any other query.
Google Cloud · Firestore & Bigtable
Firestore — document
Serverless document database with real-time listeners and offline sync (its Firebase heritage, and a genuine differentiator). Now sold in editions: Standard (priced per document read/write) and Enterprise (MongoDB-compatible API, advanced query engine, priced per bytes read/written, larger document limits).
quirk Firestore auto-indexes every field. Wonderful until a write-heavy collection makes indexing the dominant cost — exclude fields you never query.
Bigtable — wide-column
The engine behind Search, Ads and YouTube-scale workloads. Petabytes, millisecond writes, HBase-compatible API, up to 99.999% availability.
the whole design Rows are stored lexicographically by row key and there is exactly one such order. So userid#reverse_timestamp is a good key and timestamp#userid is a catastrophic one — the latter sends every write to the same end of the keyspace, hotspotting one node. Salt or field-promote to spread it.
Memorystore — cache
Managed Valkey (GA 2025, the open-source Redis fork and now Google's lead recommendation), Redis, Redis Cluster and Memcached. Instances to ~14.5 TB, 99.99% SLA, cross-region replication.
S4 · 04 Core concept 2 · the caching tier
Pass 1 Intuition

A cache is a bet that you'll be asked the same question again soon. It's the notepad next to the phone: you write down the answer you just looked up, because looking it up again costs more than reading your own handwriting. And like a notepad, the danger isn't losing it — it's trusting it after the answer has changed.

Pass 2 Mechanism · the patterns, and the one that will page you
CACHE-ASIDE (lazy loading) — the default 1 · app asks cache → HIT: return (≈0.5 ms, done) 2 · MISS: read database, write to cache with a TTL, return 3 · on update: write DB, then DELETE the cache key (don't update it) WRITE-THROUGH — for read-heavy, must-be-fresh 1 · every write goes to cache AND database, synchronously 2 · reads are therefore always warm and always current 3 · cost: every write pays both hops; cold data is cached needlessly THE STAMPEDE — how a cache causes the outage it was meant to prevent A popular key expires. 5,000 concurrent requests all miss simultaneously and all hit the database with the identical query. The database, sized for a 2% miss rate, receives 100% of traffic in one instant and falls over. The cache then can't refill. Cascade. Fixes: jitter the TTLs · single-flight / request coalescing per key · serve-stale-while-revalidate · pre-warm keys you know are hot.
Pass 3 Trade-offs
AWS
ElastiCache
Managed Redis OSS, Valkey and Memcached. Serverless option available.
MemoryDB
Redis-compatible with durable multi-AZ transaction log — a primary database, not just a cache.
DAX
Write-through cache that speaks the DynamoDB API, so it needs no application changes. Microsecond reads.
Azure
Azure Managed Redis the new name
GA, built with Redis, clustered by default, better price/performance than the old service.
retirement Azure Cache for Redis Enterprise/Enterprise Flash retire 31 March 2027; Basic, Standard and Premium retire 30 September 2028, after which un-migrated caches are disabled. Migration tooling started rolling out in early 2026 and preserves hostname and access key. Anything you design or answer today should say Azure Managed Redis.
Google Cloud
Memorystore for Valkey
GA 2025, Valkey 8/9, up to ~14.5 TB, 99.99% SLA, cross-region replication, Private Service Connect. Google's lead recommendation.
Memorystore for Redis / Redis Cluster / Memcached
Still available; Redis Cluster does zero-downtime scaling.
Should this be cached?
Follow “no ↓”. First “yes” exits right. Bottom-left is the default.
  1. Is the underlying store already single-digit-millisecond and comfortably within capacity?
    yes →Don't cache. You'd add an invalidation bug surface and a new failure mode to save nothing. This exits right far more often than people expect.
    no ↓
  2. Would serving a value a few seconds stale cause a correctness problem — money, stock, permissions?
    yes →Don't cache it, or cache with explicit invalidation on write and a very short TTL, and accept that you now own a distributed-systems problem.
    no ↓
  3. Is the same key read many times between writes, and is the computation or query genuinely expensive?
    yes →Cache-aside with a jittered TTL and single-flight on miss. The standard, correct answer.
    no ↓
  4. Is it session state, a rate-limit counter, a leaderboard, or a job queue?
    yes →Redis/Valkey data structures — sorted sets, hashes, streams. This is cache infrastructure used as a database, and it's legitimate: use a durable variant (MemoryDB, or persistence enabled) if losing it matters.
    no ↓
Default
No cache — fix the query or the index first
A cache is a permanent operational commitment bought to fix a temporary performance problem. Most “we need Redis” conversations end when someone adds the missing index or removes the N+1. Add the cache when you've measured the hit rate you'd get and the latency you'd save, and when you know precisely what invalidates each key.
S4 · 05 Core concept 3 · a first look at analytics
Pass 1 Intuition

Everything so far answers “what is the state of this one thing right now?”. The warehouse answers “what happened across everything, over time?”. Different question, different physics (columnar, from S1), different service, and — critically — a different billing model: you generally pay for bytes scanned or for reserved compute slots, not for rows stored.

Pass 2 Mechanism · the pipeline, and where object storage sits
OLTProws · your appms point reads CDC / batch LAKE (object)Parquet / Icebergcheap, open, huge transform WAREHOUSEcolumnar · MPPseconds over 1e9 rows BI · evals · dashboards · model training sets for you: eval aggregates, token-cost analysis, drift monitoring and the labelled data your next fine-tune comes from The lake is object storage from Session 2 — which is why S2 sits underneath every data platform. Open table formats (Apache Iceberg, Delta) put transactions and schema evolution on top of those files, so several engines can query the same bytes without copying them into a proprietary store.
AWS
Redshift
MPP columnar warehouse; Serverless option bills by capacity used.
Athena
Serverless SQL directly over S3 — pay per TB scanned. The cheapest way to answer an occasional question over a lake.
S3 Tables
Managed Apache Iceberg tables as a first-class S3 bucket type.
Azure
Microsoft Fabric
The strategic platform: OneLake storage, Direct Lake for Power BI, Eventhouse for real-time, Spark and warehouse engines, capacity-based billing.
stale-source alert §11 teaches Azure Synapse Analytics as the warehouse. Synapse is still supported with no announced end-of-life, but it is maintained rather than evolved — Fabric gets the net-new investment. Some pieces are already gone: Synapse Data Explorer retired in favour of Fabric Eventhouse, and Synapse Link for Cosmos DB is closed to new projects in favour of Cosmos DB mirroring into Fabric. For new build, learn Fabric; for the exam, know both and know which is which.
Google Cloud
BigQuery
Serverless columnar warehouse; on-demand priced per TB scanned, or capacity-based editions (Standard / Enterprise / Enterprise Plus) with autoscaling slots.
quirk On-demand billing makes SELECT * genuinely expensive and column pruning genuinely free. Partition and cluster your tables; the difference between a partitioned and unpartitioned scan is often two orders of magnitude on the invoice.
Also in it
BigQuery ML (train models in SQL), vector search for RAG, and BigQuery Graph. The warehouse is increasingly where GenAI feature work happens.
Pass 3 Trade-offs

Two numbers decide the warehouse billing model. On-demand / per-TB-scanned wins for sporadic, exploratory use — you pay nothing between queries. Capacity / slot / reservation wins once queries are frequent and predictable, and it also caps the blast radius of somebody's accidental unfiltered scan. The migration point usually arrives the month after a dashboard goes live and starts auto-refreshing every five minutes.

S4 · 06 The pick-the-right-database map

Session 1's tree, now with names on the exits. This is the artefact to keep.

If the workload is…ShapeAWSAzureGoogle Cloud
Transactions, joins, unpredictable queriesRelationalRDS · AuroraAzure SQL DB · PG flexible serverCloud SQL · AlloyDB
Global writes, strong consistency, RPO 0Distributed SQLAurora DSQLCosmos DB (strong)Spanner
Fetch/replace one self-contained record by id, huge scaleDocument / KVDynamoDBCosmos DB (NoSQL API)Firestore
High-volume time-ordered events, one sort orderWide-columnKeyspaces · TimestreamCosmos DB (Cassandra API)Bigtable
Sub-millisecond reads of a derived copyCacheElastiCache · MemoryDB · DAXAzure Managed RedisMemorystore (Valkey)
Scan-and-aggregate over historyColumnar OLAPRedshift · AthenaMicrosoft FabricBigQuery
Relationship traversal several hops deepGraphNeptuneCosmos DB (Gremlin)Spanner Graph
Nearest-neighbour over embeddings (RAG track)VectorOpenSearch · pgvector on RDS/Aurora · S3 VectorsCosmos DB DiskANN · AI SearchVertex AI Vector Search · pgvector on AlloyDB · Spanner/BigQuery vector
The vector row is listed for completeness and belongs to your RAG track — note the adjacency, don't design it here.
S4 · 07 Reality check

Worked example · on-demand vs provisioned at a real request rate

A metadata table for your inference platform: 500 writes/second and 2,000 reads/second sustained, average item 1.5 KB, reads eventually consistent, 100 GB stored. Current US pricing.

On-demand
1.5 KB item → 2 WRU per write
Writes: 500/s × 2 × 2.63M s/mo = 2,630M WRU$3,288
1.5 KB eventually-consistent read → 0.5 RRU
Reads: 2,000/s × 0.5 × 2.63M = 2,630M RRU$658
Storage 100 GB × $0.25$25
Monthly$3,971
Provisioned + auto-scaling
1,000 WCU × $0.00065/h × 730$475
1,000 RCU × $0.00013/h × 730$95
Storage 100 GB × $0.25$25
Monthly$595
…if the load really is flat 24×7

At a genuinely constant load, provisioned still wins by a wide margin — roughly 6.7×. But run the same table at a realistic duty cycle: a platform whose traffic is concentrated in an 8-hour working day and near-zero overnight consumes about a third of those request units, so on-demand falls to roughly $1,300/month while provisioned-for-peak stays at $595 only if auto-scaling tracks the curve well — and auto-scaling reacts in minutes, so you must provision above the peak to avoid throttling during ramps. Add weekend troughs and unpredictable eval bursts and the two converge fast.

The rule that survives the arithmetic: predictable and flat → provisioned (plus a Savings Plan). Spiky, unknown or bursty → on-demand. And the November 2024 price cut moved that boundary meaningfully toward on-demand, so recompute rather than reusing a 2023 heuristic.

Break it · the hot-key blow-up Same table, one schema decision different. Someone adds a per-tenant rate limiter keyed PK = TENANT#{id}, and one enterprise tenant generates 60% of traffic. All of that tenant's writes hash to a single partition, which is capped at 1,000 write units per second regardless of table-level capacity. At 500 writes/s × 2 WRU × 60% = 600 write units on one partition you're fine; grow 2× and you throttle — while CloudWatch shows the table using a fraction of its provisioned capacity. Engineers spend a day raising table capacity, which changes nothing.

The fix is write sharding: PK = TENANT#{id}#{shard 0–9}, writes pick a shard at random, reads query all ten and merge. Ten times the write ceiling for that tenant, at the cost of a fan-out read. Use CloudWatch Contributor Insights to find the offending keys — it is built exactly for this and almost nobody turns it on.

Three real, current examples

Cost blow-up · indexes

“My bill is 3× the estimate”

A 2026 pricing breakdown models the classic path: a team reads the rate card, projects ~$200/month, adds a few global secondary indexes, enables backups and a global table, and lands at $800–$2,400. The mechanism is unglamorous — each GSI is another synchronous write per base-table write, backups and streams bill separately, and global tables multiply writes per region. None of it is hidden; all of it is easy to leave out of the model.

Vector search inside the operational DB

Cosmos DB's DiskANN result

Microsoft's published research on integrating DiskANN into Cosmos DB NoSQL reports sub-20 ms query latency over a 10-million-vector index, recall that stays stable under updates, and roughly 43× and 12× lower query cost than two specialised serverless vector products. Take the comparison with the usual grain of salt — it's the vendor's own paper — but the architectural claim is the important one: for many RAG workloads a vector index inside the operational database beats a separate vector service on both operational complexity and cost. Your RAG track should test that claim rather than assume a dedicated vector DB.

Global NoSQL grew up

Strong consistency across regions, without Spanner

DynamoDB global tables reached GA with multi-region strong consistency in June 2025 — RPO zero, latest-value reads from any replica region — including a witness region that participates in the consistency protocol without holding a full replica, which removes that region's storage, replicated-write and transfer charges. Design consequence: “strong consistency across regions requires relational distributed SQL” is no longer true. The NoSQL option is real, and the witness trick makes three-region quorums materially cheaper than they used to be.

S4 · 08 Apply it · your context

Where each of these belongs in a GenAI serving stack

NeedShapeConcretely, on your stack
Prompt → response cache for repeated or near-identical requestsCacheRedis/Valkey keyed on a hash of (model version + normalised prompt + sampling params). Include the model version in the key or a model swap serves stale generations. This is the highest-ROI cache in an inference stack — a cache hit costs a fraction of a cent and skips the GPU entirely.
Per-tenant rate limiting and quotaCache / KVRedis counters with TTL. Beware the hot-key pattern from above — a single high-volume tenant is exactly the shape that throttles. Shard the counter key.
Conversation / session history for multi-turn chatDocumentDynamoDB / Cosmos DB / Firestore, partition key = conversation_id, sort key = turn timestamp. Naturally high cardinality, naturally range-queried, exactly the shape these engines are best at.
Token-usage and latency telemetryWide-column or warehouseBigtable if you need per-second granularity at high write volume; otherwise straight to object storage and BigQuery/Redshift/Fabric. Row key tenant#reverse_ts, never ts#tenant.
Eval results, cost analysis, drift monitoringColumnar OLAPBigQuery over your logs in GCS. This is where “which model version had the best judge score per dollar” gets answered, and it's a scan-and-aggregate question by nature.
Model registry, deployments, job stateRelationalSession 3's answer, unchanged. Don't let the NoSQL enthusiasm of this tab move it.
Embeddings for retrievalVector (RAG track)Flagged, not designed here. Note only that the 2026 default has shifted toward “vector index inside a database you already run” — pgvector on managed Postgres, Cosmos DB DiskANN, Spanner/BigQuery vector search — rather than a separate vector service. Test that in your RAG track.
The Modal / Vertex / GKE tie-in Your current stack is stateless-by-accident: Modal Volumes hold weights, and everything else lives in logs. Adding the three pieces above — a Postgres control plane (S3), a Redis prompt cache (this tab) and a log path into object storage plus a warehouse (S2 + this tab) — turns it into a platform. Do them in that order: the control plane first, because it's the one you can't retrofit cheaply; the cache second, because it pays for itself immediately in avoided GPU seconds; the analytics path last, because object storage is append-only and you can always process the backlog later. That ordering is itself the architectural point of this stage.
Optional hands-on · ~25 minutes · pennies, if you tear down

Lab S4 — build a hot partition on purpose, then fix it

Budget alert first. Smallest capacity settings only. Read the teardown before you start.

  1. Budget alert: $5, email at 50%.
  2. Create one NoSQL table in provisioned mode with the smallest capacity the service allows — on DynamoDB, 5 RCU / 5 WCU, which sits inside the always-free tier. Partition key pk (string), sort key sk (string).
  3. Write 200 items with pk = "GLOBAL" and sk = <timestamp> as fast as a small script can. Watch the throttling metrics appear. This is the failure mode, reproduced in one minute for free.
  4. Now write 200 items with pk = "GLOBAL#" + random(0..9). Same total volume, no throttling. That's write sharding, and you've now felt the difference rather than read about it.
  5. Turn on Contributor Insights (or the equivalent key-diagnostics feature) and confirm it names your hot key. Turn it back off afterwards — it bills separately.
  6. Query with a strongly-consistent read and then an eventually-consistent one, and compare the consumed capacity reported in the response. The 2× difference from Pass 3 becomes a number you've seen.
  7. Optional, on Cosmos DB instead: create a serverless account, set consistency to Session, then to Strong, and compare the RU charge for the same query. Same lesson, different currency.
Teardown — same day, and this one has real traps
  1. Delete the table. Provisioned throughput bills per hour, whether or not a single request arrives. A forgotten table provisioned at a few hundred capacity units is a genuinely unpleasant surprise, and unlike a VM there's nothing to “stop”.
  2. Delete global table replicas first if you created any — each replica region bills its own storage and replicated writes.
  3. Turn off Contributor Insights / diagnostics — separate line item, easy to forget.
  4. Delete on-demand backups and turn off point-in-time recovery. Backups outlive the table by design and keep billing for stored bytes.
  5. Delete any cache cluster immediately. An in-memory cache is billed on provisioned node-hours and is one of the more expensive things per hour in this stage — a small Redis node left running for a month costs far more than everything else in these four labs combined.
  6. If you ran a warehouse query, check the scanned-bytes charge and delete any datasets/tables you created. On per-TB-scanned billing, a single careless SELECT * over a large public dataset can cost real money — always preview with a dry run and a LIMIT won't save you (it still scans).
  7. Keep the budget alert. You now have four labs' worth of reasons why.
S4 · 09 C5 closing check

You should now be able to, without looking anything up

  • Say why a database's data files go on block storage and its backups go on object storage.
  • Convert 99.95% into minutes per month, and say what topology buys it.
  • Explain why a strongly-consistent global read costs latency, and name two services that make you pay for it explicitly.
  • Recite the four object-storage temperatures and the minimum-duration trap on each cloud — including that Google's Archive is 365 days.
  • Diagnose “my NoSQL table throttles while showing spare capacity” in one sentence.

The five habits worth keeping

  1. Name the access shape before naming a service.
  2. Check the minimum duration before every tiering decision.
  3. Default to the boring managed relational database, and earn your way off it with measurements.
  4. Design the partition key from the access pattern, on paper, before you create the table.
  5. Write the expiration rule and the teardown step at the same time you create the resource.
Bridge → C6

State now has a correct home on all three clouds. The open question this stage deliberately left unanswered: when the region holding it disappears, how do you get it back — and how fast? That's resilience, backup and disaster recovery, where the RPO and RTO numbers you've been quoting all stage finally get designed against rather than described.

← C4The path
Next stage · C6 →genaipros · C5 · Storage & DataAI for Everyone ↗