Skip to content

Commit 4ec6771

Browse files
committed
first approximation to handling smigrated
1 parent 5d80d07 commit 4ec6771

File tree

5 files changed

+457
-37
lines changed

5 files changed

+457
-37
lines changed

CLUSTER-ARCHITECTURE.txt

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
Redis Cluster Architecture Diagram
2+
===================================
3+
4+
┌─────────────────────────────────────────┐
5+
│ RedisCluster (Root) │
6+
│ │
7+
│ - _options: RedisClusterOptions │
8+
│ - _slots: RedisClusterSlots │
9+
│ - _commandOptions │
10+
│ │
11+
│ Methods: │
12+
│ + connect() │
13+
│ + sendCommand() │
14+
│ + MULTI() │
15+
│ + SUBSCRIBE() / UNSUBSCRIBE() │
16+
│ + SSUBSCRIBE() / SUNSUBSCRIBE() │
17+
│ + close() / destroy() │
18+
└──────────────┬──────────────────────────┘
19+
20+
│ contains
21+
22+
┌──────────────────────────┴──────────────────────────┐
23+
│ │
24+
│ RedisClusterSlots │
25+
│ │
26+
│ - slots: Array<Shard>[16384] │
27+
│ - masters: Array<MasterNode> │
28+
│ - replicas: Array<ShardNode> │
29+
│ - nodeByAddress: Map<string, Node> │
30+
│ - pubSubNode?: PubSubNode │
31+
│ - clientSideCache?: PooledClientSideCacheProvider │
32+
│ │
33+
│ Methods: │
34+
│ + connect() │
35+
│ + getClient() │
36+
│ + rediscover() │
37+
│ + getPubSubClient() │
38+
│ + getShardedPubSubClient() │
39+
│ + getRandomNode() │
40+
│ + getSlotRandomNode() │
41+
└───────┬─────────────────┬─────────────────┬─────────┘
42+
│ │ │
43+
┌──────────┘ │ └─────────────┐
44+
│ │ │
45+
│ has many │ optionally has │ has many
46+
▼ ▼ ▼
47+
┌────────────────────────┐ ┌────────────────────────┐ ┌────────────────────────┐
48+
│ Shard │ │ PubSubNode │ │ RedisClient │
49+
│ │ │ │ │ (per node) │
50+
│ - master: MasterNode │ │ - address: string │ │ │
51+
│ - replicas?: Array │ │ - client: RedisClient │ │ Socket, Queue, etc. │
52+
│ - nodesIterator │ │ - connectPromise │ │ │
53+
└──────────┬─────────────┘ └────────────────────────┘ └────────────────────────┘
54+
55+
│ contains
56+
57+
┌────────────┴────────────┐
58+
│ │
59+
▼ ▼
60+
┌──────────────────┐ ┌──────────────────┐
61+
│ MasterNode │ │ ShardNode │
62+
│ │ │ (replica) │
63+
│ - id: string │ │ │
64+
│ - host: string │ │ - id: string │
65+
│ - port: number │ │ - host: string │
66+
│ - address │ │ - port: number │
67+
│ - readonly: no │ │ - address │
68+
│ - client? │ │ - readonly: yes │
69+
│ - pubSub? │ │ - client? │
70+
│ └─> client │ │ │
71+
│ └─> promise │ │ │
72+
└──────────────────┘ └──────────────────┘
73+
74+
75+
Additional Components:
76+
─────────────────────
77+
78+
┌────────────────────────────────────┐
79+
│ RedisClusterMultiCommand │
80+
│ │
81+
│ Used for MULTI/PIPELINE: │
82+
│ - Batches commands │
83+
│ - Routes to single node │
84+
│ - Returns typed results │
85+
│ │
86+
│ Methods: │
87+
│ + addCommand() │
88+
│ + exec() │
89+
│ + execAsPipeline() │
90+
└────────────────────────────────────┘
91+
92+
┌────────────────────────────────────┐
93+
│ PooledClientSideCacheProvider │
94+
│ (BasicPooledClientSideCache) │
95+
│ │
96+
│ RESP3 Client-Side Caching: │
97+
│ - Shared across all nodes │
98+
│ - Invalidation tracking │
99+
│ - TTL & eviction policies │
100+
│ │
101+
│ Methods: │
102+
│ + get() / set() │
103+
│ + invalidate() │
104+
│ + clear() / enable() / disable() │
105+
└────────────────────────────────────┘
106+
107+
108+
Key Relationships:
109+
─────────────────
110+
111+
1. RedisCluster
112+
└─> RedisClusterSlots (manages topology)
113+
└─> Shard[] (16,384 hash slots)
114+
├─> MasterNode (read/write)
115+
│ └─> RedisClient
116+
│ └─> PubSub RedisClient (sharded pub/sub)
117+
└─> ShardNode[] (replicas, read-only if useReplicas=true)
118+
└─> RedisClient
119+
120+
2. RedisCluster
121+
└─> RedisClusterMultiCommand (for transactions)
122+
123+
3. RedisClusterSlots
124+
└─> PubSubNode (global pub/sub)
125+
└─> RedisClient
126+
127+
4. RedisClusterSlots
128+
└─> PooledClientSideCacheProvider (shared cache, RESP3 only)
129+
130+
131+
Command Flow:
132+
────────────
133+
134+
Single Command:
135+
Client.sendCommand()
136+
→ Cluster._execute()
137+
→ Slots.getClient(key, isReadonly)
138+
→ Calculate slot from key
139+
→ Get Shard for slot
140+
→ Return master or replica client
141+
→ Client.sendCommand()
142+
→ [If MOVED/ASK error]
143+
→ Slots.rediscover()
144+
→ Retry with new node
145+
146+
Transaction (MULTI):
147+
Client.MULTI(routing)
148+
→ RedisClusterMultiCommand
149+
→ Accumulate commands
150+
→ All commands must route to same node
151+
→ client.exec()
152+
153+
Pub/Sub:
154+
Global: Uses single PubSubNode
155+
Sharded: Uses per-master pubSub client based on channel hash
156+
157+
158+
Discovery & Failover:
159+
─────────────────────
160+
161+
1. Initial Connect:
162+
- Try rootNodes in random order
163+
- Execute CLUSTER SLOTS command
164+
- Build slot → shard mapping
165+
- Create client connections
166+
167+
2. Rediscovery (on MOVED error):
168+
- Clear cache
169+
- Re-fetch CLUSTER SLOTS
170+
- Update topology
171+
- Reconnect clients to new nodes
172+
173+
3. Node Address Mapping:
174+
- nodeAddressMap translates cluster IPs
175+
- Useful for NAT/Docker scenarios

0 commit comments

Comments
 (0)