Compute, storage and databases

EC2, ECS on Fargate, EKS, S3 with presigned URLs, and RDS with Multi-AZ, backups and parameter groups.

9 min read☁️ AWS for Backend Engineers

Three questions a service asks of the cloud: where does the JVM run, where do the files go, and where is the database. AWS has several answers to each, and the interesting part is not the product names but the operational trade each one makes — what you stop having to do, and what you stop being able to do.

Compute: EC2, ECS, EKS, and where a JVM belongs

EC2 is a virtual machine: an instance type (m6g.large — family, generation, size), an AMI, a subnet, a security group, an instance profile for its role. It is this repository's production host in a different data centre: a JVM under systemd, nginx in front, you own the OS. Operational weight: patching, the unit files, the disk, the backup timer — everything the CI/CD course's Linux lesson covered is yours. It is the right answer for one or two services on a small team, and for anything with a licensing or hardware constraint; an auto scaling group with a launch template and a load balancer makes it two-of-everything and self-healing.

ECS runs containers without a cluster to manage: a task definition (the image, CPU and memory, environment, the task role, the log configuration) and a service that keeps N tasks running behind a target group. With Fargate there are no instances at all — you pay per task-second for the CPU and memory you declared, and the Docker course's MaxRAMPercentage is what sizes the JVM to it. ECS is the least-surprising way to run a handful of Spring Boot services on AWS: the Docker knowledge transfers whole, the Kubernetes vocabulary is not needed, and deployments are rolling with health checks and circuit breakers built in.

EKS is managed Kubernetes: AWS runs the control plane, you run (or Fargate runs) the nodes, and everything in the Kubernetes course applies unchanged — Deployments, Services, probes, HPA — plus the AWS-specific glue: the load balancer controller that turns an Ingress into an ALB, IRSA or Pod Identity that turns a service account into a role, the EBS and EFS CSI drivers for volumes. Choose it when the organisation is standardising on Kubernetes or already has the skills; a team of three with four services does not need it.

Lambda runs a function per event — an S3 upload, an SQS message, an HTTP request through API Gateway — and charges per invocation and millisecond. Java's cold start (a JVM plus a framework, seconds) is the known cost; SnapStart snapshots the initialised JVM and restores it in hundreds of milliseconds, and Spring Cloud Function or a plain handler class keep the start small. Right for event-driven glue and spiky, infrequent work; wrong for a service with steady traffic, where a container is cheaper and simpler to observe.

Storage: S3, and the patterns that use it well

S3 is object storage: a bucket, keys, objects up to 5 TB, eleven nines of durability, and an HTTP API. It is not a filesystem — no rename (copy and delete), no append, no directories except as a prefix convention — and treating it as one is the mistake behind most S3 performance tickets. The patterns a backend actually uses:

  • Presigned URLs for uploads and downloads: the service signs a URL that permits one PUT to one key for fifteen minutes, hands it to the client, and the bytes go directly to S3, never through the JVM — the system-design course's file-upload brief and its "object storage: never through your service" rule.
  • Prefixes for partitioning, uploads/2026/09/18/<uuid> rather than one flat namespace, and a key design that spreads hot writes across prefixes; the old per-prefix rate limits are gone, but listing is still per prefix.
  • Lifecycle rules: transition to Infrequent Access after 30 days, to Glacier after a year, expire after seven — cost and retention as configuration, not a cron job.
  • Versioning and Object Lock for the backups (the production course's backup lesson: a backup on the same machine is not a backup; a bucket in another region with Object Lock is).
  • Event notifications to SQS or Lambda on PutObject, which is how "process this upload" becomes an event rather than a poll.
  • Server-side encryption on by default, a bucket policy that denies unencrypted puts and plain HTTP, and Block Public Access at the account level, so a bucket cannot be made public by a typo.

EBS is the block disk attached to one EC2 instance in one zone — the volume a database on EC2 would use, snapshotted to S3 for backup. EFS is a shared NFS filesystem for the rare case several instances must write the same files. Neither is where uploads belong.

Databases: RDS, and what managed actually means

RDS runs PostgreSQL (or MySQL, and the others) with the operations you would otherwise own: automated backups with point-in-time recovery, a Multi-AZ standby with synchronous replication and automatic failover, read replicas, minor version patching in a maintenance window, and metrics into CloudWatch. Aurora is AWS's own storage layer under a PostgreSQL-compatible engine, with faster failover and replicas that share storage, at a higher price per instance and a lower one for I/O-heavy workloads.

What stays yours, and what the SQL course's lessons still decide:

  • Sizing and the pool. The instance class sets max_connections, and the connection-pooling lesson's arithmetic still applies: ten services with a pool of twenty each is two hundred connections to a database that may allow a hundred and fifty. RDS Proxy is the PgBouncer the course mentioned, managed, and it also makes Lambda-to-RDS survivable.
  • Failover is a reconnect. Multi-AZ failover changes what the endpoint's DNS resolves to; a JVM that cached the address, or a pool that holds dead connections, sees errors for the thirty to sixty seconds until it notices. HikariCP's maxLifetime below the DNS TTL, and validating connections on borrow, are the settings; testing a failover deliberately (the chaos lesson) before the first real one is the practice.
  • Backups are still yours to verify. Automated snapshots exist; a restore that has never been run is the production course's "restore is the product". Cross-region snapshot copies are the off-site copy.
  • Parameter groups are postgresql.conf; Performance Insights is the plan-level view the query-optimisation lesson reads; the migration is still Flyway, still before the switchover, still expand-contract.

DynamoDB is the other database: key-value and document, single-digit-millisecond at any scale, no joins, and a data model you design around access patterns before you write it; the data-store lesson's "start from the questions" rule is the whole of DynamoDB design. ElastiCache is Redis (or Valkey) managed, for the caching course's patterns and the distributed-locks lesson's limits.

Managed queues and streams

The messaging courses' brokers exist as services, and the choice between them is the Kafka-versus-RabbitMQ decision with an operations bill attached. SQS is a queue: at-least-once (or FIFO queues with exactly-once processing and ordering per message group, at lower throughput), a visibility timeout that is the consumer's lease, a dead-letter queue configured per queue, and nothing to run — the right default for "work to be done". SNS is fan-out: a topic that pushes to many SQS queues, Lambdas or HTTP endpoints, so SNS-to-SQS is the pub/sub shape without a broker. EventBridge is SNS with routing rules on the event's content and a schema registry, for events between systems. MSK is Kafka, managed — brokers you size, patches AWS applies, and everything in the Kafka course applies unchanged, at the price of a cluster; MSK Serverless removes the sizing and caps the throughput. Amazon MQ is RabbitMQ or ActiveMQ for a workload that already speaks AMQP. Spring reaches SQS and SNS through Spring Cloud AWS, and MSK through the same Spring Kafka as any broker.

The same concepts on Azure and GCP

Every service in this course has a counterpart, and the concepts transfer whole; the names do not:

ConceptAWSAzureGCP
Identity for a serviceIAM roleManaged identityService account
Private networkVPC, subnets, security groupsVNet, subnets, NSGsVPC, subnets, firewall rules
Virtual machinesEC2, Auto Scaling groupVirtual Machines, VM Scale SetCompute Engine, managed instance group
Containers without a clusterECS on FargateContainer AppsCloud Run
Managed KubernetesEKSAKSGKE
FunctionsLambdaAzure FunctionsCloud Functions / Cloud Run
Object storageS3Blob StorageCloud Storage
Managed PostgreSQLRDS, AuroraAzure Database for PostgreSQLCloud SQL, AlloyDB
Queue / pub-sub / streamsSQS / SNS / MSKService Bus / Event Grid / Event HubsPub/Sub / Pub/Sub / Managed Kafka
HTTP load balancerALBApplication GatewayCloud Load Balancing
Metrics, logs, alarmsCloudWatchAzure MonitorCloud Monitoring, Cloud Logging
SecretsSecrets ManagerKey VaultSecret Manager

The judgement transfers too: identity through roles rather than keys, everything private behind one load balancer, a managed database with the pool sized to it, object storage through signed URLs, and a bill read by tag. What differs is the defaults and the sharp edges, which is why a platform team's guidance is worth more than the vendor's tutorial.

Choosing, for a Spring Boot service

The serviceRuns onFiles inDatabase
one or two, small team, full controlEC2 + systemd, an ASG for twoS3 via presigned URLsRDS PostgreSQL, Multi-AZ
several containerised servicesECS on FargateS3RDS, with RDS Proxy if the pool arithmetic demands
an organisation on KubernetesEKSS3RDS or Aurora
event glue, spiky, infrequentLambda with SnapStartS3 events inDynamoDB, or RDS through the proxy

Every row has S3 for files and a managed database, because those are the two places where the operational work is largest and least differentiating. The compute choice is the one that follows the team.

Progress is saved on this device and to your account when signed in.