0
# Sharded Redis Adapter
1
2
Advanced Redis adapter implementation utilizing Redis 7.0+ sharded pub/sub features for improved scalability and performance. Sharded pub/sub helps scale Socket.IO applications by distributing channel load across Redis cluster nodes.
3
4
## Capabilities
5
6
### Create Sharded Adapter
7
8
Creates a sharded Redis adapter factory function optimized for Redis 7.0+ sharded pub/sub.
9
10
```typescript { .api }
11
/**
12
* Creates a sharded Redis adapter factory using Redis 7.0+ sharded pub/sub
13
* @param pubClient - Redis client used to publish (from the 'redis' package)
14
* @param subClient - Redis client used to subscribe (from the 'redis' package)
15
* @param opts - Optional configuration options
16
* @returns Function that creates ShardedRedisAdapter instances for namespaces
17
*/
18
function createShardedAdapter(
19
pubClient: any,
20
subClient: any,
21
opts?: ShardedRedisAdapterOptions
22
): (nsp: any) => ShardedRedisAdapter;
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { Server } from "socket.io";
29
import { createClient } from "redis";
30
import { createShardedAdapter } from "@socket.io/redis-adapter";
31
32
// Basic sharded adapter setup
33
const pubClient = createClient({ host: "localhost", port: 6379 });
34
const subClient = pubClient.duplicate();
35
36
await Promise.all([
37
pubClient.connect(),
38
subClient.connect()
39
]);
40
41
const io = new Server({
42
adapter: createShardedAdapter(pubClient, subClient)
43
});
44
45
io.listen(3000);
46
47
// With custom options
48
const io2 = new Server({
49
adapter: createShardedAdapter(pubClient, subClient, {
50
channelPrefix: "my-app",
51
subscriptionMode: "dynamic-private"
52
})
53
});
54
```
55
56
### ShardedRedisAdapter Class
57
58
Main sharded adapter implementation that extends ClusterAdapter with Redis sharded pub/sub functionality.
59
60
```typescript { .api }
61
/**
62
* Sharded Redis adapter class using Redis 7.0+ sharded pub/sub features
63
* Extends ClusterAdapter from socket.io-adapter
64
*/
65
class ShardedRedisAdapter extends ClusterAdapter {
66
/**
67
* Create a new ShardedRedisAdapter instance
68
* @param nsp - Socket.IO namespace
69
* @param pubClient - Redis client for publishing
70
* @param subClient - Redis client for subscribing
71
* @param opts - Configuration options
72
*/
73
constructor(
74
nsp: any,
75
pubClient: any,
76
subClient: any,
77
opts?: ShardedRedisAdapterOptions
78
);
79
}
80
```
81
82
### Publishing Methods
83
84
Methods for publishing messages through sharded channels.
85
86
```typescript { .api }
87
/**
88
* Publishes a cluster message to appropriate sharded channel
89
* @param message - Message to publish
90
* @returns Promise resolving to offset (empty string for Redis)
91
*/
92
doPublish(message: ClusterMessage): Promise<Offset>;
93
94
/**
95
* Publishes a response to the requesting server's specific channel
96
* @param requesterUid - Unique ID of the requesting server
97
* @param response - Response message to send
98
* @returns Promise that resolves when message is published
99
*/
100
doPublishResponse(
101
requesterUid: string,
102
response: ClusterResponse
103
): Promise<void>;
104
```
105
106
### Server Management
107
108
Methods for managing server connections and counts.
109
110
```typescript { .api }
111
/**
112
* Gets the count of servers using sharded pub/sub
113
* Uses SHARDNUMSUB command for accurate server counting
114
* @returns Promise resolving to number of connected servers
115
*/
116
serverCount(): Promise<number>;
117
```
118
119
### Lifecycle Management
120
121
Methods for managing the sharded adapter lifecycle.
122
123
```typescript { .api }
124
/**
125
* Closes the sharded adapter and cleans up all subscriptions
126
* Unsubscribes from base channels and dynamic room channels
127
* @returns Promise that resolves when cleanup is complete
128
*/
129
close(): Promise<void>;
130
```
131
132
## Configuration Options
133
134
```typescript { .api }
135
interface ShardedRedisAdapterOptions {
136
/**
137
* The prefix for Redis Pub/Sub channels
138
* @default "socket.io"
139
*/
140
channelPrefix?: string;
141
142
/**
143
* Subscription mode that impacts the number of channels used:
144
*
145
* - "static": 2 channels per namespace
146
* Useful with dynamic namespaces
147
*
148
* - "dynamic": (2 + 1 per public room) channels per namespace
149
* Default value, optimal when some rooms have few clients
150
* Only creates channels for public rooms (not Socket IDs)
151
*
152
* - "dynamic-private": Like "dynamic" but includes private rooms
153
* Creates separate channels for Socket ID rooms
154
* Useful for lots of 1:1 communication via socket.emit()
155
*
156
* @default "dynamic"
157
*/
158
subscriptionMode?: "static" | "dynamic" | "dynamic-private";
159
}
160
```
161
162
## Subscription Modes Explained
163
164
### Static Mode
165
- **Channels**: 2 per namespace
166
- **Use Case**: Dynamic namespaces with unpredictable room patterns
167
- **Pros**: Predictable channel count, simple setup
168
- **Cons**: All messages go through same channels, less optimization
169
170
### Dynamic Mode (Default)
171
- **Channels**: 2 base + 1 per public room
172
- **Use Case**: Applications with some rooms having few clients
173
- **Pros**: Optimized delivery, servers only get relevant room messages
174
- **Cons**: More channels to manage
175
- **Note**: Only public rooms get separate channels, not Socket ID rooms
176
177
### Dynamic Private Mode
178
- **Channels**: 2 base + 1 per room (including private/Socket ID rooms)
179
- **Use Case**: Heavy 1:1 communication patterns
180
- **Pros**: Maximum optimization for direct socket communication
181
- **Cons**: Highest channel count, more subscription overhead
182
183
## Usage Examples
184
185
### Basic Sharded Setup
186
187
```typescript
188
import { createClient } from "redis";
189
import { Server } from "socket.io";
190
import { createShardedAdapter } from "@socket.io/redis-adapter";
191
192
const pubClient = createClient({ url: "redis://localhost:6379" });
193
const subClient = pubClient.duplicate();
194
195
await Promise.all([
196
pubClient.connect(),
197
subClient.connect()
198
]);
199
200
const io = new Server({
201
adapter: createShardedAdapter(pubClient, subClient)
202
});
203
204
// All Socket.IO operations work the same
205
io.emit("broadcast", "Hello everyone!");
206
io.to("room1").emit("room-message", "Hello room1!");
207
```
208
209
### Advanced Configuration
210
211
```typescript
212
const io = new Server({
213
adapter: createShardedAdapter(pubClient, subClient, {
214
channelPrefix: "my-game",
215
subscriptionMode: "dynamic-private" // Optimize for 1:1 messaging
216
})
217
});
218
219
// Efficient for direct socket communication
220
io.to(socketId).emit("private-message", "Hello specific user!");
221
```
222
223
### Room-based Broadcasting
224
225
```typescript
226
// With dynamic mode, each room gets its own optimized channel
227
io.to("lobby").emit("player-joined", { playerId: 123 });
228
io.to("game-room-1").emit("game-update", gameState);
229
230
// Servers not subscribed to these specific rooms won't receive these messages
231
```
232
233
## Requirements and Limitations
234
235
### Minimum Requirements
236
- **Redis**: Version 7.0 or higher
237
- **redis package**: Version 4.6.0 or higher
238
- **Node.js**: Version 10.0.0 or higher
239
240
### Limitations
241
- **ioredis with Redis Cluster**: Not currently supported for sharded adapter
242
- **Redis Clients**: Only the `redis` package is supported, not `ioredis`
243
- **Backward Compatibility**: Cannot mix sharded and regular adapters in same deployment
244
245
### Redis Commands Used
246
- **SPUBLISH**: For publishing to sharded channels
247
- **SSUBSCRIBE/SUNSUBSCRIBE**: For managing sharded subscriptions
248
- **SHARDNUMSUB**: For counting subscribers to sharded channels
249
250
## Migration from Regular Adapter
251
252
When migrating from the regular Redis adapter to the sharded adapter:
253
254
1. **Ensure Redis 7.0+**: Verify your Redis version supports sharded pub/sub
255
2. **Update Redis Client**: Use `redis` package v4.6.0+
256
3. **Change Import**: Switch from `createAdapter` to `createShardedAdapter`
257
4. **Update Configuration**: Review subscription mode for your use case
258
5. **Test Thoroughly**: Sharded pub/sub has different delivery patterns
259
260
```typescript
261
// Before (regular adapter)
262
import { createAdapter } from "@socket.io/redis-adapter";
263
const adapter = createAdapter(pubClient, subClient, {
264
key: "my-app"
265
});
266
267
// After (sharded adapter)
268
import { createShardedAdapter } from "@socket.io/redis-adapter";
269
const adapter = createShardedAdapter(pubClient, subClient, {
270
channelPrefix: "my-app",
271
subscriptionMode: "dynamic"
272
});
273
```