CloudBrum
CloudBrum · Cloud decision-support platform
AWS Databases

Amazon ElastiCacheLast reviewedReading time~12 minLevelBeginner to advanced

Amazon Web Services · Databases · Managed Valkey, Redis OSS and Memcached

Amazon ElastiCache is a managed in-memory cache that sits between an application and its database, so a repeated read costs a few hundred microseconds of network time instead of a database query. It runs Valkey, Redis OSS or Memcached, either as a serverless cache with nothing to size or as clusters whose nodes you pick yourself. AWS patches the engine, replaces failed nodes and takes the backups. What it can’t do is decide what is safe to cache and for how long, and most cache incidents trace back to that decision rather than to the service.

On this page (17 sections)

    Mind map: Amazon ElastiCache at a glance

    Amazon ElastiCache mind map Amazon ElastiCache at a glance: Engines: Valkey, Redis OSS, Memcached; Deployment: Serverless, Node-based clusters, Global Datastore; Uses: Cache-aside reads, Session store, Rate limits, leaderboards; Availability: Multi-AZ failover, Replicas, Shards; Data safety: Daily snapshots, Manual backups, Restore to a new cache; Security: VPC only, security groups, TLS and KMS, IAM and user groups; Operations: CloudWatch metrics, Maintenance windows, Events to SNS; Pricing: GB-hours and ECPUs, Node hours, Reserved nodes. Amazon ElastiCache at a glance In-memory caching on AWS: the main building blocks and decisions CloudBrum Cloud decision-support platform CloudBrum Valkey Redis OSS Memcached Engines Serverless Node-based clusters Global Datastore Deployment Cache-aside reads Session store Rate limits, leaderboards Uses Multi-AZ failover Replicas Shards Availability Daily snapshots Manual backups Restore to a new cache Data safety VPC only, security groups TLS and KMS IAM and user groups Security CloudWatch metrics Maintenance windows Events to SNS Operations GB-hours and ECPUs Node hours Reserved nodes Pricing ElastiCache17-point analysis CloudBrum· 17-point cloud service analysis cloudbrum.com
    CloudBrum ElastiCache at a glance · 17-point analysis Engines Valkey Redis OSS Memcached Deployment Serverless Node-based clusters Global Datastore Uses Cache-aside reads Session store Rate limits, leaderboards Availability Multi-AZ failover Replicas Shards Data safety Daily snapshots Manual backups Restore to a new cache Security VPC only, security groups TLS and KMS IAM and user groups Operations CloudWatch metrics Maintenance windows Events to SNS Pricing GB-hours and ECPUs Node hours Reserved nodes CloudBrum · cloudbrum.com

    Free to share. The downloaded image includes the CloudBrum link.

    Key features (summary)

    • Three enginesValkey is the open source fork of Redis that AWS backs and prices lower. Redis OSS is still offered, up to version 7.1 at the time of writing. Memcached suits plain key-value caches that need several threads and no persistence.
    • ServerlessCreate a cache with a name and a subnet list. Storage and compute grow with the traffic, the data is kept across three zones, there is one endpoint, and you can set upper limits on storage and compute so the bill has a ceiling.
    • Node-based clustersPick the node type, the number of shards and the replicas per shard (up to five), with cluster mode on or off. This route gives exact control, reserved pricing and features such as Global Datastore and data tiering on SSD-backed nodes.
    • FailoverWith Multi-AZ on, a replica in another zone is promoted when the primary fails. You can rehearse that with the test-failover call instead of waiting for a real outage.
    • Online scalingAdd or remove shards, change the node type or change the replica count while the cache keeps serving. A serverless cache does this on its own.
    • Global DatastoreReplicates a node-based cache to other Regions, so readers far away get local latency and a second Region holds a copy for disaster recovery.
    • Private by designA cache has only private addresses inside your VPC. TLS, encryption at rest with a KMS key, security groups, IAM sign-in and role-based access control with user groups are all supported.
    • More than get and setHashes, lists, sets, sorted sets, streams, geospatial indexes and publish/subscribe make it a fit for sessions, rankings, rate limits and light queues, not only for caching rows.

    Basic concepts

    Valkey
    An open source, Redis-compatible engine under the Linux Foundation. Valkey 8 is compatible with Redis OSS 7.2, so most clients work without changes.
    Redis OSS
    The open source Redis line that ElastiCache has run for years. New engine work on ElastiCache goes to Valkey.
    Memcached
    A simpler cache with strings only, several threads per node, no replication and no persistence.
    Serverless cache
    A cache you create without choosing nodes. It scales by itself, and you can cap its storage and compute.
    Replication group
    A node-based Valkey or Redis OSS cache: one or more shards, each with a primary and up to five replicas.
    Shard (node group)
    A slice of the data with its own primary node and replicas. More shards raise memory and write capacity.
    Cluster mode
    When on, keys are spread over shards by hash slot and clients must follow the cluster layout. When off, one shard holds everything.
    Endpoints
    The addresses clients use: a configuration or primary endpoint for writes, and a reader endpoint that balances reads over replicas.
    ElastiCache Processing Unit (ECPU)
    The serverless compute unit. A simple read or write of up to 1 KB uses one ECPU, and larger values or heavier commands use more.
    Eviction policy
    What the engine does when memory is full. The default on ElastiCache removes least recently used keys among those that have a time to live.
    Time to live (TTL)
    The number of seconds after which a key is removed. A cache without TTLs fills up and serves stale data.
    Parameter group
    A named set of engine settings, such as the eviction policy, that you attach to a node-based cache.
    Subnet group
    The list of subnets in which a node-based cache may place its nodes.
    User group
    A set of users for role-based access control. Each user has an access string that says which commands and keys it may use.
    Cache-aside
    The usual pattern: read the cache, on a miss read the database and store the answer, and on a write change the database and remove the cached copy.

    How to create & configure it

    Create a private cache and connect an application with the AWS CLI

    1. Choose serverless or node-basedStart serverless when traffic is uneven or you can’t predict the size. Take node-based clusters when the load is steady, you want exact node types and reserved pricing, or you need Global Datastore.
    2. Choose the enginePick Valkey for new work. It costs less and it is where AWS puts new effort. Keep Redis OSS only for a reason you can name, and use Memcached when you want a plain multi-threaded cache and nothing else.
    3. Plan the networkThe cache gets private addresses in your subnets, ideally in three zones. Allow the cache port only from the application’s security group. There is no public endpoint to hide.
    4. Set up usersSwitch the built-in default user off, and create an application user that signs in with IAM and may touch only the keys it needs.
    5. Create the cache with limits and backupsSet storage and compute limits on a serverless cache, or shards, replicas, Multi-AZ and a snapshot window on a node-based one. Turn on TLS and encryption at rest.
    6. Connect with a cluster-aware clientUse TLS, short timeouts and a client that follows the cluster layout. Serverless caches and cluster-mode groups both expect it.
    7. Cache with a TTL and decide invalidationGive every key an expiry, add a little random spread so keys don’t expire together, and drop the cached copy whenever the database row changes.
    8. Add alarmsWatch EngineCPUUtilization, DatabaseMemoryUsagePercentage, Evictions, CurrConnections and ReplicationLag, plus the capacity and throttling metrics of a serverless cache.
    9. Test failure on purposeRun a failover, restart the application during it, and restore a snapshot into a new cache. Then run a test that starts with an empty cache and see how much load reaches the database.

    Tip: treat the cache as something you can lose at any time. If the application breaks when the cache is empty, you have built a database without a database’s guarantees. Run the load test with a cold cache before launch. See the code references for the same setup as Terraform.

    Common issues after configuration

    SymptomLikely causeWhat to check / fix
    Connections time outThe client is outside the VPC, a security group doesn’t allow the client’s group, or the subnet routes don’t reach the cacheConnect from inside the VPC or over a VPN, allow the client’s security group on the cache port, and check the cache and client use the same VPC.
    The connection is reset right after it opensThe cache requires TLS and the client is speaking plain textTurn TLS on in the client, use the TLS port setting of your library, and trust the system certificate store.
    MOVED or CROSSSLOT errorsA client that doesn’t understand cluster mode is talking to a sharded cache, or one command uses keys that live on different shardsUse a cluster-aware client, and put keys that must be used together under one hash tag such as {user:7}.
    OOM command not allowed when used memory is above maxmemoryThe cache is full and the eviction policy can’t remove anything, for example because keys have no TTLSet TTLs, review the eviction policy, delete big or forgotten keys and add memory or shards.
    Keys vanish earlier than their TTLMemory pressure evicts keys, or a maintenance event or failover lost writes the replica hadn’t receivedCheck the Evictions metric, size for the data plus headroom, and never treat the cache as the only copy.
    One node is at high CPU while the rest are calmA hot key, a very large value, or a slow command such as KEYS or a big SMEMBERS is keeping the single engine thread busyFind the key with the slow log, split large values, replace KEYS with SCAN, and spread hot keys with a suffix.
    Latency spikes now and thenLarge values, long Lua scripts, a backup fork that needs spare memory, or a client creating a new connection for every requestKeep values small, reuse connections through a pool, leave memory headroom for backups and look at the slow log.
    Errors for a minute after a failoverThe client caches the old address in DNS or doesn’t reconnect after the primary changesUse the cluster or primary endpoint name, keep DNS caching short, and give the client retry and reconnect settings.
    A serverless cache throttlesThe compute limit you set was reached, or a burst needs more than the cache can add at onceRaise the limit, spread the burst with retries and jitter, and cut expensive commands and large values.
    Sign-in fails with WRONGPASS or NOAUTHThe IAM token is older than 15 minutes, the user isn’t in the cache’s user group, or the connection ran past 12 hoursCreate a fresh token on every connect, add the user to the group, and let the client reconnect when the connection ends.
    The bill is higher than expectedLarge values multiply serverless compute, nodes are bigger than the working set, replicas aren’t needed in a test, or traffic crosses zonesCompare memory in use with the node size, shrink values, drop test replicas, and keep clients in the zone of the node they read from.

    Use cases: when and where to use it

    Good fit

    • Read-heavy applications where the same rows or API answers are fetched again and again
    • Session stores for web and mobile back ends that must survive an instance restart
    • Rate limiting, counters and leaderboards that need atomic updates at speed
    • Short-lived queues and publish/subscribe between services that can tolerate a lost message
    • Cutting load on a relational or NoSQL database before paying for a larger one
    • Caching expensive results, such as rendered fragments or machine learning predictions

    Consider something else

    Pros: why consider it?

    Why teams choose it

    • Managed: AWS patches, monitors and replaces nodes
    • Serverless mode removes sizing for uneven workloads
    • Microsecond-range reads from memory take load off the database
    • Valkey is priced below Redis OSS on both serverless and node-based caches
    • Multi-AZ failover, snapshots and Global Datastore are built in
    • Private by design, with IAM, TLS, KMS and role-based access control

    Trade-offs to weigh

    • Data is held in memory, so it costs more per gigabyte than disk-based databases
    • A cache can serve stale data unless you design invalidation
    • It lives inside a VPC, so reaching it from a laptop or another network needs a bridge
    • Node-based clusters still need sizing, parameter choices and resharding plans
    • Cluster mode needs cluster-aware clients and care with multi-key commands
    • Failover and maintenance can drop connections, so clients must retry

    Common threats, vulnerabilities & risks

    RiskSeverityWhy it mattersMitigation
    Cache with no sign-in inside a shared VPCHighAnyone or anything in a network that can reach the port can read, change or flush every key.Turn on IAM sign-in or a user group, switch the default user off, and allow only the application’s security group.
    Plain text trafficHighSession ids and cached personal data can be read or changed on the network.Enable encryption in transit when you create the cache, and refuse clients that don’t use it.
    Personal or secret data cached without a planHighA cache is easy to read and rarely audited, so it gathers data that nobody meant to keep.Cache only what you can afford to leak, set short TTLs on personal data, and classify what goes in.
    Stale data served as truthMediumA price or a permission read from an old copy leads to wrong decisions.Remove the cached copy on every write, give fast-changing data a short TTL, and go to the database for anything that must be exact.
    The database can’t cope with a cold cacheMediumAfter a restart, failover or flush, every request misses at once and the database falls over.Warm important keys, use a lock so one caller rebuilds each missing key, spread expiry times and load test with an empty cache.
    No headroom for backups and replicationMediumTaking a snapshot or syncing a replica needs spare memory, and a full node can fail both.Keep memory use well below the node’s limit and watch DatabaseMemoryUsagePercentage.
    A single node, or Multi-AZ offMediumOne failure removes the cache and the database takes the full load.Use at least one replica in another zone for anything that matters, and rehearse failover.
    Dangerous commands open to the applicationLow–MedFLUSHALL, KEYS and CONFIG can wipe or stall a cache from a single bug.Give the application user an access string that excludes them.
    Cost drift from forgotten cachesLow–MedTest caches and oversized nodes keep billing, and large serverless values quietly raise compute use.Tag every cache with an owner, set serverless limits and review node utilisation each month.

    Performance optimisation

    • Keep values small. Compress or split anything over a few kilobytes, since size drives both latency and serverless compute.
    • Use a connection pool and keep connections open. Opening a TLS connection for every request wastes more time than the read itself.
    • Give every key a TTL with random spread, so a batch of keys doesn’t expire in the same second.
    • Put keys that are used together under one hash tag, so multi-key commands and transactions stay on one shard.
    • Send reads to replicas through the reader endpoint where slightly old data is fine.
    • Replace KEYS and other full scans with SCAN, and look at the slow log when one node runs hot.
    • Batch work with pipelining instead of many round trips.
    • Keep application and cache in the same zone where you can, since every hop across a zone adds delay.

    Reduce monthly cost

    FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Amazon ElastiCache.

    • Try Valkey before paying for Redis OSS. AWS lists lower prices for Valkey on both serverless and node-based caches.
    • Set storage and compute limits on serverless caches, so a runaway client can’t run up the bill.
    • Check memory in use against node size. Many caches run at a fraction of the memory they pay for.
    • Use reserved nodes for steady node-based caches. Valkey and Redis OSS reservations in the same family can be shared.
    • Shrink values with compression or smaller fields. On serverless, larger values use more compute units for each call.
    • Skip replicas in development and test, and keep them where an outage would hurt.
    • Consider data tiering on SSD-backed nodes for large caches with a small hot set.
    • Keep snapshot retention to what you will restore from, because backup storage beyond the free amount is billed.
    • Reduce cross-zone traffic by reading from replicas in the client’s own zone where the design allows.
    • Tag every cache by team and add a budget alert on ElastiCache spend.

    No dollar rates are quoted here because AWS prices differ by Region and change, and the secondary sources I read disagreed. The relative gaps come from AWS announcements read in October 2026. Check the live page (see Pricing).

    Security optimisation

    • Keep the cache in private subnets, and allow only the application’s security group on the cache port.
    • Turn on encryption in transit and encryption at rest. Use your own KMS key if your rules require control of the key.
    • Sign in with IAM authentication and give each application its own user in a user group, with an access string that limits commands and key prefixes.
    • Switch the built-in default user off or give it no commands.
    • Exclude dangerous commands such as FLUSHALL, CONFIG and KEYS from application users.
    • Cache no secrets and no unneeded personal data, and use short TTLs on what you do cache.
    • Send slow log and engine log to CloudWatch Logs or Firehose for review.
    • Restrict who can call modify, delete and failover operations, and alert on them in CloudTrail.
    • Encrypt snapshots and control who can copy or share them.
    • Review public access paths to your VPC, since reaching the cache requires first reaching the network.

    Governance & compliance

    Guardrails

    • A shared Terraform module that always sets encryption in transit and at rest, a user group, a subnet group, snapshots, tags and an owner
    • A service control policy that blocks creating caches without a user group or encryption where your rules require it
    • A standard for key prefixes, TTLs and what may be cached, written down for each application
    • A review step for any cache that holds personal data

    Continuous checks (AWS Config, Security Hub and your own scripts)

    • A scheduled script that lists caches with encryption off, no user group, no snapshots, no Multi-AZ or no usage limits (the C# tab does this)
    • Config rules and Security Hub checks for ElastiCache, if your standard covers them
    • Alarms on EngineCPUUtilization, DatabaseMemoryUsagePercentage and Evictions
    • A CloudTrail alert for changes to user groups, snapshots and security groups
    • A monthly report of caches with low memory use or no traffic

    AWS CloudTrail logs who changed a cache, AWS Config keeps the history of each setting, Security Hub checks them against standards, and AWS Artifact has the compliance reports. AWS operates the hosts and the engine. The contents are your side: what goes into the cache, how long it stays, who may read it and how the application copes when it is empty.

    Reduce carbon footprint

    • Size the cache to the working set, not to the biggest day you can imagine.
    • Use serverless for uneven loads so capacity isn’t idle between peaks.
    • Drop caches and replicas that nobody uses.
    • Graviton-based node types do more work for the power they draw, so prefer them where your software runs on them.
    • A good hit rate means fewer database queries, and so less work for a much larger system.
    • The AWS carbon tool reports per account and doesn’t list ElastiCache on its own, so quote no ElastiCache figure.

    Pricing

    Purchase options

    Serverless Data stored plus compute units

    Billed for the data stored, in gigabyte-hours with a small minimum, and for the ElastiCache Processing Units your requests use. AWS prices Valkey about a third below Redis OSS here, and its minimum stored amount is far smaller.

    Node-based Per node, per hour

    Every node bills for every hour, replicas too, at a rate set by the node type. AWS prices Valkey about a fifth below Redis OSS for node-based caches.

    Reserved nodes One- or three-year commitment

    A commitment lowers the hourly rate for steady use. Reservations can cover a different size in the same family, and Redis OSS reservations can be applied to Valkey nodes.

    Backups and transfer Snapshots, cross-zone traffic

    Snapshot storage beyond the free allowance and data moving between zones or Regions are billed on top, including traffic for Global Datastore.

    What you actually pay for

    • For serverless: gigabyte-hours of stored data and the compute units your requests consume
    • For node-based caches: every node-hour, including replicas
    • Backup storage above the free allowance
    • Data transfer across zones, Regions or out to the internet
    • Extras such as Global Datastore replication and reserved node commitments

    AWS lists the rates, the minimums and any free tier for new accounts on its pricing page, and rates differ by Region. See the official Amazon ElastiCache pricing page and the AWS Pricing Calculator.

    Important code references

    A private Valkey cache in two forms: a serverless cache with usage limits and a node-based group with two shards, one replica each, Multi-AZ failover, TLS, encryption at rest and a snapshot window, plus users that sign in with IAM and may use only keys that start with app:. The CLI tab builds both, reads their status, rehearses a failover and reads a memory metric; Terraform describes the same resources. The Python tab connects with an IAM token and shows cache-aside reads that stop a stampede, plus a rate limit, and the C# tab audits every replication group and serverless cache for encryption, sign-in, failover, snapshots and usage limits. Replace the Region and the security group with your own.

    # Placeholders: replace the Region and the application security group with your own. This uses the default VPC; use your own private subnets in production.
    REGION=ap-south-1
    APP_SG=sg-0123456789abcdef0
    
    VPC_ID=$(aws ec2 describe-vpcs --region $REGION --filters Name=is-default,Values=true --query "Vpcs[0].VpcId" --output text)
    SUBNETS=$(aws ec2 describe-subnets --region $REGION --filters Name=vpc-id,Values=$VPC_ID --query "Subnets[0:3].SubnetId" --output text)
    
    # 1. A security group for the cache. It accepts the cache port only from the application's security group.
    CACHE_SG=$(aws ec2 create-security-group --region $REGION --group-name app-cache --description "Cache" --vpc-id $VPC_ID --query GroupId --output text)
    aws ec2 authorize-security-group-ingress --region $REGION --group-id $CACHE_SG --protocol tcp --port 6379 --source-group $APP_SG
    
    # 2. Users. The built-in default user is switched off, and the application user signs in with IAM and may touch only keys that start with app:
    aws elasticache create-user --region $REGION --user-id no-access --user-name default --engine valkey \
      --access-string "off ~keys* -@all +get" --no-password-required
    aws elasticache create-user --region $REGION --user-id app-user --user-name app-user --engine valkey \
      --access-string "on ~app:* -@all +@read +@write +@connection" --authentication-mode Type=iam
    aws elasticache create-user-group --region $REGION --user-group-id app-users --engine valkey --user-ids no-access app-user
    
    # 3. Option A, serverless: nothing to size. The limits cap the bill, and the daily snapshot is kept for a week.
    aws elasticache create-serverless-cache --region $REGION --serverless-cache-name sessions --engine valkey \
      --subnet-ids $SUBNETS --security-group-ids $CACHE_SG --user-group-id app-users \
      --cache-usage-limits "DataStorage={Maximum=10,Unit=GB},ECPUPerSecond={Maximum=50000}" \
      --snapshot-retention-limit 7 --daily-snapshot-time 21:00
    
    # 4. Option B, node-based: two shards with one replica each, spread over zones, with failover, TLS, encryption at rest and a snapshot window.
    aws elasticache create-cache-subnet-group --region $REGION --cache-subnet-group-name app-cache-subnets \
      --cache-subnet-group-description "Cache subnets" --subnet-ids $SUBNETS
    aws elasticache create-replication-group --region $REGION --replication-group-id orders --replication-group-description "Orders cache" \
      --engine valkey --engine-version 8.0 --cache-node-type cache.m7g.large --num-node-groups 2 --replicas-per-node-group 1 \
      --automatic-failover-enabled --multi-az-enabled --cache-subnet-group-name app-cache-subnets --security-group-ids $CACHE_SG \
      --transit-encryption-enabled --at-rest-encryption-enabled --user-group-ids app-users \
      --snapshot-retention-limit 7 --snapshot-window 21:00-22:00 --preferred-maintenance-window sun:22:30-sun:23:30 --auto-minor-version-upgrade
    
    # 5. Is it up, and where do clients connect?
    aws elasticache describe-serverless-caches --region $REGION --serverless-cache-name sessions \
      --query "ServerlessCaches[0].{status:Status,endpoint:Endpoint.Address,reader:ReaderEndpoint.Address}"
    aws elasticache describe-replication-groups --region $REGION --replication-group-id orders \
      --query "ReplicationGroups[0].{status:Status,failover:AutomaticFailover,multiAz:MultiAZ,endpoint:ConfigurationEndpoint.Address}"
    
    # 6. Take a snapshot before a risky change, then rehearse a failover of the first shard.
    aws elasticache create-snapshot --region $REGION --replication-group-id orders --snapshot-name orders-before-change
    aws elasticache test-failover --region $REGION --replication-group-id orders --node-group-id 0001
    
    # 7. Evictions and memory use of the first node in the last hour. Members of a cluster-mode group are named group-shard-node.
    aws cloudwatch get-metric-statistics --region $REGION --namespace AWS/ElastiCache --metric-name DatabaseMemoryUsagePercentage \
      --dimensions Name=CacheClusterId,Value=orders-0001-001 --statistics Maximum --period 300 \
      --start-time $(date -u -d '-1 hour' +%FT%TZ) --end-time $(date -u +%FT%TZ)
    
    # 8. Add a shard when memory or CPU stays high. Clients that follow the cluster topology pick it up without a restart.
    aws elasticache modify-replication-group-shard-configuration --region $REGION --replication-group-id orders --node-group-count 3 --apply-immediately
    # Placeholders: pass in your own application security group. This uses the default VPC; use your own private subnets in production.
    variable "region" {
      type    = string
      default = "ap-south-1"
    }
    
    variable "app_security_group_id" {
      type = string
    }
    
    provider "aws" {
      region = var.region
    }
    
    data "aws_vpc" "default" {
      default = true
    }
    
    data "aws_subnets" "default" {
      filter {
        name   = "vpc-id"
        values = [data.aws_vpc.default.id]
      }
    }
    
    # The cache accepts its port only from the application's security group.
    resource "aws_security_group" "cache" {
      name        = "app-cache"
      description = "Cache"
      vpc_id      = data.aws_vpc.default.id
    
      ingress {
        from_port       = 6379
        to_port         = 6379
        protocol        = "tcp"
        security_groups = [var.app_security_group_id]
      }
    }
    
    # The built-in default user is switched off. The application user signs in with IAM and may touch only keys that start with app:
    resource "aws_elasticache_user" "no_access" {
      user_id              = "no-access"
      user_name            = "default"
      engine               = "VALKEY"
      access_string        = "off ~keys* -@all +get"
      no_password_required = true
    }
    
    resource "aws_elasticache_user" "app" {
      user_id       = "app-user"
      user_name     = "app-user"
      engine        = "VALKEY"
      access_string = "on ~app:* -@all +@read +@write +@connection"
    
      authentication_mode {
        type = "iam"
      }
    }
    
    resource "aws_elasticache_user_group" "app" {
      user_group_id = "app-users"
      engine        = "VALKEY"
      user_ids      = [aws_elasticache_user.no_access.user_id, aws_elasticache_user.app.user_id]
    }
    
    # Option A, serverless: nothing to size. The limits cap the bill, and the daily snapshot is kept for a week.
    resource "aws_elasticache_serverless_cache" "sessions" {
      name                 = "sessions"
      engine               = "valkey"
      major_engine_version = "8"
      subnet_ids           = slice(data.aws_subnets.default.ids, 0, 3)
      security_group_ids   = [aws_security_group.cache.id]
      user_group_id        = aws_elasticache_user_group.app.user_group_id
    
      cache_usage_limits {
        data_storage {
          maximum = 10
          unit    = "GB"
        }
        ecpu_per_second {
          maximum = 50000
        }
      }
    
      snapshot_retention_limit = 7
      daily_snapshot_time      = "21:00"
    }
    
    # Option B, node-based: two shards with one replica each, spread over zones, with failover, TLS and encryption at rest.
    resource "aws_elasticache_subnet_group" "cache" {
      name       = "app-cache-subnets"
      subnet_ids = slice(data.aws_subnets.default.ids, 0, 3)
    }
    
    resource "aws_elasticache_replication_group" "orders" {
      replication_group_id    = "orders"
      description             = "Orders cache"
      engine                  = "valkey"
      engine_version          = "8.0"
      node_type               = "cache.m7g.large"
      num_node_groups         = 2
      replicas_per_node_group = 1
    
      automatic_failover_enabled = true
      multi_az_enabled           = true
      subnet_group_name          = aws_elasticache_subnet_group.cache.name
      security_group_ids         = [aws_security_group.cache.id]
    
      transit_encryption_enabled = true
      at_rest_encryption_enabled = true
      user_group_ids             = [aws_elasticache_user_group.app.user_group_id]
    
      snapshot_retention_limit   = 7
      snapshot_window            = "21:00-22:00"
      maintenance_window         = "sun:22:30-sun:23:30"
      auto_minor_version_upgrade = true
    }
    
    output "serverless_endpoint" {
      value = aws_elasticache_serverless_cache.sessions.endpoint[0].address
    }
    
    output "cluster_endpoint" {
      value = aws_elasticache_replication_group.orders.configuration_endpoint_address
    }
    # pip install "redis>=5" boto3
    # Connects to ElastiCache with TLS and an IAM token, then shows cache-aside reads with a lock against stampedes, and a simple rate limit.
    import json
    import random
    import time
    from urllib.parse import ParseResult, urlencode, urlunparse
    
    import botocore.session
    import redis
    from botocore.model import ServiceId
    from botocore.signers import RequestSigner
    
    REGION = "ap-south-1"
    TTL_SECONDS = 300
    MISSING = "__missing__"
    
    
    class IamCredentials(redis.CredentialProvider):
        """Signs a short-lived token (15 minutes) with the caller's AWS credentials. redis-py asks for a fresh one whenever it connects."""
    
        def __init__(self, user, cache_name, serverless=False):
            self.user, self.cache_name, self.serverless = user, cache_name, serverless
            session = botocore.session.get_session()
            self.signer = RequestSigner(ServiceId("elasticache"), REGION, "elasticache", "v4",
                                        session.get_credentials(), session.get_component("event_emitter"))
    
        def get_credentials(self):
            query = {"Action": "connect", "User": self.user}
            if self.serverless:
                query["ResourceType"] = "ServerlessCache"
            url = urlunparse(ParseResult("https", self.cache_name, "/", "", urlencode(query), ""))
            signed = self.signer.generate_presigned_url({"method": "GET", "url": url, "body": {}, "headers": {}, "context": {}},
                                                        operation_name="connect", expires_in=900, region_name=REGION)
            return self.user, signed.removeprefix("https://")
    
    
    def connect(host, user, cache_name, serverless=False):
        """Serverless caches and cluster-mode groups both want a cluster-aware client. Short timeouts keep a slow cache from stalling the app."""
        return redis.RedisCluster(host=host, port=6379, ssl=True, decode_responses=True, socket_timeout=0.5, socket_connect_timeout=0.5,
                                  credential_provider=IamCredentials(user, cache_name, serverless))
    
    
    def jittered(ttl):
        """Spreads expiry times so that a batch of keys written together does not all expire together."""
        return ttl + random.randint(0, ttl // 10)
    
    
    def get_or_load(r, key, load, ttl=TTL_SECONDS):
        """Returns the cached value. On a miss one caller runs load() under a short lock, and the others wait a moment and read the result."""
        hit = r.get(key)
        if hit is not None:
            return None if hit == MISSING else json.loads(hit)
    
        lock = "app:lock:" + key
        if r.set(lock, "1", nx=True, ex=10):
            try:
                value = load()
                if value is None:
                    r.set(key, MISSING, ex=30)  # remember "not found" briefly, so a missing row does not hit the database every time
                else:
                    r.set(key, json.dumps(value), ex=jittered(ttl))
                return value
            finally:
                r.delete(lock)
    
        for _ in range(20):  # another caller is loading: wait up to about a second
            time.sleep(0.05)
            hit = r.get(key)
            if hit is not None:
                return None if hit == MISSING else json.loads(hit)
        return load()  # the loader was slow: go to the database directly
    
    
    def save(r, key, row, write_to_database):
        """Writes the database first, then drops the cached copy, so the next read loads the new row."""
        write_to_database(row)
        r.delete(key)
    
    
    def allow(r, who, limit=100, window=60):
        """Fixed-window rate limit: True while `who` has made fewer than `limit` calls in the current window."""
        key = f"app:rate:{who}:{int(time.time()) // window}"
        count = r.incr(key)
        if count == 1:
            r.expire(key, window)
        return count <= limit
    
    
    if __name__ == "__main__":
        cache = connect("sessions-abc123.serverless.aps1.cache.amazonaws.com", "app-user", "sessions", serverless=True)
        product = get_or_load(cache, "app:product:42", lambda: {"id": 42, "name": "Notebook"})
        print(product, "| allowed:", allow(cache, "user-7"))
    // dotnet add package AWSSDK.ElastiCache
    // Audits every ElastiCache replication group and serverless cache in the Region: encryption, sign-in, failover, snapshots and usage limits.
    using Amazon.ElastiCache;
    using Amazon.ElastiCache.Model;
    
    using var elasticache = new AmazonElastiCacheClient();
    int problems = 0;
    
    void Flag(string name, string message)
    {
        Console.WriteLine($"{name}: {message}");
        problems++;
    }
    
    string? marker = null;
    do
    {
        var page = await elasticache.DescribeReplicationGroupsAsync(new DescribeReplicationGroupsRequest { Marker = marker });
        foreach (ReplicationGroup group in page.ReplicationGroups)
        {
            string name = group.ReplicationGroupId;
            if (group.TransitEncryptionEnabled != true) Flag(name, "encryption in transit is off");
            if (group.AtRestEncryptionEnabled != true) Flag(name, "encryption at rest is off");
            if (group.AuthTokenEnabled != true && (group.UserGroupIds == null || group.UserGroupIds.Count == 0))
                Flag(name, "no password, token or user group: any client in the VPC can connect");
            if (group.MemberClusters.Count > 1 && (group.MultiAZ != MultiAZStatus.Enabled || group.AutomaticFailover != AutomaticFailoverStatus.Enabled))
                Flag(name, "has replicas but Multi-AZ or automatic failover is off");
            if (group.SnapshotRetentionLimit is null or 0) Flag(name, "automatic snapshots are off");
            if (group.AutoMinorVersionUpgrade != true) Flag(name, "automatic minor version upgrades are off");
        }
        marker = page.Marker;
    } while (marker != null);
    
    string? token = null;
    do
    {
        var page = await elasticache.DescribeServerlessCachesAsync(new DescribeServerlessCachesRequest { NextToken = token });
        foreach (ServerlessCache cache in page.ServerlessCaches)
        {
            string name = cache.ServerlessCacheName;
            if (string.IsNullOrEmpty(cache.UserGroupId)) Flag(name, "no user group: any client in the VPC can connect");
            if (cache.SnapshotRetentionLimit is null or 0) Flag(name, "automatic snapshots are off");
            if (cache.CacheUsageLimits?.ECPUPerSecond?.Maximum is null && cache.CacheUsageLimits?.DataStorage?.Maximum is null)
                Flag(name, "no usage limits, so the bill is not capped");
        }
        token = page.NextToken;
    } while (token != null);
    
    Console.WriteLine(problems == 0 ? "No problems found." : $"{problems} problem(s) found.");
    return problems == 0 ? 0 : 1;

    Best videos to explore

    Videos picked for this service. Each one is labelled with its source, opens on YouTube if you prefer, and loads only when you press play.

    Introducing Amazon ElastiCache ServerlessOfficial · AWS · Beginner · Watch on YouTube
    AWS Databases in 15 - Getting Started with ElastiCache for Redis Performance & Cost OptimizationOfficial · AWS · Intermediate · Watch on YouTube
    AWS re:Invent 2021 - Deep dive on Amazon ElastiCache for RedisOfficial · AWS · Advanced · Watch on YouTube
    Amazon ElastiCache Overview: In-Memory Data Store for Redis and MemcachedCommunity video · Beginner · Watch on YouTube

    Interview questions

    BasicWhat is Amazon ElastiCache used for?

    It’s a managed in-memory store that most teams use as a cache in front of a database, so frequent reads return in microseconds without a query. It’s also used for session storage, counters, rate limits, leaderboards and light queues, because the engines support data structures beyond plain key-value pairs.

    BasicWhich engines does ElastiCache support?

    Valkey, Redis OSS and Memcached. Valkey and Redis OSS offer rich data types, replication, snapshots and failover. Memcached is simpler, multi-threaded and has no replication or persistence. For new work on Valkey and Redis OSS, AWS prices Valkey lower.

    BasicWhat is the difference between ElastiCache Serverless and node-based clusters?

    Serverless needs no capacity planning: you name the cache and, if you wish, set limits, and it grows and shrinks with demand behind one endpoint. A node-based cluster has node types, shards and replicas that you choose, which gives control and reserved pricing but also work in sizing and resharding.

    IntermediateWhat is the cache-aside pattern?

    The application checks the cache first. On a hit it uses the value. On a miss it reads the database, stores the result with a time to live and returns it. On a write it changes the database and then removes the cached copy. The cache stays optional, so losing it costs speed and not data.

    IntermediateHow does failover work with Multi-AZ?

    A replication group keeps replicas in other zones. If the primary fails, ElastiCache promotes a replica and updates the endpoint DNS, which typically takes under a minute or so. Clients must reconnect and retry, and a few of the latest writes can be lost because replication is asynchronous.

    IntermediateWhat does the eviction policy do?

    It decides what the engine removes when memory is full. The ElastiCache default evicts the least recently used keys among those that have a TTL, so keys without a TTL are never removed, and once memory is full with nothing left to evict, writes fail. Choose the policy to match whether everything in the cache is expendable.

    AdvancedHow would you design a secure, highly available cache for an application with personal data?

    Use a node-based or serverless cache in private subnets across three zones, with a replica in another zone, TLS, encryption at rest with a customer key and IAM authentication through a user group that allows only the commands and key prefixes the application needs. Keep TTLs short on personal data, send logs to CloudWatch, alarm on memory, evictions and CPU, and restrict who can modify the cache.

    AdvancedHow do you prevent a cache stampede?

    A hot key expiring sends a burst of identical misses to the database. Several defences work together: a short lock so a single caller does the rebuild, expiry times with some random spread, early refresh of the busiest keys, and a load test that begins with an empty cache to prove the database can take it.

    AdvancedWhy do cluster-mode caches give CROSSSLOT errors, and how do you avoid them?

    Cluster mode assigns every key to a hash slot, and each slot lives on one shard. If a single command or transaction names keys from more than one slot, the server refuses it. Wrap the shared part of related keys in braces, as in {user:7}, so they hash together, and do multi-key work only inside such groups.

    AdvancedHow would you decide between ElastiCache and a durable in-memory database such as MemoryDB?

    Ask whether the data can be rebuilt. If it can, a cache is cheaper and simpler. If the in-memory store is the system of record and must not lose acknowledged writes, a service with a durable log fits better, at higher cost. Many designs keep the real data in a database and use ElastiCache only to speed up reads.

    Similar or alternative services on other clouds

    CapabilityAWSAzureGoogle Cloud
    ServiceAmazon ElastiCacheAzure Cache for Redis and Azure Managed RedisMemorystore
    EnginesValkey, Redis OSS, MemcachedRedis, on the Redis Enterprise engine for Managed RedisValkey, Redis, Memcached
    Hands-off modeElastiCache ServerlessSized tiers, no serverless modeSized by node type and shard count
    Scaling outShards and replicas, onlineLarger sizes and clustering policyShards and replicas, online
    Private accessVPC subnets and security groupsPrivate endpointPrivate Service Connect or private services access
    Sign-inIAM authentication and user groupsMicrosoft Entra ID or access keysIAM authentication or token
    Across RegionsGlobal DatastoreActive geo-replicationCross-instance replication
    BackupsSnapshots to S3Persistence and exportManaged backups and persistence
    How you are billedGigabyte-hours and compute units, or node-hoursHourly price by tier and sizeNode-hours by node type

    Typical clients are Amazon EC2 instances, Amazon EKS pods and AWS Lambda functions inside the same VPC, with Amazon RDS or Amazon DynamoDB behind the cache. Cache metrics and alarms live in Amazon CloudWatch.

    Did you find this article helpful?

    Your answer helps us improve this page for the next reader.

    Sources and further reading

    CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.