ElastiCache, OpenSearch, and Database Selection
ElastiCache, OpenSearch Service, and AWS database services solve different data problems. The outcome of this lesson is not a memorized list of products; it is the ability to map an application requirement to the right storage or retrieval mechanism and explain the consequences. A shopping cart needs durable transactional writes. A product search box needs relevance ranking and inverted indexes. A session lookup may need sub-millisecond reads and can often tolerate regeneration. Those are different shapes of state, so they should not automatically share one backend.
In this part of the AWS Cloud course, you are moving from individual services to architecture selection. The design skill is to start with access patterns: how data is written, how it is read, how fresh it must be, what happens if it disappears, and how operators recover it. AWS offers purpose-built data services because one storage engine cannot optimize equally for key-value lookup, relational joins, document search, graph traversal, time-series ingestion, and in-memory caching.
What Each Service Is For
Amazon ElastiCache runs managed Redis OSS, Valkey, or Memcached-compatible in-memory clusters. It is usually placed in front of a durable database to reduce read latency, absorb hot-key traffic, store short-lived sessions, coordinate lightweight counters, or maintain ephemeral leaderboards. The key idea is that memory is fast but not the primary system of record for most business data.
Amazon OpenSearch Service runs managed OpenSearch clusters for search, log analytics, and near-real-time document retrieval. It stores documents in indexes, breaks text into tokens, and uses inverted indexes so a query such as wireless noise cancelling headphones can find documents containing related terms without scanning every product description. It is usually fed from another source of truth, such as DynamoDB streams, application events, S3 objects, or relational change data capture.
Database selection is the discipline of choosing a durable system of record. Amazon RDS and Aurora fit relational workloads with SQL, transactions, joins, and mature operational tooling. DynamoDB fits high-scale key-value and document access patterns with predictable partition-key queries. DocumentDB, Neptune, Timestream, Keyspaces, and Redshift cover other specialized models. The right answer depends on query shape, consistency needs, scale pattern, and operational complexity.
Internal Mechanisms
ElastiCache improves latency because data is already in memory and addressed by key. A cache-aside application checks the cache first. On a miss, it reads the database, writes the result into the cache with a time to live, then returns the value. Redis-style engines also provide data structures such as strings, hashes, sorted sets, lists, and streams. Clustered Redis-compatible deployments shard keys across nodes by hash slot. Replicas can serve reads and provide failover targets, but replication lag and failover windows mean the cache should not be treated as the only durable copy unless the workload has been explicitly designed for that risk.
OpenSearch works differently. A document is sent to an index. The index mapping defines field types such as keyword, text, date, integer, and vector fields where enabled. Text fields are analyzed: the analyzer tokenizes strings, normalizes case, and may remove stop words or apply stemming. OpenSearch writes data into shards, and each shard is a Lucene index. Searches fan out to relevant shards, score matches, merge results, and return ranked hits. Refresh intervals make newly indexed documents searchable after a short delay, so OpenSearch is near-real-time rather than strictly transactional.
Relational databases organize data into tables with schemas, indexes, constraints, and transactions. They are strong when the application needs multi-row consistency, joins, foreign keys, and SQL reporting. DynamoDB organizes data by primary key and partitions throughput across storage partitions. It is strong when requests can be modeled as direct key lookups or bounded range queries. The most important DynamoDB design step is choosing partition and sort keys from known access patterns, not from an abstract entity diagram.
Configuration Anatomy
For ElastiCache, important configuration choices include engine family, node type, cluster mode, number of replicas, subnet group, security groups, encryption, authentication, automatic backups for Redis-compatible engines, parameter groups, and eviction policy. A cache with maxmemory-policy allkeys-lru behaves differently from one that refuses writes when memory fills. A small cache can be worse than no cache if it constantly evicts hot data and overloads the database with misses.
For OpenSearch, the core objects are domains, indexes, mappings, shards, replicas, ingest pipelines, access policies, snapshots, and dashboards. Shard count affects parallelism and overhead. Too few shards limit scale; too many shards waste heap and slow cluster state operations. Field mapping matters because a keyword field supports exact matching and aggregations, while a text field supports full-text search.
For database selection, describe the workload before naming the service: read/write ratio, access patterns, item size, transaction boundaries, consistency requirements, retention, growth rate, recovery point objective, recovery time objective, and administrative skills. A database decision is incomplete until it states how backups, schema changes, scaling, authentication, and failover will work.
Worked Example 1: Pick the System of Record
The first example scores four common workload descriptions. It is intentionally simple, but it forces the decision to start from access patterns instead of service preference.
workloads = [
{"name": "orders", "needs_sql": True, "full_text": False, "ephemeral": False, "key_value_scale": False},
{"name": "product_search", "needs_sql": False, "full_text": True, "ephemeral": False, "key_value_scale": False},
{"name": "session_tokens", "needs_sql": False, "full_text": False, "ephemeral": True, "key_value_scale": True},
{"name": "device_readings", "needs_sql": False, "full_text": False, "ephemeral": False, "key_value_scale": True},
]
for workload in workloads:
if workload["full_text"]:
choice = "OpenSearch for search index, plus a durable source of truth"
elif workload["ephemeral"]:
choice = "ElastiCache with TTL, backed by re-login or regeneration"
elif workload["needs_sql"]:
choice = "Aurora or RDS for relational transactions"
elif workload["key_value_scale"]:
choice = "DynamoDB when access patterns are key-based"
else:
choice = "Re-check requirements before choosing"
print(f"{workload['name']}: {choice}")
Expected output is deterministic: orders maps to Aurora or RDS, product_search maps to OpenSearch plus a durable source, session_tokens maps to ElastiCache with TTL, and device_readings maps to DynamoDB. The main lesson is that OpenSearch is not the order database and ElastiCache is not the durable ledger.
Worked Example 2: Add Cache-Aside Reads
Assume a product detail page reads the same item thousands of times per minute. The source of truth can remain DynamoDB or Aurora, while ElastiCache stores a short-lived copy. The application reads the cache key product:123. On a miss, it reads the database and stores the serialized value for 300 seconds. If the product is edited, the application can delete the cache key immediately or rely on TTL for eventual refresh.
The expected behavior is measurable. First request after expiry is slower because it reaches the database. Repeated requests are faster and reduce database read load. If the cache node fails, the application should still serve correct data by falling back to the database, though latency and database load increase until the cache recovers or warms again.
Worked Example 3: Search Index Mapping
A catalog search page needs text relevance for names and descriptions, exact filters for brand, and numeric filtering for price. That points to OpenSearch as a secondary index, not as the only product store.
{
"mappings": {
"properties": {
"product_id": {"type": "keyword"},
"name": {"type": "text"},
"brand": {"type": "keyword"},
"description": {"type": "text"},
"price_cents": {"type": "integer"},
"updated_at": {"type": "date"}
}
}
}
With this mapping, a query can search analyzed text in name and description, filter exactly on brand, and filter ranges on price_cents. If brand were mapped only as text, aggregations and exact filters would behave poorly because the value would be tokenized. If price_cents were stored as text, numeric range queries would not have the intended semantics.
Worked Example 4: Compare Latency and Durability
A login service stores refresh tokens. ElastiCache alone gives fast lookup and TTL expiry, but token loss during cache failure may force users to sign in again. DynamoDB gives durable key-value storage with TTL-based cleanup, but each lookup is slower than an in-memory cache. A common design is DynamoDB as the durable token registry and ElastiCache as a short-lived acceleration layer. The correction path is clear: if the cache misses, read DynamoDB; if DynamoDB says the token is revoked, never accept the cached value.
Design Trade-Offs
ElastiCache trades durability and memory cost for latency. Use it when the same data is read repeatedly, when recomputation is expensive, or when temporary state is acceptable. Avoid it as the only copy of records that require auditability, legal retention, or exact recovery.
OpenSearch trades transactional guarantees for search and analytics features. It is excellent for relevance ranking, log exploration, and flexible document queries. It is a poor fit for bank balances, order placement, or workflows where a write must immediately participate in a strict transaction.
Relational databases trade horizontal write scaling simplicity for strong modeling and transactional power. DynamoDB trades ad hoc querying for predictable scale when access patterns are known. The mistake to avoid is choosing DynamoDB and then expecting arbitrary SQL-style exploration, or choosing Aurora and then expecting unlimited hot-key writes without schema and index work.
Failure Modes and Troubleshooting
Cache stampede: symptoms include sudden database CPU spikes, many cache misses, and increased page latency after a popular key expires. The cause is many clients recomputing the same value at once. Diagnose by comparing cache miss rate, database read throughput, and key expiry timing. Correct with jittered TTLs, request coalescing, background refresh, or temporary stale reads where acceptable.
Eviction surprises: symptoms include low hit rate even though the application writes to the cache. Causes include insufficient memory, oversized values, or an eviction policy that removes needed keys. Diagnose memory usage, evictions, item sizes, and key cardinality. Correct by increasing node size, reducing cached payload size, separating workloads, or changing TTL and eviction policy.
OpenSearch yellow or red cluster health: symptoms include missing replicas, failed indexing, slow searches, or unavailable shards. Causes include node loss, insufficient disk, shard allocation limits, or overloaded JVM heap. Diagnose cluster health, shard allocation explanations, disk watermarks, and rejected thread-pool operations. Correct by restoring capacity, freeing disk, reducing shard pressure, or scaling data nodes.
Wrong database model: symptoms include expensive scans, complex application-side joins, slow reports, or repeated schema workarounds. The cause is usually choosing a service before documenting access patterns. Diagnose by listing the top queries, their cardinality, indexes used, and consistency needs. Correct by adding the right index, changing keys, introducing a purpose-built read model, or migrating the system of record when the mismatch is fundamental.
Security, Performance, and Reliability
Keep ElastiCache and OpenSearch inside private subnets unless a specific design justifies otherwise. Use security groups to allow only application clients, encrypt traffic where supported by the selected engine and client, and use authentication rather than relying only on network reachability. For OpenSearch, combine network controls with fine-grained access control when different users or services need different index permissions.
Performance work should be based on service-specific signals. For ElastiCache, watch hit rate, evictions, CPU, memory, replication lag, and connection count. For OpenSearch, watch search latency, indexing latency, rejected operations, JVM pressure, disk usage, shard count, and cluster health. For databases, watch query latency, lock waits, consumed capacity, connection saturation, storage growth, and replica lag. Reliability improves when each derived store has a rebuild path from the source of truth.
Hands-On Lab
Prerequisites: an AWS account with permission to inspect data services, AWS CLI configured, a test VPC if you create resources, and a naming prefix such as course-data-choice. To avoid cost, this lab can be completed as a design and validation exercise before any resource creation.
- Write three workload rows:
orders,catalog_search, andsession_cache. For each, record primary key, read pattern, write pattern, freshness requirement, durability requirement, and recovery path. - Choose the primary store: Aurora or RDS for
orders, a relational or DynamoDB product table as the catalog source, and ElastiCache only for generated or recoverable session state. - Choose derived stores: OpenSearch for catalog search and ElastiCache for hot product reads if repeated lookups justify memory cost.
- Run the following read-only AWS CLI checks to see whether your account already has relevant services deployed.
set -euo pipefail
aws elasticache describe-cache-clusters --show-cache-node-info --output table
aws opensearch list-domain-names --output table
aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceStatus]' --output table
aws dynamodb list-tables --output table
Verification: you should have a written mapping from workload to service and CLI output showing current service inventory. If you create test resources later, verify that application subnets and security groups can reach them, that unauthorized principals cannot, and that deleting the cache does not delete durable business records. Cleanup: remove any test ElastiCache clusters, OpenSearch domains, database instances, tables, indexes, alarms, and security group rules created for the exercise. For production-like databases, take or confirm a snapshot before destructive cleanup.
Assessment Exercises
- A team stores order history only in Redis-compatible ElastiCache because reads are fast. Identify the data-loss risk and propose a corrected architecture.
- A product search API uses Aurora
LIKEqueries across long descriptions and is slowing down. Explain when OpenSearch helps and what remains in Aurora. - A DynamoDB table is experiencing hot partitions because all writes use the same tenant key. Describe how the key design could change and what query trade-off follows.
- An OpenSearch dashboard shows red cluster health after a node failure. List the diagnostic checks you would run before changing shard count or instance size.
- Design a cache invalidation approach for product prices where stale values are acceptable for at most 60 seconds.
Summary
Use ElastiCache for fast, usually recoverable in-memory access; OpenSearch for search and near-real-time document retrieval; and durable databases for systems of record. The selection process starts with access patterns, consistency, durability, latency, and recovery. A strong AWS design often combines services: a database owns truth, OpenSearch serves search, and ElastiCache accelerates hot reads without becoming an accidental ledger.
