Ir al contenido principal
Versión: 4.x

Adaptador Redis

Cómo funciona

El adaptador Redis se basa en el mecanismo Pub/Sub de Redis.

Cada paquete que se envía a múltiples clientes (ej. io.to("room1").emit() o socket.broadcast.emit()) es:

  • enviado a todos los clientes coincidentes conectados al servidor actual
  • publicado en un canal Redis, y recibido por los otros servidores Socket.IO del clúster
Diagrama de cómo funciona el adaptador RedisDiagrama de cómo funciona el adaptador Redis

El código fuente de este adaptador se puede encontrar aquí.

Características soportadas

CaracterísticaVersión de socket.ioSoporte
Gestión de sockets4.0.0✅ SÍ (desde versión 6.1.0)
Comunicación entre servidores4.1.0✅ SÍ (desde versión 7.0.0)
Broadcast con acknowledgements4.5.0✅ SÍ (desde versión 7.2.0)
Recuperación del estado de conexión4.6.0❌ NO

Instalación

npm install @socket.io/redis-adapter

Tabla de compatibilidad

Versión del adaptador RedisVersión del servidor Socket.IO
4.x1.x
5.x2.x
6.0.x3.x
6.1.x4.x
7.x y superior4.3.1 y superior

Uso

consejo

Para nuevos desarrollos, recomendamos usar el adaptador sharded, que aprovecha la característica sharded Pub/Sub introducida en Redis 7.0.

Con el paquete redis

precaución

El paquete redis parece tener problemas restaurando las suscripciones Redis después de reconectarse:

Podrías querer usar el paquete ioredis en su lugar.

import { createClient } from "redis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = createClient({ url: "redis://localhost:6379" });
const subClient = pubClient.duplicate();

await Promise.all([
pubClient.connect(),
subClient.connect()
]);

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

Con el paquete redis y un clúster Redis

import { createCluster } from "redis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = createCluster({
rootNodes: [
{
url: "redis://localhost:7000",
},
{
url: "redis://localhost:7001",
},
{
url: "redis://localhost:7002",
},
],
});
const subClient = pubClient.duplicate();

await Promise.all([
pubClient.connect(),
subClient.connect()
]);

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

Con el paquete ioredis

import { Redis } from "ioredis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = new Redis();
const subClient = pubClient.duplicate();

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

Con el paquete ioredis y un clúster Redis

import { Cluster } from "ioredis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = new Cluster([
{
host: "localhost",
port: 7000,
},
{
host: "localhost",
port: 7001,
},
{
host: "localhost",
port: 7002,
},
]);
const subClient = pubClient.duplicate();

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

Con Redis sharded Pub/Sub

Sharded Pub/Sub fue introducido en Redis 7.0 para ayudar a escalar el uso de Pub/Sub en modo clúster.

Referencia: https://redis.io/docs/interact/pubsub/#sharded-pubsub

Se puede crear un adaptador dedicado con el método createShardedAdapter():

import { Server } from "socket.io";
import { createClient } from "redis";
import { createShardedAdapter } from "@socket.io/redis-adapter";

const pubClient = createClient({ host: "localhost", port: 6379 });
const subClient = pubClient.duplicate();

await Promise.all([
pubClient.connect(),
subClient.connect()
]);

const io = new Server({
adapter: createShardedAdapter(pubClient, subClient)
});

io.listen(3000);

Requisitos mínimos:

precaución

Actualmente no es posible usar el adaptador sharded con el paquete ioredis y un clúster Redis (referencia).

Opciones

Adaptador predeterminado

NombreDescripciónValor predeterminado
keyEl prefijo para los canales Redis Pub/Sub.socket.io
requestsTimeoutDespués de este timeout el adaptador dejará de esperar respuestas a solicitudes.5_000
publishOnSpecificResponseChannelSi publicar una respuesta al canal específico del nodo solicitante.false
parserEl parser a usar para codificar y decodificar mensajes enviados a Redis.-
consejo

Establecer la opción publishOnSpecificResponseChannel a true es más eficiente ya que las respuestas (por ejemplo al llamar fetchSockets() o serverSideEmit()) solo se envían al servidor solicitante, y no a todos los servidores.

Sin embargo, actualmente está en false por defecto para compatibilidad hacia atrás.

Adaptador sharded

NombreDescripciónValor predeterminado
channelPrefixEl prefijo para los canales Redis Pub/Sub.socket.io
subscriptionModeEl modo de suscripción impacta el número de canales Redis Pub/Sub usados por el adaptador.dynamic

Valores disponibles para la opción subscriptionMode:

Valor# de canales Pub/SubDescripción
static2 por namespaceÚtil cuando se usan namespaces dinámicos.
dynamic (defecto)(2 + 1 por sala pública) por namespaceÚtil cuando algunas salas tienen un bajo número de clientes (así solo unos pocos servidores Socket.IO son notificados).
dynamic-private(2 + 1 por sala) por namespaceComo dynamic pero crea canales separados para salas privadas también. Útil cuando hay mucha comunicación 1:1 vía llamadas socket.emit().

Preguntas frecuentes

¿Se almacena algún dato en Redis?

No, el adaptador Redis usa el mecanismo Pub/Sub para reenviar los paquetes entre los servidores Socket.IO, así que no hay claves almacenadas en Redis.

¿Todavía necesito habilitar sesiones sticky al usar el adaptador Redis?

Sí. No hacerlo resultará en respuestas HTTP 400 (estás llegando a un servidor que no conoce la sesión Socket.IO).

Más información se puede encontrar aquí.

¿Qué pasa cuando el servidor Redis está caído?

En caso de que la conexión al servidor Redis se corte, los paquetes solo se enviarán a los clientes que están conectados al servidor actual.

Últimas versiones

VersiónFecha de lanzamientoNotas de lanzamientoDiff
8.3.0Marzo 2024link8.2.1...8.3.0
8.2.1Mayo 2023link8.2.0...8.2.1
8.2.0Mayo 2023link8.1.0...8.2.0
8.1.0Febrero 2023link8.0.0...8.1.0
8.0.0Diciembre 2022link7.2.0...8.0.0
7.2.0Mayo 2022link7.1.0...7.2.0

Changelog completo

Emitter

El emitter Redis permite enviar paquetes a los clientes conectados desde otro proceso Node.js:

Diagrama de cómo funciona el emitter RedisDiagrama de cómo funciona el emitter Redis

Este emitter también está disponible en varios lenguajes:

Instalación

npm install @socket.io/redis-emitter redis

Uso

import { Emitter } from "@socket.io/redis-emitter";
import { createClient } from "redis";

const redisClient = createClient({ url: "redis://localhost:6379" });

redisClient.connect().then(() => {
const emitter = new Emitter(redisClient);

setInterval(() => {
emitter.emit("time", new Date);
}, 5000);
});

Nota: con redis@3, no es necesario llamar a connect() en el cliente Redis:

import { Emitter } from "@socket.io/redis-emitter";
import { createClient } from "redis";

const redisClient = createClient({ url: "redis://localhost:6379" });
const emitter = new Emitter(redisClient);

setInterval(() => {
emitter.emit("time", new Date);
}, 5000);

Por favor consulta la hoja de referencia aquí.

Migrando desde socket.io-emitter

El paquete fue renombrado de socket.io-emitter a @socket.io/redis-emitter en v4, para reflejar mejor la relación con Redis.

Para migrar al nuevo paquete, deberás asegurarte de proporcionar tus propios clientes Redis, ya que el paquete ya no creará clientes Redis en nombre del usuario.

Antes:

const io = require("socket.io-emitter")({ host: "127.0.0.1", port: 6379 });

Después:

const { Emitter } = require("@socket.io/redis-emitter");
const { createClient } = require("redis");

const redisClient = createClient();
const io = new Emitter(redisClient);

Últimas versiones

VersiónFecha de lanzamientoNotas de lanzamientoDiff
5.1.0Enero 2023link5.0.0...5.1.0
5.0.0Septiembre 2022link4.1.1...5.0.0
4.1.1Enero 2022link4.1.0...4.1.1
4.1.0Mayo 2021link4.0.0...4.1.0
4.0.0Marzo 2021link3.2.0...4.0.0

Changelog completo