AWS Certified Solutions Architect - Associate (SAA-C03) · High-Performing Storage, Compute, and Databases
~12 min
Amazon EC2 groups instance types into families by which resource they're built to maximize, and matching the family to a workload's dominant constraint is the first performance decision to make. General purpose instances (like the M family) balance compute, memory, and networking for workloads with no single standout need — web servers, small-to-medium databases. Compute optimized instances (the C family) favor CPU over memory, suited to batch processing, media transcoding, and other CPU-bound work. Memory optimized instances (the R and X families) favor RAM over CPU, built for in-memory databases and large-dataset analytics. Storage optimized instances (the I and D families) deliver very high, low-latency local disk I/O for workloads like high-throughput databases and data processing. Accelerated computing instances add GPUs or other hardware accelerators for machine learning training and graphics-heavy workloads.
Picking the family is a matter of naming the bottleneck: if a workload is CPU-bound, more memory on a general-purpose instance won't help nearly as much as moving to a compute-optimized one.
bash
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type c7g.2xlarge \
--count 1For workloads packaged as containers, the next decision is who manages the servers underneath them. Running containers on Amazon ECS or Amazon EKS with EC2 gives you full control over the instance type (and therefore the family) the containers run on — useful when a container workload has the same kind of dominant resource need as any other EC2-hosted workload. AWS Fargate runs those same containers without you provisioning or managing any EC2 instances at all: you specify the CPU and memory the task needs, and Fargate handles the rest, trading some control over the underlying hardware for less operational overhead.
The same tradeoff shows up outside containers. AWS Lambda takes it furthest: no server or container to size at all, only a memory setting for the function, and a request-scoped runtime with a hard duration limit — the right fit for short, event-driven work rather than a long-running service.
Inside AWS Lambda, memory is the one dial that changes almost everything else: Lambda allocates CPU power in proportion to the memory you configure, so a memory-bound, CPU-bound, or network-bound function can often get faster simply by turning the memory setting up, with no code change. At 1,769 MB, a function has the equivalent of one full vCPU; below that, it shares a fraction of a vCPU.
Because Lambda bills for memory and duration together, more memory doesn't automatically cost more — if doubling the memory more than halves the run time, the total bill can actually drop. Guessing the right setting is unreliable; AWS's open-source Lambda Power Tuning tool runs a function at several memory levels and measures the real cost/ performance curve, which is the reliable way to pick a setting instead of assuming "more memory always costs more."
It can go down — Lambda bills for memory times duration together, and more than halving the duration while only doubling the memory reduces the total, even though the per-millisecond price at 1024 MB is higher.