GCP Lesson 65 of 98

GCP Well-Architected: System Design — Core Principles, Geography & Regions, the Resource Hierarchy, Networking Foundations, and Choosing Compute, Storage & Databases

In a nutshell

System design is the skill of turning a set of requirements (“a payments API that must never lose a transaction, stay up during a festival sale, and keep Indian data in India”) into a concrete architecture (“Cloud Run in front, Spanner for the ledger, Pub/Sub between them, all in asia-south1 + asia-south2”). The trap beginners fall into is starting from the services — “let’s use Spanner!” — and reverse-engineering a problem to fit. Good architects do the opposite, and they do it the same way every time, running a short repeatable method.

Think of it like planning a new hospital. You do not begin by choosing the brand of the MRI machine. You begin by asking how many patients per day, how fast the emergency room must respond, what must legally stay on-site, and what happens when the power fails — and once those numbers are on the wall, the equipment choices fall out almost on their own. The method in this lesson is that same discipline for software: requirements → capacity estimate → API & data model → compute, storage & data choices → scaling & caching → reliability & DR → cost. Each step’s answer is the next step’s input, and the moment you can name the numbers, the right Google Cloud building block is usually obvious.

Google Cloud hands you a menu of managed building blocks — Cloud Run, GKE, and Compute Engine for compute; Cloud SQL, Spanner, Firestore, and Bigtable for data; Pub/Sub and Cloud Tasks for wiring services together — and the entire craft is matching each block to a requirement you can defend. This lesson has two halves that serve that craft. The first half (this method and a worked example) is how to think — the sequence you run at a whiteboard, in a design review, or in a system-design interview. The second half (the Google Cloud Architecture Framework’s System Design pillar — principles, geography, the resource hierarchy, networking, and the compute/storage/database decision tables) is what to pick — the detailed menu each step of the method reaches into. A total beginner can follow the method; an experienced engineer will still find sharp edges in “Going deeper.”

Level: Advanced · Time: ~45 min

Prerequisites: You should be comfortable with the idea that a project is your billing-and-resource boundary and that resources live in regions and zones, and know roughly what a virtual machine, a relational database, and a load balancer are. You do not need to have used any of these services in anger — the method is the map that ties them together. If the foundational shape of a web app on GCP is unfamiliar, read Three-tier web application: the foundational build first; it is the gentle, concrete companion to this more abstract lesson.

After this lesson you can:

The architect's method: requirements → capacity → API & data model → compute & data choices → scale/cache → reliability/DR → cost

Read the diagram left → right: the non-functional numbers on the far left size everything downstream, the access patterns pick the compute and the datastore in the middle, and caching, DR, and cost harden the design on the right — name a GCP service only once the requirement above it forces the choice.

Where this fits

The Google Cloud Architecture Framework is Google’s body of guidance for building and running workloads on Google Cloud, organized into pillars — System Design, Operational Excellence, Security, Privacy & Compliance, Reliability, Cost Optimization, and Performance Optimization — sitting on top of a set of cross-cutting core principles. System Design is the foundational pillar — part 1 of the series — and it is deliberately first, because it is where you make the structural, hard-to-reverse decisions that every other pillar later inherits: where your data physically lives (geography and regions), how your environment is organized for governance and billing (the resource hierarchy), how packets move and what is reachable (networking foundations), and which managed primitives you build on (compute, storage, and databases). Get System Design right and reliability, cost, and performance become tuning problems; get it wrong and they become migration projects.

Google Cloud Architecture Framework — animated overview

The architect’s method — from requirements to cost

The framework pillars below tell you the principles and hand you the menu of services. The method is the repeatable sequence you actually run against a blank page. It is the same whether you are sketching a startup’s first service, reviewing a staff engineer’s design doc, or standing at an interview whiteboard. Seven steps, and the discipline that makes it work is simple: each step’s output is the next step’s input, and skipping a step is where designs go wrong. You do not get to pick a database (step 5) before you know the access pattern (step 3) and the read:write ratio (step 2); doing it out of order is how a point-lookup workload ends up on a relational engine it will fight forever.

Step 1 — Requirements: functional and non-functional

Split requirements into two piles. Functional requirements are what the system does — the operations and the actors (“a user shortens a URL,” “a merchant settles a batch,” “an admin revokes a link”). Non-functional requirements (NFRs) are the qualities it must have, and they are the ones that actually drive the architecture. Write them down as numbers before you name a single service.

Non-functional requirement The question to answer What it later drives
Scale How many users/requests/GB, today and in 3 years? The whole capacity estimate (step 2)
Latency SLA How fast, at p99 (not the mean)? Region choice, caching, compute, datastore
Availability target Three-nines? Four-nines? On which path? Zonal vs regional vs multi-region topology
Consistency Must reads see the latest write, always? Spanner vs Firestore vs Bigtable vs eventual
Durability (RPO/RTO) How much data may you lose, how fast must you recover? Replication, backups, DR posture (step 7)
Data residency Must the data legally stay in a country/region? Region pair, Organization Policy, Assured Workloads
Security & compliance PCI/HIPAA/SOC 2? What’s the data classification? Perimeters, CMEK, IAM, VPC Service Controls
Cost ceiling What’s the budget envelope? Managed-vs-self, scale-to-zero, CUDs, region

The most valuable habit here is to label each requirement a one-way door or a two-way door (a reversible decision). “It must stay in India” and “the ledger must be strongly consistent” are one-way doors — expensive to reverse because data has gravity and residency is a legal fact. “It runs on Cloud Run” is a two-way door — you can re-containerize onto GKE in a sprint. Spend your design energy on the one-way doors; prototype your way through the two-way ones.

Step 2 — Capacity estimate: the back of the envelope

Turn the scale NFR into rough numbers. Precision is not the point — an order of magnitude is, because it is the difference between “one Cloud SQL instance is fine” and “this needs Spanner or Bigtable.” The four quantities worth estimating:

The single most useful derived number is the read:write ratio. A 100:1 read-heavy workload is fundamentally a caching problem (put a CDN and Memorystore in front and most reads never reach the database); a write-heavy or high-fan-out workload is a partitioning problem (choose a store that spreads writes, and decouple with Pub/Sub). You will do the arithmetic for a real workload in the worked example below.

Step 3 — API and data model: the contract and the access patterns

Now define the API contract — the handful of operations the system exposes (POST /urls, GET /{short}) with their inputs and outputs — and the data model behind it. The reason this comes before the database choice is that the access pattern is what actually selects the datastore. Ask: is the dominant access a point lookup by key (screams key-value: Firestore or Bigtable), a relational query with joins and transactions (Cloud SQL, AlloyDB, Spanner), a range scan over time-ordered rows (Bigtable), or a large aggregate over history (BigQuery)? Model the entities and, critically, list the queries you must serve. A schema that is beautiful but cannot serve your hot query cheaply is the wrong schema.

Step 4 — Compute: walk the managed → control spectrum

With load and shape known, pick where the code runs. The framework’s full compute table is in the Choosing compute, storage, and databases section below; the decision is a walk from most-managed to least, stopping at the first option that meets the requirement:

The question that decides it: “What is the cheapest operational model that still meets this requirement?” Reaching for a VM by habit signs your team up for patching, scaling, and failover toil that Google would otherwise own.

Step 5 — Storage, database, and messaging: model, consistency, wiring

Pick the datastore by data model and consistency, not by familiarity (the full storage and database tables are in the Choosing compute, storage, and databases section below). The decision flow:

Then wire the services together. The two workhorses are Pub/Sub and Cloud Tasks, and conflating them is a classic mistake — one is an event bus, the other is a task queue:

Dimension Pub/Sub Cloud Tasks
Mental model Event bus — publish once, fan out to many independent subscribers Task queue — enqueue one unit of work for one specific handler
Delivery At-least-once (exactly-once available); push or pull At-least-once to a specific HTTP (or App Engine) target
Rate control Consumer-driven; flow control on the subscriber Per-queue dispatch rate + max concurrency — throttle the target
Scheduling Immediate; optional ordering keys Per-task schedule/delay (up to ~30 days), deferred execution
Best for Streaming ingestion, event fan-out, decoupling many consumers Deferred/offloaded work; calling one worker at a controlled rate
Reach for it when… Many things care about this event” “Do this one job later, without overwhelming the worker”

Around those two sit the rest of the wiring: Cloud Scheduler is managed cron; Eventarc routes events (built on Pub/Sub) to Cloud Run and Workflows; Workflows orchestrates a sequence of steps and service calls. See the Pub/Sub deep dive for delivery semantics.

Step 6 — Scaling and caching: absorb load before you buy more database

Read-heavy paths are a caching problem before they are a scaling problem. In order of leverage: Cloud CDN at the edge (cache cacheable responses so they never reach your origin), Memorystore (Redis/Valkey) for the hot working set and sessions, then autoscaling the compute (Cloud Run concurrency + max-instances; MIG autoscaler; GKE HPA/VPA + cluster autoscaler), read replicas to take reads off a primary, and a connection pooler so scaled-out compute does not exhaust the database’s connections. Write and fan-out paths get Pub/Sub decoupling so a slow downstream deepens a queue instead of failing the user’s request, and analytics stream asynchronously to BigQuery off the hot path.

Step 7 — Reliability, DR, and cost: designed in, not bolted on

Finally, harden and price it. State the RPO (how much data you may lose) and RTO (how fast you must recover), then pick a DR posture on the ladder to match the RTO you promised:

DR posture RTO / RPO character Cost Fits
Backup & restore Hours; RPO = backup interval Lowest Non-critical, cost-sensitive
Pilot light Tens of minutes Low Core data replicated, compute off
Warm standby Minutes Medium Scaled-down replica running
Hot standby / active-active Seconds; RPO ≈ 0 Highest Four-nines paths (payments)

For cost, treat these as design forces, not a finance afterthought: committed use discounts (resource- and spend-based) for steady baseline, Spot VMs for fault-tolerant work, sustained use discounts (automatic on Compute Engine/GKE), scale-to-zero for bursty serverless, right-sizing via Recommender, and — the silent line item — egress (inter-region and internet). Spanner’s node/processing-unit floor and BigQuery’s on-demand-vs-capacity model belong in this same conversation.

Where the menu is. The rest of this lesson — Core principles, Geography, the Resource hierarchy, Networking, and the compute/storage/database tables — is the detailed menu each step above draws on. Read the method as the how to think, and the framework sections as the what to pick. Next, watch the method run end to end on a concrete problem.

Worked example — designing a URL shortener on GCP

A URL shortener is the classic warm-up because it is deceptively deep: read-heavy, latency-sensitive, and global. Watch the seven steps produce the design.

Step 1 — Requirements. Functional: create a short link (optionally with a custom alias and an expiry), redirect a short link to its long URL, and count clicks. Non-functional: the redirect path must be 99.99% available at p99 < 50 ms globally (users are worldwide); links are durable with RPO ≈ 0 (losing a link breaks a printed QR code); the create path may be slower and can tolerate scale-to-zero; the team is small and cost-conscious.

Step 2 — Capacity. Assume 100 M new URLs/month. Writes ≈ 100,000,000 ÷ (30 × 86,400)~40 writes/sec average, ~200/sec at a 5× peak. A shortener is famously read-heavy — assume 100:1 — so reads ≈ ~3,900/sec average and ~20,000/sec at peak. Storage: each record (7-char code + a ~500-byte URL + metadata) ≈ ~600 bytes, so 100 M × 600 B60 GB/month~720 GB/year~3.6 TB over 5 years. Modest. The key space: base62 over 7 characters is 62⁷3.5 trillion codes — comfortably more than the ~6 billion links five years produces. Read the tea leaves: massively read-heavy (caching problem), tiny records, a point-lookup access pattern, and a global low-latency SLA.

Step 3 — API & data model. POST /urls {long_url, alias?, ttl?} → {short} and GET /{short} → 301/302 redirect. The data model is a single key-value record: key = short code, value = {long_url, created_at, expires_at, owner}. The dominant access is a point lookup by short code — no joins, no scans. That single fact is decisive.

Step 4 — Compute. Stateless HTTP with bursty traffic → Cloud Run. Put min-instances > 0 on the redirect service to eliminate cold starts on the latency-critical hot path; let the create service scale to zero to save money. GKE (no node/mesh need) and GCE (nothing VM-shaped here) would both be over-provisioned complexity.

Step 5 — Data & wiring. A point-lookup, read-heavy, global key-value workload points squarely at a key-value/document store, not a relational one. Firestore (multi-region, serverless, strongly consistent per document) is the pragmatic default for a small team; Bigtable is the answer if raw throughput and single-digit-ms latency at extreme scale dominate; Spanner earns its place only if you want globally-sequential short codes with strong consistency (its node floor is real cost for a workload this small). A single-region Cloud SQL would work at this data size but fights the global 20k/sec redirect SLA. Click events go onto Pub/Sub and stream to BigQuery — counting clicks must never slow a redirect.

Step 6 — Scaling & caching. Redirects are the hot path, so cache them: Cloud CDN in front of the global external Application Load Balancer caches the redirect response by short code with a TTL, and Memorystore holds the warm working set. Together they collapse the vast majority of the ~20k/sec reads at the edge, so the datastore only ever sees cache misses and writes. This — not the database brand — is what lets a tiny team serve the load cheaply.

Step 7 — Reliability, DR & cost. A multi-region datastore (Firestore multi-region, or Bigtable replication) survives a region loss and gives RPO ≈ 0 on links; the global external ALB shifts traffic on a regional failure to keep the redirect path at four-nines. Cost stays low because the CDN + cache slash paid database reads, create scales to zero, and the storage is only a few TB; egress is cheap because a redirect is a tiny 301 header, not a payload. The decision that mattered was not “which database” — it was recognizing the access pattern and the read:write ratio in step 2–3, which made caching + a KV store + async analytics the obvious spine.

Core principles — the design philosophy underneath every decision

The Architecture Framework’s core principles are the lens you apply before you reach for a service. They are not pillar-specific; they are the shared design philosophy that keeps the pillars coherent, and the System Design pillar is where you operationalize them first.

The principles you are applying. Across Google’s guidance the load-bearing principles are:

Principle What it means in practice The System Design consequence
Design for change Requirements, traffic, and Google’s own services evolve; bake in the ability to evolve Favor loosely coupled, API-fronted services; avoid hard-wiring regions or instance types
Document your architecture An architecture that lives only in someone’s head cannot be reviewed, audited, or evolved Produce diagrams, an ADR (architecture decision record) log, and IaC as the source of truth
Simplify and use managed services Undifferentiated heavy lifting (patching, replication, failover) is Google’s job, not yours Prefer Cloud Run, GKE Autopilot, BigQuery, Spanner over self-managed equivalents
Decouple your architecture Tight coupling turns a local failure into a global one and blocks independent scaling Insert Pub/Sub, queues, and well-defined service boundaries between components
Use a stateless architecture Stateless tiers scale horizontally and recover by replacement, not repair Push state to managed data stores; keep compute fungible
Automate and use IaC Manual, click-ops change is unreproducible and drift-prone Terraform / Infrastructure Manager, Config Controller, CI/CD for infra

Why it matters. These principles are what stop System Design from degenerating into “pick a VM and a database.” Design for change is the difference between a workload you can move to a second region in a sprint and one that needs a re-platform. Simplify and use managed services is usually the single highest-leverage decision a team makes on Google Cloud, because Google’s managed primitives (Spanner, BigQuery, Cloud Run, GKE Autopilot) absorb exactly the operational toil that sinks projects.

How to do it well. Treat the principles as a checklist you run against every significant decision and record the answer. The concrete artifacts are an Architecture Decision Record (ADR) log (one short document per significant, hard-to-reverse choice, with context, options, decision, and consequences), a set of reference architecture diagrams, and an IaC repository that is the environment rather than describing it. The framework’s own Architecture Center, Cloud Well-Architected content, and the Google Cloud Architecture Diagramming tool are the canonical references; Active Assist and Recommender later surface where reality has drifted from these principles.

Geography and regions — where your data and compute physically live

Region and zone selection is the most physical decision in System Design: it sets latency to your users, your data-residency and compliance posture, your blast radius, and a meaningful slice of your cost. It is also one of the hardest to reverse, because data has gravity — once petabytes live in europe-west1, moving them is a project, not a config change.

The hierarchy of physical placement.

The decisions you are actually making.

Decision driver What it forces you to evaluate GCP levers
Latency to users Pick regions close to the user population; multi-region front door Cloud CDN, global External Application Load Balancer, Network Service Tiers (Premium vs Standard)
Data residency / sovereignty Some data legally cannot leave a country/continent Regional resources, Organization Policy location constraints, Assured Workloads, Sovereign Controls
Service availability Not every product or machine type exists in every region Per-region product availability, GPU/TPU availability
Reliability target Single-zone vs multi-zone vs multi-region Zonal vs regional resources (regional MIGs, regional persistent disk)
Carbon footprint Regions differ in carbon intensity Per-region carbon-free energy % published by Google
Cost Pricing differs by region; egress between regions is charged Per-region pricing, network egress matrix

How to do it well. Choose a primary region by latency and residency, then a secondary region in the same geography (and ideally the same continent for low cross-region latency and for legal residency) for DR. Make every resource’s location an explicit, IaC-set value — never accept a default region. For data-residency-bound workloads, enforce placement with the Organization Policy constraint gcp.resourceLocations (allowed/denied locations) rather than trusting engineers to remember, and consider Assured Workloads to get a compliance-scoped folder with location and personnel controls baked in. Artifacts: a region-selection rationale (latency, residency, CFE%, cost) recorded as an ADR, a primary/secondary region pair per workload, and Organization Policy location constraints applied at the right folder.

The resource hierarchy — the structural backbone for governance, billing, and isolation

The Google Cloud resource hierarchy is the single most important governance artifact you create, because almost everything else attaches to it: IAM policies, Organization Policies, billing, networking scope, and quotas all inherit down it. Designing it deliberately, up front, is the difference between governance-by-design and governance-by-cleanup-project-two-years-later.

The levels, top to bottom.

Why it matters. The hierarchy is how inheritance works. An IAM role granted at a folder flows to every project beneath it; an Organization Policy set at the org constrains everything below unless explicitly overridden. This is enormously powerful and equally dangerous: a project landing in the wrong folder silently inherits the wrong access and the wrong guardrails. The project is also the billing and quota boundary — billing rolls up to a Cloud Billing account linked per project, and quotas are largely per-project-per-region, so your project topology directly shapes both your cost reporting and your scaling ceilings.

How to do it well. Follow the Google enterprise foundations / landing zone pattern:

Artifact Purpose Tool
Org → folder → project diagram The map everything inherits from Architecture diagram + Terraform
Folder-per-environment layout Clean prod/non-prod isolation Resource Manager, folders
Org Policy constraint set Org-wide guardrails by inheritance Organization Policy Service
Billing accounts + budgets Cost ownership and alerting Cloud Billing, budgets/alerts, BigQuery billing export
Foundation IaC Reproducible, reviewable structure Cloud Foundation Toolkit, Infrastructure Manager/Terraform

Artifacts to produce: an organization/folder/project topology diagram, an Organization Policy baseline, a naming-and-labeling standard, the billing-account-to-project mapping with budgets and alerts, and the foundation expressed as version-controlled Terraform.

Networking foundations — VPC design, hybrid connectivity, and reachability

Networking is the substrate every workload runs on, and on Google Cloud it has one property that makes it different from most clouds: the VPC is a global resource whose subnets are regional. That single fact reshapes how you design — you do not need a separate VPC per region, and you can route between regions over Google’s backbone without peering meshes.

The foundational VPC decisions.

Connectivity, ingress, and security.

Concern The right Google Cloud building block
Hybrid connectivity Cloud Interconnect (Dedicated or Partner) for private, high-bandwidth links; Cloud VPN (HA VPN) as backup or for lower bandwidth
Dynamic routing Cloud Router with BGP for hybrid and for regional/global dynamic routing mode
Outbound from private VMs Cloud NAT (managed, no NAT instances) so private VMs reach the internet without external IPs
Private access to Google APIs Private Google Access, Private Service Connect, VPC Service Controls to reach BigQuery, Cloud Storage, etc. without traversing the public internet
Global load balancing / ingress Cloud Load Balancing (global External Application LB, regional, internal, network LB) on Google’s anycast frontend
Edge protection Cloud Armor (WAF, DDoS, geo/rate rules), Cloud CDN for caching
East-west security VPC firewall rules + hierarchical firewall policies (org/folder-level), firewall policies, tags/service accounts as rule targets
Exfiltration control VPC Service Controls service perimeters around sensitive data services
DNS Cloud DNS (public + private zones, DNS peering/forwarding for hybrid)

Why it matters and how to do it well. Network topology is a foundational, slow-to-change decision; a flat single VPC with overlapping ranges and public IPs everywhere is a security and scaling dead end. The enterprise-standard pattern is: Shared VPC with a host project per environment, custom-mode subnets with deliberate CIDR allocation (including GKE secondary ranges), Cloud NAT for egress, Private Google Access / Private Service Connect so workloads never need public IPs to reach Google services, hierarchical firewall policies for org-wide baseline rules, VPC Service Controls perimeters around data, and HA VPN + Cloud Interconnect for redundant hybrid links terminated on Cloud Router. Artifacts: a CIDR/IP allocation plan, a Shared VPC host/service-project design, a network topology diagram (regions, subnets, connectivity, LB ingress), firewall and hierarchical-policy definitions, and a hybrid-connectivity design with redundancy.

Choosing compute, storage, and databases — selecting the right managed primitives

This is where System Design becomes concrete: matching each workload to the Google Cloud compute, storage, and data services whose operational model, scaling behavior, and consistency guarantees fit the requirement. The framework’s bias is explicit — prefer the most managed option that meets the requirement — because every operational concern you hand to Google is one your team does not run at 2 a.m.

Compute — the managed-vs-control spectrum

Service Model Best for You manage
Cloud Run Serverless containers, scale-to-zero Stateless HTTP/event services, APIs, web apps, jobs Just the container
Cloud Run functions (Cloud Functions) Event-driven functions (FaaS) Glue, event handlers, lightweight endpoints Just the function code
App Engine PaaS (standard/flexible) Classic web apps wanting a fully managed platform App + minimal config
GKE Autopilot Managed Kubernetes, Google runs nodes Containerized platforms wanting K8s API without node ops Workloads + manifests
GKE Standard Managed Kubernetes, you size node pools K8s needing node-level control, GPUs/TPUs, custom networking Node pools + workloads
Compute Engine (MIGs) VMs / managed instance groups Lift-and-shift, licensed software, full OS control, specialized hardware OS, patching, scaling config
Batch / Dataflow / Dataproc Managed batch & data processing HPC/batch jobs, streaming/batch ETL, Spark/Hadoop Job definition

How to choose. Walk the spectrum from most-managed to least: Can it run as a stateless container?Cloud Run (with scale-to-zero and request-based autoscaling). Does it need the Kubernetes API but not node control?GKE Autopilot. Does it need node-level control, GPUs/TPUs, or a service mesh you tune?GKE Standard. Is it a VM-shaped, lift-and-shift, or license-bound workload?Compute Engine with regional managed instance groups for zonal redundancy and autoscaling. For VM cost/efficiency, layer machine families (E2/N2/N2D general purpose, C-series compute-optimized, M-series memory-optimized), Spot VMs for fault-tolerant work, and committed use discounts for steady baseline.

Storage — match the access pattern, not the habit

Service Type Best for Notes
Cloud Storage Object Unstructured blobs, data lake, backups, static assets Storage classes: Standard / Nearline / Coldline / Archive; Autoclass; regional/dual-region/multi-region
Persistent Disk / Hyperdisk Block (VM-attached) Boot disks, databases on VMs, low-latency block Zonal vs regional PD (synchronous cross-zone replication)
Local SSD Ephemeral block Scratch, caches, very high IOPS Data lost on stop/terminate
Filestore Managed NFS Shared POSIX file systems, lift-and-shift apps, GKE RWX Tiers from Basic to Enterprise
Cloud Storage FUSE / Parallelstore File-over-object / HPC parallel FS ML training data, HPC scratch High-throughput AI/HPC

How to choose. Decide by access shape and durability need: object (Cloud Storage) for anything blob-like or lake-like, picking the storage class by access frequency (or Autoclass to let Google move objects automatically and avoid early-deletion fees); block (Persistent Disk/Hyperdisk, using regional PD when a database VM must survive a zone failure) for VM-attached low-latency storage; managed NFS (Filestore) only when you genuinely need shared POSIX semantics. Govern object data with lifecycle policies, Object Versioning, retention policies/Bucket Lock (WORM), and uniform bucket-level access.

Databases — pick by data model and consistency, not by familiarity

Service Model Consistency / scale Best for
Cloud SQL Managed MySQL / PostgreSQL / SQL Server Regional HA (multi-zone), read replicas; vertical scale Lift-and-shift relational, classic OLTP
AlloyDB for PostgreSQL Managed PostgreSQL-compatible High-performance HA, columnar engine for analytics Demanding PostgreSQL OLTP/HTAP
Spanner Distributed relational Horizontal scale + strong consistency, global, 99.999% Global OLTP, financial/inventory, no-sharding scale
Firestore Document NoSQL Serverless, regional/multi-region, real-time Mobile/web app data, real-time sync
Bigtable Wide-column NoSQL Massive scale, low-latency, high-throughput Time-series, IoT, ad-tech, large analytical KV
Memorystore Managed Redis / Valkey / Memcached In-memory cache Caching, sessions, leaderboards
BigQuery Serverless data warehouse Petabyte-scale analytics, separation of storage/compute Analytics, BI, ELT, ML on data (BigQuery ML)

How to choose. Start from the data model and consistency requirement: relational + needs to scale globally with strong consistency → Spanner; relational, regional, lift-and-shift → Cloud SQL (or AlloyDB when you need more performance/HTAP from PostgreSQL); document with real-time sync → Firestore; huge-scale low-latency key/wide-column (time-series, IoT) → Bigtable; analytical/warehouse → BigQuery; hot-path caching → Memorystore. Capture for each store the RPO/RTO, HA topology (multi-zone vs multi-region), read-replica strategy, and consistency model, because those are the System Design facts the Reliability pillar will later depend on. Artifacts: a per-workload service-selection matrix (compute/storage/database) with the rationale, a data-classification and residency note per data store, and the HA/replication topology for each stateful service.

Foundational system-design decisions — the cross-cutting choices

Some System Design decisions cut across all the sub-components above and set the trajectory of the whole platform. These are the ones to make consciously, early, and record as ADRs.

Real-world enterprise scenario

Meridian Pay is a fictional pan-Asian digital-payments and merchant-settlement company headquartered in Bengaluru. Their platform handles real-time card authorizations, a merchant ledger, a settlement engine, and a fraud-scoring service. Peak load reaches ~30,000 authorizations/second during festival-sale windows across India and Southeast Asia. Regulation requires that Indian payment data remain resident in India, and the board has set a target of four-nines (99.99%) availability for the authorization path with a regional active topology plus tested cross-region DR. They are migrating from an on-prem data centre and are net-new on Google Cloud.

Core principles. The platform team writes an ADR log from day one and adopts a managed-first rule: nothing self-hosted unless a licensing or hardware requirement forces it. Everything is Terraform via Infrastructure Manager, decoupled with Pub/Sub between authorization, ledger, and settlement so a slow downstream deepens a queue rather than failing a card swipe.

Geography and regions. They choose asia-south1 (Mumbai) as primary and asia-south2 (Delhi) as secondary — both in India, satisfying data residency while giving a true second region for DR. The authorization tier runs across three zones in asia-south1. An Organization Policy gcp.resourceLocations constraint, set at the production folder, hard-blocks any resource outside the two Indian regions, and the regulated ledger sits inside an Assured Workloads folder.

Resource hierarchy. Under the org they create folders prod, nonprod, and shared. Workloads land in dedicated projects (auth-prod, ledger-prod, settlement-prod), while shared concerns get their own projects: vpc-host-prod (Shared VPC host), logging (aggregated org-level log sink to BigQuery), and security. An Organization Policy baseline disables the default network, blocks external IPs on VMs, enforces OS Login, and restricts locations. Labels (env, cost-center, data-classification=pci) are mandatory, and Cloud Billing budgets with alerts are wired per project, with billing export to BigQuery.

Networking foundations. A custom-mode Shared VPC lives in vpc-host-prod; the three workload projects attach as service projects. Non-overlapping /16s are allocated per region with dedicated GKE secondary ranges for Pods/Services. Cloud NAT provides egress so no VM has a public IP; Private Service Connect and Private Google Access reach BigQuery and Cloud Storage privately; VPC Service Controls wraps the ledger and fraud data in a perimeter to block exfiltration. Ingress is a global External Application Load Balancer fronted by Cloud Armor (rate-limiting + geo rules) and Cloud CDN for static merchant assets. Redundant HA VPN plus a Partner Interconnect link, terminated on Cloud Router, connect the remaining on-prem reconciliation systems.

Compute, storage, databases. The authorization service and merchant dashboard run on Cloud Run (request-based autoscaling, scale-to-zero for non-prod). The fraud-scoring platform, needing GPUs and a service mesh, runs on GKE Standard. The merchant ledger moves to Spanner for horizontal scale with strong consistency and 99.999% availability — no application-level sharding — which is the decision that lets the auth path hit four-nines. Reporting and settlement analytics land in BigQuery (with BigQuery ML for fraud features); the hot authorization cache uses Memorystore for Redis; transaction-evidence blobs and statements go to Cloud Storage with Bucket Lock (WORM) for the regulator’s retention requirement.

Foundational decisions. Identity federates the corporate IdP into Cloud Identity via Workforce Identity Federation; all IAM is granted to groups, and CI/CD uses Workload Identity Federation (zero downloaded service-account keys). Per-project, per-region quotas on Cloud Run instances and Spanner nodes are raised to 2x projected peak ahead of the festival window.

Outcome. Meridian Pay went live with 99.99% measured availability on the authorization path over its first two quarters, passed a residency audit cleanly (the Organization Policy location constraint produced zero out-of-region resources), and executed a DR drill that failed asia-south1 over to asia-south2 with Spanner multi-region promotion and a load-balancer traffic shift in under 8 minutes. Choosing Spanner over sharded Cloud SQL at System Design time is what the team credits for avoiding the re-platform that the old on-prem ledger would have required to scale.

Deliverables & checklist

Common pitfalls

Going deeper

This is the material an experienced engineer will care about — the internals and edge cases that make the difference between a design that demos and a design that survives production.

One-way doors vs two-way doors. Not all decisions carry the same weight, and the skill is spending your design budget on the ones that are expensive to reverse. One-way doors (hard to undo): your region and residency choice (data gravity plus legal constraints), the resource hierarchy (retrofitting IAM/billing onto a populated org is brutal), and the primary datastore’s data model (migrating a relational schema to wide-column, or vice versa, is a re-platform). Two-way doors (cheap to undo): the compute engine (re-containerize onto GKE in a sprint), the cache, and much of the scaling topology. Deliberate slowly on the one-way doors; prototype fast through the two-way ones. This single framing keeps design reviews from spending an hour on the reversible choice and five minutes on the irreversible one.

CAP and PACELC behind the database table. The database decision is really a choice of where on the consistency/latency curve you want to sit. A single-primary Cloud SQL has one writer — simple and strongly consistent, but that writer is your ceiling. Spanner gives you strong (in fact external) consistency across regions using TrueTime, but pays for it with commit-wait latency on cross-region writes — the “consistency costs latency” corner made explicit. Firestore offers strong consistency per document with serverless scale. Bigtable is strongly consistent within a single cluster but eventually consistent across replicated clusters — you trade cross-cluster consistency for availability and throughput. There is no free lunch; picking a database is picking your point on this curve, and step 1’s consistency NFR is what tells you which point.

Capacity-estimation traps. Three mistakes recur. (1) Designing to the mean. Size to peak and to p99 latency, because the average hides the exact load that pages you at 2 a.m. (2) Forgetting the connection count. A relational database has a hard max_connections; ten thousand stateless compute instances, each with a small pool, will exhaust it long before CPU is the problem — the fix is a connection pooler (PgBouncer, the Cloud SQL connectors) or a database that does not connection-bind. (3) The hot-key / celebrity problem. If one key takes 50% of traffic while the average key takes a rounding error, no amount of even sharding helps — you must cache the hot key at the edge, replicate it, or fan its reads out. Averages lie; distributions tell the truth.

Quotas and scaling ceilings are first-class design constraints. Per-project, per-region quotas (Cloud Run max instances, Compute Engine CPUs, Spanner nodes, and — a classic silent wall — Cloud NAT port allocation) gate your scaling path just as surely as a code bug. NAT port exhaustion in particular presents as intermittent connection failures under load, not as an obvious “quota exceeded.” Inventory the quotas on your scaling path, request increases ahead of the launch, and remember that region choice and project topology both move these ceilings.

Cost is an architecture force, not a line item. Four cost mechanics change designs. Egress — inter-region and internet egress is metered and is the silent budget-killer of chatty cross-region designs; keep tiers that talk a lot in the same region. Spanner’s floor — it bills by nodes/processing units with a minimum, so a tiny always-on Spanner is expensive; size in processing units for small workloads or pick Firestore/Cloud SQL. Scale-to-zero vs min-instances — free when idle, but the first request after idle pays a cold start; on a latency-critical path, min-instances > 0 trades a little cost for predictable p99. CUDs vs SUDssustained use discounts apply automatically to Compute Engine/GKE for running most of the month, while committed use discounts (resource- and spend-based) are a deliberate 1-/3-year commitment; know which applies so you neither double-count nor leave savings on the table.

How the method maps onto the six pillars. The seven-step method is not separate from the framework — it is the framework, sequenced for a single design. Steps 1–2 (requirements, capacity) are System Design + Performance Optimization; steps 4–5 (compute, data) are the heart of System Design; step 6 (scaling, caching) is Performance + Reliability; step 7 (DR, cost) is Reliability + Cost Optimization; and all of it rests on Operational Excellence (you can run it) and Security, Privacy & Compliance (it is safe by construction). Run the method and you have exercised every pillar without having to consult six documents.

Practice challenges

Work these as design exercises — sketch the answer on paper first, then open the solution. They escalate from a back-of-envelope estimate to a full DR design, and they exercise the same method the lesson teaches. Placeholders are yours to fill in.

1. Estimate the load for a social feed (beginner). A social app has 5 M daily active users, each opening their feed 20 times a day; each open is 1 read. Estimate the average and peak read QPS and say what the number implies for the design.

<details> <summary>Solution</summary>

Average reads = 5,000,000 × 20 ÷ 86,400~1,160 reads/sec. At a 5× peak factor, ~5,800 reads/sec. That is comfortably a single-region workload, and being heavily read-dominated it is a caching problem first: put Memorystore in front for the hot feed and/or precompute feeds (fan-out-on-write), and add read replicas if a database still sees load.

Why: QPS ≈ DAU × actions ÷ 86,400, then peak = average × a peak factor. The magnitude (thousands, not millions) tells you not to over-engineer — no Spanner, no multi-region, just cache + replicas. </details>

2. Choose the compute for a thumbnail API (beginner → intermediate). A stateless HTTP service resizes uploaded images to thumbnails. Traffic is spiky (quiet nights, busy campaigns), no GPUs, no special OS. Which compute service, and which one setting matters most?

<details> <summary>Solution</summary>

Cloud Run. It is stateless HTTP with bursty load — the textbook case: request-based autoscaling and scale-to-zero mean you pay for campaigns, not for quiet nights. The setting that matters is container concurrency (how many requests one instance serves at once) together with max-instances; tune concurrency to your per-request CPU/memory to balance cost against tail latency, and set min-instances=0 to save money (or >0 if cold-start latency on the first request hurts).

gcloud run deploy thumbnailer --image IMAGE_URL --region REGION \
  --concurrency=40 --max-instances=100 --min-instances=0

Why: stateless + spiky = Cloud Run; GKE or GCE would add node/OS management for no benefit. Concurrency is the dial that trades cost against latency. </details>

3. Choose the database for a global ledger (intermediate). A fintech needs a transaction ledger that is strongly consistent, scales horizontally to global write volume, and must not rely on application-level sharding. Which database, and what is the main cost caveat?

<details> <summary>Solution</summary>

Spanner. It is the only Google Cloud database that combines a relational model, horizontal scale, and strong (external) consistency at global scale, with a 99.999% multi-region SLA — exactly the “no-sharding global OLTP” case. The cost caveat is Spanner’s node / processing-unit floor: a minimally-sized instance is still a real monthly cost, so for smaller workloads size it in processing units (sub-node granularity) rather than whole nodes, and confirm the write volume genuinely justifies it over Cloud SQL.

Why: model (relational) + scale (horizontal) + consistency (strong, global) has exactly one answer on GCP. Everything else is a trade-off against that trio. </details>

4. Pub/Sub or Cloud Tasks? (intermediate). Pick the right primitive for each: (a) “email a receipt to the customer after checkout, retried with backoff, at a rate the mail provider can accept”; (b) “when an order is placed, notify the inventory, analytics, and fraud services.”

<details> <summary>Solution</summary>

(a) Cloud Tasks. It is one job handed to one handler (the mail sender) where you need per-queue rate limiting so you do not overwhelm the provider, plus retries with backoff and optional deferral. (b) Pub/Sub. It is one event that many independent consumers care about — classic fan-out; each of inventory, analytics, and fraud subscribes and processes at its own pace.

Why: task-to-one-worker-with-throttle → Cloud Tasks; event-to-many-consumers → Pub/Sub. Using Pub/Sub to throttle a single downstream, or Cloud Tasks to fan out, fights the tool. </details>

5. Protect the datastore from a hot key (intermediate → advanced). In the URL shortener, a single “celebrity” short link receives 50% of all redirects. The naive design serves every redirect straight from Firestore. Redesign the read path so the hot key does not become a database hotspot and redirects stay under 50 ms globally.

<details> <summary>Solution</summary>

Put a cache in front of the point lookup. Cloud CDN on the global external Application Load Balancer caches the 301/302 redirect keyed by the short code with a TTL, so the celebrity link is served from the edge POP nearest each user — the datastore never sees the hot reads at all. Back it with Memorystore for the warm working set so even cache-miss traffic mostly avoids Firestore. The datastore is left serving only writes and cold misses.

Why: a hot key cannot be spread by sharding — it is one key. The fix is to serve it from cache at the edge, which both removes the database hotspot and beats the latency SLA because the response never crosses an ocean. </details>

6. Design DR for a payments auth path (advanced). The card-authorization path needs RTO < 10 minutes, RPO ≈ 0, and the data must stay in-country. Sketch the region, data, and failover design, and name the guardrail that enforces residency (rather than trusting engineers).

<details> <summary>Solution</summary>

Use a primary + secondary region in the same country (e.g., asia-south1 + asia-south2). Put the ledger on Spanner multi-region (or a dual-region config) so writes are synchronously replicated → RPO ≈ 0 and fast promotion of the secondary. Front the auth service with the global external Application Load Balancer so a regional failure is a traffic shift, not a rebuild → RTO in minutes. Run the auth tier across three zones in the primary for zonal resilience. Enforce residency with the Organization Policy constraint gcp.resourceLocations set at the production folder, hard-blocking any resource outside the two in-country regions — and test the failover with a scheduled DR drill, because an untested DR plan is a hope, not a plan.

Why: RPO ≈ 0 + minutes RTO demands a synchronously-replicated multi-region datastore plus an LB-driven traffic shift; residency is guaranteed by policy inheritance, not by reminding people. </details>

Common beginner mistakes

Glossary

What’s next

Part 2 of the Google Cloud Architecture Framework series turns to the Operational Excellence pillar — building the observability, automation, incident-management, and operational-readiness practices that keep the system you have just designed running reliably in production.

GCPWell-ArchitectedSystem DesignEnterprise
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments