ELK Stack — Shards & Replicas
Shards and Replicas
Elasticsearch distributes data across multiple pieces called shards and creates copies called replicas for fault tolerance. Understanding sharding is critical for designing scalable, resilient clusters.
What Is a Shard?
A shard is a self-contained Lucene index — a subset of your Elasticsearch index. When you create an index, Elasticsearch splits it into one or more shards.
┌──────────────────────────────────────────────────┐
│ Index: nginx-logs (3 shards, 1 replica) │
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Shard 0 │ │ Shard 1 │ │ Shard 2 │ │
│ │ (Primary) │ │ (Primary) │ │ (Primary) │ │
│ │ │ │ │ │ │ │
│ │ Docs 1-100 │ │ Docs 101- │ │ Docs 201- │ │
│ │ │ │ 200 │ │ 300 │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└──────────────────────────────────────────────────┘
Why shard?
- Parallelism — searches run on all shards simultaneously
- Scalability — shards can be distributed across multiple nodes
- Size limits — a single Lucene index (shard) has a practical limit of ~50 GB
What Is a Replica?
A replica is a copy of a primary shard on a different node. Replicas serve two purposes:
- High availability — if a node dies, the replica takes over
- Read throughput — search queries can be served by replicas too
┌─────────────────────────────────────────────────────────┐
│ 3-Node Cluster (3 shards, 1 replica) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ │ │ │ │ │ │
│ │ Shard 0 (P) │ │ Shard 1 (P) │ │ Shard 2 (P) │ │
│ │ Shard 1 (R) │ │ Shard 2 (R) │ │ Shard 0 (R) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ (P) = Primary shard │
│ (R) = Replica shard │
│ │
│ If Node 1 dies: Shard 0 replica on Node 3 becomes │
│ primary. No data loss! │
└─────────────────────────────────────────────────────────┘
Setting Shards and Replicas
When creating an index:
$ curl -X PUT -u elastic:changeme123 \
"http://localhost:9200/my-index" \
-H "Content-Type: application/json" \
-d '{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}'
number_of_shards— fixed at creation time (cannot be changed later without reindexing)number_of_replicas— can be changed anytime
Change Replica Count Dynamically
$ curl -X PUT -u elastic:changeme123 \
"http://localhost:9200/my-index/_settings" \
-H "Content-Type: application/json" \
-d '{
"index": {
"number_of_replicas": 2
}
}'
View Shard Allocation
$ curl -u elastic:changeme123 "http://localhost:9200/_cat/shards/my-index?v"
Expected output:
index shard prirep state docs store ip node
my-index 0 p STARTED 100 50kb 172.18.0.2 es-node-1
my-index 0 r STARTED 100 50kb 172.18.0.3 es-node-2
my-index 1 p STARTED 98 48kb 172.18.0.3 es-node-2
my-index 1 r STARTED 98 48kb 172.18.0.4 es-node-3
my-index 2 p STARTED 102 52kb 172.18.0.4 es-node-3
my-index 2 r STARTED 102 52kb 172.18.0.2 es-node-1
How Many Shards Do You Need?
This is one of the most common questions. Here are the guidelines:
| Index Size | Recommended Shards | Reasoning |
|---|---|---|
| < 1 GB | 1 shard | Over-sharding wastes resources |
| 1-50 GB | 1-2 shards | Keep shards between 10-50 GB |
| 50-200 GB | 2-5 shards | Distribute across nodes |
| > 200 GB | Aim for 20-50 GB per shard | Balance search parallelism |
Rules of thumb:
- Target shard size: 10-50 GB — shards that are too small waste resources; shards that are too large slow searches
- Max shards per node: ~1000 — each shard consumes memory and file handles
- For log indices: 1 shard per daily index is often enough (if < 50 GB/day)
- Over-sharding is worse than under-sharding — too many small shards create overhead
The Over-Sharding Problem
BAD: 1000 indices × 5 shards × 1 replica = 10,000 shards
(Each shard uses ~30-50 MB of heap memory)
(10,000 × 40 MB = 400 GB of heap just for shard overhead!)
GOOD: 1000 indices × 1 shard × 1 replica = 2,000 shards
(Much more manageable)
Single-Node Clusters and Yellow Health
On a single-node cluster, replicas can never be allocated (no other node to put them on), so cluster health is always yellow:
$ curl -u elastic:changeme123 "http://localhost:9200/_cluster/health?pretty"
{
"status": "yellow",
"unassigned_shards": 1
}
Fix for learning/dev: Set replicas to 0:
$ curl -X PUT -u elastic:changeme123 \
"http://localhost:9200/my-index/_settings" \
-H "Content-Type: application/json" \
-d '{ "index": { "number_of_replicas": 0 } }'
Now health will be green.
Shard Routing — How Documents Find Their Shard
When you index a document, Elasticsearch determines which shard it goes to using this formula:
shard = hash(_routing) % number_of_primary_shards
By default, _routing is the document _id. This ensures documents are evenly distributed across shards.
This is why you can’t change number_of_shards after index creation — changing it would break the routing formula and documents would end up in the wrong shards.
Split and Shrink APIs
If you need to change shard count:
Split (increase shards):
$ curl -X POST -u elastic:changeme123 \
"http://localhost:9200/my-index/_split/my-index-split" \
-H "Content-Type: application/json" \
-d '{ "settings": { "index.number_of_shards": 6 } }'
Shrink (decrease shards):
$ curl -X POST -u elastic:changeme123 \
"http://localhost:9200/my-index/_shrink/my-index-shrunk" \
-H "Content-Type: application/json" \
-d '{ "settings": { "index.number_of_shards": 1 } }'
Quick Reference
Concept Key Point Primary shard Original piece of an index Replica shard Copy of a primary on a different node Shard sizing Target 10-50 GB per shard Shards fixed number_of_shardsset at creation (use split/shrink to change)Replicas dynamic number_of_replicaschangeable anytimeSingle-node yellow Normal — no node for replicas; set replicas to 0 Over-sharding Too many small shards waste memory; avoid View shards GET /_cat/shards/my-index?v
Next Step
You understand the storage model. Let’s get hands-on with CRUD operations — creating, reading, updating, and deleting documents.