Commit df9b566
committed
Add replica-only node type for read scalability
This commit introduces a new `replica_only` node role that provides
read scalability without impacting the write path or triggering cluster
rebalancing, enabling cost-effective horizontal scaling for read-heavy
workloads.
## Motivation
Organizations often need to scale read capacity independently from write
capacity. Traditional approaches of adding more data nodes cause:
- Unwanted shard rebalancing across the cluster
- Increased write coordination overhead
- Higher infrastructure costs for full-featured data nodes
The replica-only node type addresses these challenges by:
- Providing read-only shard hosting without participating in primary
shard allocation or rebalancing
- Enabling cheap, ephemeral nodes that can be added/removed without
cluster disruption
- Supporting integration with object stores (S3, etc.) for pulling
index data on-demand
## Why Auto-Expand Replicas 0-all Only
The replica-only node type exclusively supports indices with
`index.auto_expand_replicas: 0-all` for several critical reasons:
1. **Dynamic Replica Management**: Auto-expand automatically adjusts
replica counts when replica-only nodes join/leave, eliminating
manual intervention and preventing under-replication
2. **No Manual Rebalancing**: Without auto-expand, adding replica-only
nodes would require manual replica count adjustments and could
trigger rebalancing on data nodes
3. **Predictable Behavior**: The 0-all setting guarantees one copy per
eligible node, making replica distribution deterministic and
transparent
4. **Operational Safety**: Prevents accidental allocation of critical
production indices to nodes that may be ephemeral or have different
SLAs
## High-Level Design
### Core Components
1. **New Node Role (DiscoveryNodeRole.REPLICA_ONLY_ROLE)**
- Role name: `replica_only`
- Dedicated role that cannot coexist with any other role
2. **Allocation Decider (ReplicaOnlyAllocationDecider)**
- Blocks ALL primary shard allocation to replica-only nodes
- Blocks replica allocation unless index has auto_expand_replicas:
0-all
- Prevents force allocation of primaries (safety guarantee)
3. **Rebalancing Prevention (LocalShardsBalancer)**
- Excludes replica-only nodes from rebalancing model entirely
- Adding/removing replica-only nodes causes zero data node
rebalancing
- Maintains cluster balance stability
4. **Replica Promotion Prevention (RoutingNodes)**
- Blocks promotion of replicas to primaries on replica-only nodes
- Cluster enters YELLOW/RED state when primary fails and only
replica-only nodes have copies
- Ensures data integrity by requiring regular data node for primaries
## Design Concerns Addressed
### 1. Data Integrity and Cluster Health
What happens if primary fails and only replica-only nodes
have copies?
Replicas on replica-only nodes NEVER promote to primaries.
The cluster enters YELLOW/RED state and waits for a regular data node.
This prevents data loss scenarios where an ephemeral node becomes the
source of truth.
### 2. Rebalancing Isolation
Will replica-only nodes trigger rebalancing on production
data nodes?
Replica-only nodes are completely excluded from the
BalancedShardsAllocator model. They are invisible to the balancer,
ensuring zero rebalancing impact when nodes join/leave.
### 3. Role Transitions
What happens if a data node transitions to replica-only role?
- Primary shards are relocated to other data nodes
- Replicas from non-auto-expand indices are relocated out
- Replicas from auto-expand 0-all indices remain
- All transitions are safe with no data loss (canRemain() enforcement)
### 4. Recovery Code Paths
Could recovery logic accidentally create primaries on
replica-only nodes?
No, via multiple layers of protection:
- AllocationDecider blocks at allocation time
- canForceAllocatePrimary() blocks forced allocation
- promoteReplicaToPrimary() has explicit replica-only check
### 5. Auto-Expand Node Counting
How do replica-only nodes integrate with auto-expand
replica counting?
shouldAutoExpandToNode() in ReplicaOnlyAllocationDecider
is automatically called by
AutoExpandReplicas.getDesiredNumberOfReplicas().
Replica-only nodes are counted only for 0-all indices, ensuring correct
replica counts.
## Configuration Example
Node configuration:
```yaml
node.roles: [replica_only]
```
Index configuration:
```json
PUT /my-index
{
"settings": {
"index.auto_expand_replicas": "0-all"
}
}
```1 parent 88ffbc7 commit df9b566
8 files changed
Lines changed: 600 additions & 1 deletion
File tree
- server/src
- main/java/org/opensearch/cluster
- node
- routing
- allocation
- allocator
- decider
- test/java/org/opensearch/cluster
- node
- routing/allocation/decider
Lines changed: 2 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
| 80 | + | |
80 | 81 | | |
81 | 82 | | |
82 | 83 | | |
| |||
396 | 397 | | |
397 | 398 | | |
398 | 399 | | |
| 400 | + | |
399 | 401 | | |
400 | 402 | | |
401 | 403 | | |
| |||
Lines changed: 13 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
133 | 137 | | |
134 | 138 | | |
135 | 139 | | |
| |||
542 | 546 | | |
543 | 547 | | |
544 | 548 | | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
545 | 558 | | |
546 | 559 | | |
547 | 560 | | |
| |||
Lines changed: 38 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
337 | 337 | | |
338 | 338 | | |
339 | 339 | | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
340 | 375 | | |
341 | 376 | | |
342 | 377 | | |
343 | 378 | | |
344 | | - | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
345 | 382 | | |
346 | 383 | | |
347 | 384 | | |
| |||
Lines changed: 18 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
85 | 86 | | |
86 | 87 | | |
87 | 88 | | |
| 89 | + | |
| 90 | + | |
88 | 91 | | |
89 | 92 | | |
90 | 93 | | |
| |||
812 | 815 | | |
813 | 816 | | |
814 | 817 | | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
815 | 833 | | |
816 | 834 | | |
817 | 835 | | |
| |||
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
765 | 765 | | |
766 | 766 | | |
767 | 767 | | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
768 | 777 | | |
769 | 778 | | |
770 | 779 | | |
| |||
Lines changed: 140 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
Lines changed: 37 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
162 | 199 | | |
0 commit comments