Architecture Design and Implementation Built for the Cloud · Topic 2 of 11

Stateless Design, Caching and Multi-Tenancy

Externalize session state to DynamoDB, S3 or ElastiCache, choose ElastiCache or DAX caching strategies, and isolate SaaS tenants with silo or pool models.

  • 5 min
In a nutshell
  • Stateless compute plus external state is the default for anything that auto scales.
  • Lazy loading caches on demand and can serve stale data. Write-through keeps the cache fresh at the cost of extra writes.
  • DAX is for DynamoDB only and accelerates eventually consistent reads. ElastiCache fronts any data source.

What it is

A stateless application keeps no user or session data on the compute that serves a request. Any instance, container or function can handle any request, so the fleet scales out, scales in and replaces failed nodes freely.

The state still exists, but it lives in a shared store. Caching then makes that store fast, and multi-tenancy decides how one platform keeps many customers apart.

Requestany userload balancerStateless computeany nodereads and writesShared stateDynamoDB, S3, ElastiCache

How it works

Where to put the state

StateStoreWhy
Web session dataElastiCache (Valkey or Redis OSS) or DynamoDBFast key lookups, with TTL to expire old sessions
User uploads and generated filesAmazon S3Durable object storage shared by every node
Shopping carts, user profilesDynamoDBScales with no servers and supports TTL and conditional writes
Workflow progressStep Functions or a databaseSurvives node loss mid process

Sticky sessions on a load balancer pin a user to one node. They are a short-term fix for legacy apps, but they unbalance load and lose the session when the node dies, so the exam prefers external state.

Caching strategies

Lazy loading (cache aside) reads the cache first and fills it from the database only on a miss. It caches only what is requested, but the first read is slow and data can go stale.

Write-through updates the cache every time the database is written. Reads are always fresh, but the cache holds data that may never be read. Combine either strategy with a TTL to bound staleness and memory use.

NeedChoose
Microsecond reads for a DynamoDB table with no code changes to query logicDynamoDB Accelerator (DAX)
Cache for RDS or Aurora, session store, leaderboards, rich data typesElastiCache for Valkey or Redis OSS
Simple multithreaded cache with no persistence or replicationElastiCache for Memcached
Cache with no node sizingElastiCache Serverless
Static and API responses close to usersCloudFront or API Gateway caching

DAX serves eventually consistent reads from its cache. Strongly consistent reads pass through to DynamoDB, so DAX does not help a workload that needs strongly consistent reads.

AppreadCacheElastiCachemissDatabaseAuroraresultCachestore with TTL

Multi-tenant isolation models

ModelWhat is sharedStrengthTrade-off
SiloNothing: an account, VPC or database per tenantStrongest isolation, simple per-tenant costHighest cost and operational overhead at scale
PoolEverything: shared compute and tables with a tenant IDBest cost efficiency and agilityIsolation must be enforced in code and policy, noisy neighbor risk
BridgeMix: shared compute with siloed data, or by tierBalances bothMore moving parts

Many SaaS designs put premium tenants in silos and smaller tenants in a pool.

Enforcing isolation in a pool

  • Tenant context from identity: store the tenant ID as a custom attribute in Amazon Cognito so it appears in the token. The backend reads the tenant from the verified token, never from a request parameter.
  • Scoped credentials: assume an IAM role with session tags or a policy that limits DynamoDB access to items whose partition key matches the tenant, using the dynamodb:LeadingKeys condition key.
  • Row-level security: PostgreSQL row-level security on RDS or Aurora filters every query by a tenant setting on the session.
  • Tenant-specific encryption: a separate AWS KMS key per tenant lets you revoke one tenant's access and gives a clear audit trail per tenant.
  • Noisy neighbors: API Gateway usage plans and throttling per tenant protect shared capacity.
Tenant usersigns inCognitotenant ID in tokentokenAPIreads tenant claimassumesScoped roleLeadingKeys conditionqueriesDynamoDBtenant rows only

How the exam asks about this

  • "Users are logged out when Auto Scaling terminates instances" -> move session state to ElastiCache or DynamoDB and remove the dependence on sticky sessions.
  • "A read-heavy DynamoDB table needs microsecond latency with the least application change" -> put DAX in front of the table.
  • "A SaaS provider must stop one tenant from reading another tenant's items in a shared DynamoDB table" -> derive the tenant ID from the Cognito token and use IAM policies with the dynamodb:LeadingKeys condition.

What to remember for the exam

  • Stateless compute plus external state is the default for anything that auto scales.
  • Lazy loading caches on demand and can serve stale data. Write-through keeps the cache fresh at the cost of extra writes.
  • DAX is for DynamoDB only and accelerates eventually consistent reads. ElastiCache fronts any data source.
  • Silo gives the strongest isolation, pool gives the lowest cost, bridge mixes them per tier or per layer.
  • Take tenant context from the verified identity token, not from input the client controls.
  • Per-tenant KMS keys support tenant-level revocation and audit.
Watch out

Application code that adds "WHERE tenant_id = ?" is not isolation on its own. The exam expects an enforced control such as scoped IAM credentials or row-level security, so one bug cannot leak another tenant's data.

Common mistakes

Fixing lost sessions with sticky sessions. Stickiness hides the problem and still loses sessions when a node is replaced. External session storage fixes the cause.

Choosing DAX for strongly consistent reads. Those reads go straight to DynamoDB, so the cache adds cost without speed. Use DAX only where eventual consistency is acceptable.

Putting every tenant in its own account by default. Silos are simple to reason about but expensive to run for thousands of small tenants. A pool or bridge model is usually the cost-effective answer unless the scenario demands hard isolation.

Check yourself

  • Why do sticky sessions conflict with Auto Scaling?

    A user's session lives on one node, so scale-in or a node failure loses it, and load is spread unevenly across the fleet.

  • When is write-through caching better than lazy loading?

    When reads must not return stale data, because the cache is updated on every database write.

  • How can a pooled DynamoDB table stop tenants reading each other's data?

    Use a role scoped by the tenant ID from the Cognito token with the dynamodb:LeadingKeys condition, so each request can only touch that tenant's partition keys.

Topic 2 of 11 in Architecture Design and Implementation Built for the Cloud

Test yourself on Architecture Design and Implementation Built for the Cloud

The full AWS SAP-C03 question bank has 850 questions, with timed practice exams and an explanation for every answer.

This study guide is independent and is not affiliated with, endorsed by, or sponsored by AWS. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.