ArchitectMind
  1. Home
  2. Tutorials
  3. Book 8 · Architecture Quality Attributes
  4. Volume III
  5. Vertical Scaling
Book 8 · Volume III — Scalability & Elasticity · Topic 1.2

Vertical Scaling

CPU · memory

10 min readStage 3 · Systems10 interview questions
Chapter
Chapter 1 — Scalability Fundamentals
Prerequisites
Topic 1.1; Volume II Chapter 2 (capacity relationships)
You will be able to
Decide when scaling up is the right move, identify CPU- versus memory-bound workloads, choose instance families and sizes, resize databases and caches with minimal disruption, size JVM heaps for bigger machines, and recognise the ceiling, cost and blast-radius limits of vertical scaling
Covers
CPU · Memory
On this page
  1. 1. Concept / Definition
  2. 2. Why It Exists
  3. 3. Core Concepts
  4. 4. How It Works Internally — Resizing Without Downtime
  5. 4A. Deep Dive — Bigger JVMs Need Different GC Choices
  6. 5. APIs / Features / Syntax
  7. 6. Practical Examples
  8. 7. Common Problems & Mistakes
  9. 8. Performance & Production Considerations
  10. 9. Architecture & Design Considerations
  11. 10. Interview Questions & Answers

1Concept / Definition

Vertical scaling (scaling up) increases the capacity of a single instance — more or faster CPU, more memory, faster storage or network — instead of adding more instances.

Vertical scaling ladder — Aurora r7g
Figure 1 — Vertical scaling ladder — Aurora r7g
Resource scaledHow in AWSTypical trigger
CPU (more vCPU, faster cores)Larger instance, newer generation (Graviton4), compute family (c7g)CPU-bound, high run-queue
MemoryMemory family (r7g, x2g), larger sizeWorking set > RAM, GC pressure, cache misses
Storage I/Ogp3/io2 IOPS, Aurora I/O-OptimizedIOPS/throughput limits
NetworkNetwork-optimised sizesBandwidth or PPS limits
Pod resourcesHigher requests/limits (VPA)Container throttling, OOM
Table 1 — What vertical scaling changes

2Why It Exists

Vertical scaling requires no code changes and keeps a single copy of state, which preserves strong consistency and simplicity. For many systems — especially relational databases — it is the fastest and safest way to buy capacity.

Vertical scaling — pros and cons
Figure 2 — Vertical scaling — pros and cons
WorkloadWhy vertical fits
Relational writerOne writer holds the data; distributing writes is hard
In-memory analyticsNeeds large RAM on one node
Legacy monolithsNot stateless yet
Caches with large working setsFewer, larger nodes reduce shard count
Short-term event capacityScale up for sale week, down after
Table 2 — When vertical is natural

3Core Concepts

3.1 CPU

CPU scaling optionEffectWatch
More vCPUsMore parallel workSoftware must use them (thread pools, parallel GC)
Faster cores / newer generationLower per-request CPU timeOften cheapest improvement
Compute-optimised familyHigher CPU:RAM ratioMemory may become limiting
Remove throttling (K8s limits)Full use of allocated coresNoisy neighbours
Table 3 — CPU scaling
CPU-bound signalTool
CPU > 70% sustained with rising latencyCloudWatch, Container Insights
Run-queue > coresEnhanced Monitoring (DB), node exporter
DB load dominated by CPU waitPerformance Insights
Hot methods in profilesJFR / async-profiler
Table 4 — Recognising CPU-bound workloads

3.2 Memory

Sizing memory vertically — search pod
Figure 3 — Sizing memory vertically — search pod
Memory scaling benefitExample
Larger buffer cacheDB working set fits → fewer disk reads
Larger in-process cachesHigher hit ratio
Fewer GC cyclesMore headroom per allocation burst
Fewer shardsCache/search clusters with bigger nodes
Table 5 — Memory scaling
CPU-bound vs memory-bound
Figure 4 — CPU-bound vs memory-bound

4How It Works Internally — Resizing Without Downtime

Resizing a database vertically (Aurora)
Figure 5 — Resizing a database vertically (Aurora)
ComponentResize methodDisruption
Aurora writerAdd reader of new size → failover → retire old~30 s failover (RDS Proxy reduces impact)
Aurora readerModify instance classReader removed from endpoint during change
ElastiCache (cluster mode)Online vertical scalingMinimal; brief connection resets
EKS podsChange requests/limits → rolling restartNone with surge rollout
EC2 instanceStop, change type, startDowntime unless behind LB with peers
Table 6 — Resize mechanics

4ADeep Dive — Bigger JVMs Need Different GC Choices

JVM heap size vs GC pause
Figure 6 — JVM heap size vs GC pause
Heap sizeCollector recommendation (Java 25)
≤ 4 GBG1 default is fine
4–32 GB, latency-sensitiveGenerational ZGC
> 32 GBZGC (compressed oops off ≥ 32 GB — size to 31 GB or much larger)
Batch/throughputParallel or G1
Table 7 — Scaling memory changes GC behaviour
Container sizing ruleReason
-XX:MaxRAMPercentage=65–75Leave room for off-heap, threads, OS
Requests = limits for memoryAvoid OOM kills from overcommit
No tight CPU limitsAvoid CFS throttling on GC/JIT bursts
Right-size with VPA recommendationsData-driven sizes
Table 8 — JVM in bigger containers
Vertical scaling has a ceiling
Figure 7 — Vertical scaling has a ceiling

5APIs / Features / Syntax

BASH
# Aurora: scale the writer up with minimal disruption
aws rds create-db-instance --db-instance-identifier orders-r7g-12xl \
  --db-cluster-identifier orders --db-instance-class db.r7g.12xlarge \
  --engine aurora-postgresql \
  --promotion-tier 0
aws rds failover-db-cluster --db-cluster-identifier orders \
  --target-db-instance-identifier orders-r7g-12xl  # ~30 s; RDS Proxy keeps clients
YAML
# Vertical Pod Autoscaler in recommendation mode (feed sizes into Helm values)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata: { name: search }
spec:
  targetRef: { apiVersion: apps/v1, kind: Deployment, name: search }
  updatePolicy: { updateMode: "Off" }          # recommend only; HPA scales replicas
  resourcePolicy:
    containerPolicies:
      - containerName: search
        minAllowed: { cpu: "2", memory: 8Gi }
        maxAllowed: { cpu: "16", memory: 64Gi }
YAML
# Pod sized up for a memory-bound search service
resources:
  requests: { cpu: "4", memory: 32Gi }
  limits:   { memory: 32Gi }
env:
  - name: JAVA_TOOL_OPTIONS
    value: "-XX:+UseZGC -XX:MaxRAMPercentage=70"

6Practical Examples

6.1 ShopNow orders writer: scale up before sharding

StepInstanceWriter CPU at sale peak
2024r7g.4xlarge (16 vCPU)88%
After query fixesr7g.4xlarge71%
Scale upr7g.8xlarge (32 vCPU)42%
2026 growthr7g.12xlarge (48 vCPU)55%
Ceilingr7g.16xlarge (64 vCPU)≈ 2 more years → sharding plan triggered
Table 9 — Vertical first, with a known horizon

6.2 Search pods: memory-bound

Search pods (4 vCPU / 8 GB) evicted facet caches constantly (hit ratio 45%). Moving to 4 vCPU / 32 GB raised the hit ratio to 82% and cut OpenSearch CPU by 30% — a vertical memory move on a horizontally scaled service.

6.3 CPU generation upgrade

Moving checkout pods from Graviton2 to Graviton4 reduced CPU per request from 110 ms to 82 ms (−25%) at similar price — the cheapest "scale up" available.

6.4 Lock-bound database — vertical did not help

A trial move of the inventory DB to a larger instance changed nothing: DB load was 70% Lock:transactionid on hot rows. The fix was data design (sharded counters), not size.

6.5 Worked example — choose the family

WorkloadMeasuredFamily
Checkout APICPU-bound, 1.5 GB/vCPUc7g / m7g
Search podsMemory-bound cachesr7g
Orders DBWorking set 90 GB, CPU 55%r7g (RAM for cache)
Analytics ETLMemory-heavy joinsx2g or EMR
Table 10 — Match family to the bottleneck

6.6 Worked example — ceiling horizon

InputValue
Writer CPU today at peak55% on 48 vCPU
Growth60% per year
Largest class64 vCPU
Years until 70% on largest≈ 1.1 years
DecisionStart sharding design now (lead time 9 months)
Table 11 — Compute when the ceiling arrives

6.7 Worked example — interview whiteboard

PromptAnswer outline
"Our database is at 85% CPU. Scale up or out?""Check the bottleneck first — if it's CPU (not locks), scale up via a larger reader and failover; it's quick and preserves consistency. In parallel, remove load (query fixes, caching, read replicas) and compute when we'd hit the largest instance at current growth; if within ~18 months, start partitioning/sharding design now."
Table 12 — Structured answer

6.8 Worked example — temporary scale-up for a sale

ComponentNormalSale weekAfter
Orders writerr7g.8xlarger7g.12xlarger7g.8xlarge
Valkey nodesr7g.large × 6r7g.xlarge × 6r7g.large × 6
Extra monthly-equivalent cost—+₹3.1 L for 10 days—
Table 13 — Vertical scaling can be elastic on a calendar

6.9 Worked example — cache cluster: up vs out

Option for 2× Valkey memoryShardsFailover blast radiusCost
Scale up nodes (large → xlarge)61/6 of keys per node failureSame per GB
Scale out shards (6 → 12)121/12Same per GB, more connections
ChosenScale outSmaller blast radius, more throughput—
Table 14 — Even for stateful systems, compare up vs out

6.10 Worked example — right-sizing down

PodRequestedp95 usedVPA recommendationSaving
reviews4 vCPU / 8 GB0.6 vCPU / 2.1 GB1 vCPU / 3 GB−70%
notifications2 vCPU / 4 GB0.3 vCPU / 1.2 GB0.5 vCPU / 2 GB−60%
Table 15 — Vertical scaling also means scaling down over-provisioned services

7Common Problems & Mistakes

MistakeFix
Scaling up a lock- or I/O-bound system for CPUDiagnose first
Ignoring the ceilingCompute horizon, plan next step
Same GC settings on a 4× heapRevisit collector (ZGC)
Downtime during resizeReader-promotion / online scaling
Paying for idle big instances year-roundScale up for events, down after
Bigger failure domain unnoticedMulti-AZ replicas, failover tested
Table 16 — Mistakes and fixes

8Performance & Production Considerations

ConsiderationPractice
Compute Optimizer / VPA recommendationsMonthly right-sizing
Failover sizingReplicas same class as writer
LicensingPer-core licences can make scaling up expensive
Warm-upBuffer cache cold after failover to new instance
Table 17 — Operating vertical scaling

Vertical sizes go stale in both directions, so review them monthly. AWS Compute Optimizer and VPA recommendations show over-provisioned instances and pods, which are common after a peak passes, and under-provisioned ones before growth catches up. Keep Aurora replicas at the same instance class as the writer, because a failover to a smaller replica turns an availability event into a performance incident. After any resize or failover, expect a cold buffer cache and slower queries for several minutes; schedule changes off-peak and pre-warm with representative queries where possible. Check licensing before scaling licensed software by cores, since per-core fees can outweigh the hardware cost. Finally, record each step in the capacity plan with the date it is expected to reach its ceiling, so the next scaling move is never a surprise.

9Architecture & Design Considerations

GuidelineDetail
Use vertical scaling for state, horizontal for computeTypical split
Keep a documented ceiling and horizonIn the capacity plan
Design for later partitioningKeys in tables, no cross-entity transactions
Reduce demand before scaling upQuery fixes, caching
Table 18 — Design guidance

10Interview Questions & Answers

Q1BasicConcept

What is vertical scaling?

Vertical scaling, or scaling up, means increasing the capacity of a single instance instead of adding more instances. You give one machine, database or pod more or faster CPU, more memory, faster storage or more network bandwidth. In AWS that means a larger size or a newer generation, for example Aurora r7g.8xlarge to r7g.12xlarge or Graviton2 to Graviton4, a different family such as compute-optimised c7g or memory-optimised r7g, provisioned IOPS, or higher pod requests and limits in Kubernetes. It contrasts with horizontal scaling, which adds instances and spreads the load. Most real systems use both: vertical for stateful components, horizontal for stateless compute.

Q2BasicConcept

Main advantage?

Its main advantage is simplicity: you get more capacity with no code changes and no distribution complexity, because there is still exactly one copy of the state. A relational writer that scales up keeps strong consistency, local transactions and joins; there is no sharding key to choose, no cross-shard query, no rebalancing and no distributed transaction. That makes it the fastest and safest way to buy capacity for databases, legacy monoliths and in-memory workloads. At ShopNow the orders writer went from 16 to 32 vCPUs through a reader promotion with about 30 seconds of failover, while a sharding project would have taken months of design and migration.

Q3IntermediateTrade-off

Main limitations?

There are four main limits. First, a hard ceiling: the largest instance class exists, and growth will eventually reach it, so vertical scaling only buys time. Second, a larger failure domain: one big node holds all the load, so its failure or maintenance affects everything unless replicas and failover are in place. Third, possible disruption: some resizes need a restart or failover, although reader promotion and online scaling keep this to seconds. Fourth, cost grows faster than benefit near the top, and per-core software licences make big machines expensive. Software must also use the extra cores; a single-threaded or lock-bound workload will not get faster.

Q4IntermediateInternals

How do you resize an Aurora writer with minimal downtime?

Use reader promotion rather than modifying the writer in place. Add a new Aurora replica with the target instance class to the cluster at promotion tier 0, and wait until it is available; because Aurora replicas share the cluster storage volume, there is no data copy and replica lag is typically milliseconds. Then trigger a failover to that replica, which usually takes around 30 seconds, while RDS Proxy keeps client connections open and reduces errors during the switch. Finally remove the old writer, or keep it as a reader. Expect a cold buffer cache on the new instance, so do it off-peak and keep the replicas the same class as the writer.

Q5Senior EngineerScenario

How do you know if a workload is CPU- or memory-bound?

Look at what saturates as load rises. A CPU-bound workload shows sustained CPU above about 70% with latency rising, a run queue longer than the number of cores, database load dominated by CPU in Performance Insights, and hot methods in JFR or async-profiler flame graphs. A memory-bound workload shows a working set larger than RAM: falling buffer or cache hit ratios, more disk reads, frequent GC that reclaims little memory, evictions or OOM kills, while CPU stays moderate. Check container throttling too, because a CPU limit can look like CPU-bound behaviour. The diagnosis picks the family: compute-optimised c7g for CPU, memory-optimised r7g or x2g for memory.

Q6Senior EngineerTricky

When doesn't scaling up help?

Scaling up does not help when the bottleneck is not a resource the bigger machine adds. The common case is contention: lock waits on hot rows, a single synchronized section or a single-threaded process, where extra cores simply sit idle. ShopNow moved its inventory database to a larger instance and nothing changed, because 70% of database load was transaction-ID lock waits on hot SKUs; the fix was sharded counters. It also fails when the limit is external, such as a slow dependency, network latency, a connection limit on a partner API, or an inefficient algorithm whose cost grows faster than the hardware. Diagnose the bottleneck before buying capacity.

Q7Technical ArchitectInternals

What JVM changes accompany bigger heaps?

A bigger heap changes GC behaviour, so the collector and sizing need revisiting. G1 is fine up to about 4 GB, but larger latency-sensitive heaps should use generational ZGC, the only ZGC mode in Java 25, whose pauses stay below a millisecond regardless of heap size. Watch the 32 GB boundary: above it compressed object pointers are switched off and references take twice the space, so size to about 31 GB or go much larger. In containers, set -XX:MaxRAMPercentage to around 65 to 75 to leave room for metaspace, thread stacks, direct buffers and the OS, set memory requests equal to limits, and avoid tight CPU limits.

Q8Technical ArchitectTrade-off

What is the cheapest vertical upgrade?

Often a newer CPU generation at the same size. Each generation gives more work per core for a similar price, so the CPU time per request falls without any architectural change. When ShopNow moved checkout pods from Graviton2 to Graviton4, CPU per request dropped from 110 to 82 ms, about 25% less, at a similar hourly cost. The move needs an arm64 container image and a quick check of native libraries, but Java code runs unchanged. Right-sizing over-provisioned services using VPA or Compute Optimizer recommendations is the other cheap move, because it frees money and node capacity for the services that really need to scale up.

Q9Solution ArchitectEstimation

How do you plan beyond vertical scaling?

Compute the ceiling horizon and start the next step before you reach it. Take today's peak utilisation, the growth rate and the largest instance class available, and work out when peak utilisation on that largest class would cross your threshold, usually around 70%. ShopNow's orders writer runs at 55% of 48 vCPUs at peak and grows 60% a year; even on the 64-vCPU class it reaches 70% in about 1.1 years. Sharding needs about nine months of lead time, so design starts now. Meanwhile, reduce demand with query fixes, caching and read replicas, and design data for later partitioning, with partition keys and no cross-entity transactions.

Q10Solution ArchitectDesign

When would you scale up only temporarily?

When the extra demand is predictable and short, such as a Diwali sale week, a product launch or month-end batch processing. Scaling up for the event and back down afterwards avoids paying for a large instance all year and avoids a risky architectural change for a peak that lasts days. ShopNow moves its orders writer from r7g.8xlarge to r7g.12xlarge and its Valkey nodes up one size for sale week, for about ₹3.1 lakh extra, then reverses both. Schedule the change days before the event using reader promotion and online scaling, warm the caches, load-test at the new size, and make scaling down an explicit part of the plan.

Newsletter

Get new tutorials every week

New ArchitectMind tutorials and interview questions, once a week. No spam, unsubscribe anytime.

Almost done! Check your inbox and click the confirmation link to complete your subscription.
Keep going in Book 8

Architecture Quality Attributes

Volume I · Topic 1.1

Quality Attributes

Quality Attributes & Architectural Thinking

Volume I · Topic 1.2

Why Quality Attributes Matter

Quality Attributes & Architectural Thinking

Volume I · Topic 1.3

Quality Attribute Categories

Quality Attributes & Architectural Thinking

Volume II · Topic 1.1

Performance

Performance & Capacity

Volume II · Topic 1.2

Latency Components

Performance & Capacity

Volume II · Topic 1.3

Tail Latency

Performance & Capacity

Volume III · Topic 1.1

Scalability

Scalability & Elasticity

Volume III · Topic 1.3

Horizontal Scaling

Scalability & Elasticity

Volume IV · Topic 1.1

Availability Fundamentals

Availability, Reliability & Resilience

Volume IV · Topic 1.2

Availability Calculation

Availability, Reliability & Resilience

Volume IV · Topic 1.3

Nines of Availability

Availability, Reliability & Resilience

Volume V · Topic 1.1

Security Requirements

Security, Privacy & Compliance

Volume V · Topic 1.2

Security Architecture

Security, Privacy & Compliance

Volume V · Topic 1.3

Threat Modeling

Security, Privacy & Compliance

Volume VI · Topic 1.1

Maintainability

Maintainability, Modifiability & Testability

Volume VI · Topic 1.2

Technical Debt

Maintainability, Modifiability & Testability

Volume VI · Topic 1.3

Code Quality

Maintainability, Modifiability & Testability

Volume VII · Topic 1.1

What Is Operability?

Operability, Observability & Deployability

Volume VII · Topic 1.2

Operational Readiness

Operability, Observability & Deployability

Volume VII · Topic 1.3

Production Readiness Checklist

Operability, Observability & Deployability

Volume VIII · Topic 1.1

Why Evaluate Architecture?

Quality Attribute Trade-offs & Architecture Evaluation

Volume VIII · Topic 1.2

Architecture Evaluation Methods

Quality Attribute Trade-offs & Architecture Evaluation

Volume VIII · Topic 1.3

ATAM

Quality Attribute Trade-offs & Architecture Evaluation