JavaScript Avançado

O que Todo Dev Deve Saber sobre Redis com Node.js: Cache, Pub/Sub, Filas e Session Store

7 min de leitura

O que Todo Dev Deve Saber sobre Redis com Node.js: Cache, Pub/Sub, Filas e Session Store

Redis e Node.js: Fundamentos Essenciais Redis é um banco de dados em memória (in-memory data store) que se tornou essencial em arquiteturas modernas. Diferentemente de bancos tradicionais, Redis opera na RAM, oferecendo latência extremamente baixa—na ordem de milissegundos. Com Node.js, você integra Redis através da biblioteca (cliente oficial) ou (alternativa com recursos adicionais). Neste artigo, exploraremos os quatro pilares: caching, pub/sub, filas e session store. Antes de começar, instale as dependências necessárias: Cache com Redis O caching reduz requisições ao banco de dados, acelerando drasticamente sua aplicação. Redis armazena pares chave-valor simples ou estruturas complexas (hashes, listas, sets). Implementação Básica de Cache user:${id} user:${id} A função define tanto o valor quanto a expiração em uma única operação. Isso é fundamental para evitar que dados obsoletos permaneçam em cache indefinidamente. Use chaves estruturadas ( ) para organizar dados logicamente. Pub/Sub: Comunicação em Tempo Real Pub/Sub (Publish/Subscribe) permite que múltiplos clientes se inscrevam em canais e recebam mensagens em tempo real. É

<h2>Redis e Node.js: Fundamentos Essenciais</h2>

<p>Redis é um banco de dados em memória (in-memory data store) que se tornou essencial em arquiteturas modernas. Diferentemente de bancos tradicionais, Redis opera na RAM, oferecendo latência extremamente baixa—na ordem de milissegundos. Com Node.js, você integra Redis através da biblioteca <code>redis</code> (cliente oficial) ou <code>ioredis</code> (alternativa com recursos adicionais). Neste artigo, exploraremos os quatro pilares: caching, pub/sub, filas e session store.</p>

<p>Antes de começar, instale as dependências necessárias:</p>

<pre><code class="language-bash">npm install redis express express-session connect-redis uuid</code></pre>

<h2>Cache com Redis</h2>

<p>O caching reduz requisições ao banco de dados, acelerando drasticamente sua aplicação. Redis armazena pares chave-valor simples ou estruturas complexas (hashes, listas, sets).</p>

<h3>Implementação Básica de Cache</h3>

<pre><code class="language-javascript">const redis = require(&#039;redis&#039;);

const express = require(&#039;express&#039;);

const app = express();

const client = redis.createClient({

host: &#039;localhost&#039;,

port: 6379

});

client.connect();

// Simular consulta ao banco pesada

async function buscarUsuario(id) {

// Verificar se existe em cache

const cached = await client.get(user:${id});

if (cached) {

console.log(&#039;Cache hit&#039;);

return JSON.parse(cached);

}

// Simular query ao BD

const usuario = { id, nome: &#039;João Silva&#039;, email: &#039;joao@example.com&#039; };

// Armazenar no cache por 1 hora (3600 segundos)

await client.setEx(user:${id}, 3600, JSON.stringify(usuario));

console.log(&#039;Cache miss - dados armazenados&#039;);

return usuario;

}

app.get(&#039;/usuario/:id&#039;, async (req, res) =&gt; {

const usuario = await buscarUsuario(req.params.id);

res.json(usuario);

});</code></pre>

<p>A função <code>setEx</code> define tanto o valor quanto a expiração em uma única operação. Isso é fundamental para evitar que dados obsoletos permaneçam em cache indefinidamente. Use chaves estruturadas (<code>user:123</code>) para organizar dados logicamente.</p>

<h2>Pub/Sub: Comunicação em Tempo Real</h2>

<p>Pub/Sub (Publish/Subscribe) permite que múltiplos clientes se inscrevam em canais e recebam mensagens em tempo real. É ideal para notificações, atualizações ao vivo e coordenação entre serviços.</p>

<h3>Sistema de Notificações em Tempo Real</h3>

<pre><code class="language-javascript">const redis = require(&#039;redis&#039;);

// Subscriber (ouvinte)

async function iniciarSubscriber() {

const subscriber = redis.createClient();

await subscriber.connect();

subscriber.subscribe(&#039;notificacoes&#039;, (mensagem) =&gt; {

console.log(&#039;Notificação recebida:&#039;, mensagem);

});

}

// Publisher (emissor)

async function enviarNotificacao(texto) {

const publisher = redis.createClient();

await publisher.connect();

await publisher.publish(&#039;notificacoes&#039;, texto);

await publisher.quit();

}

// Em uma rota Express

app.post(&#039;/notificar&#039;, async (req, res) =&gt; {

await enviarNotificacao(Novo pedido recebido: ${req.body.pedidoId});

res.json({ sucesso: true });

});

iniciarSubscriber();</code></pre>

<p>Cada subscriber recebe apenas mensagens publicadas <strong>após</strong> sua inscrição. Para persistência, considere usar Redis Streams. Pub/Sub é perfeito para coordenar eventos entre microserviços ou notificar múltiplos clientes WebSocket simultaneamente.</p>

<h2>Filas com Redis</h2>

<p>Filas em Redis processam tarefas assincronamente, desacoplando produtores de consumidores. Use listas Redis (operações <code>LPUSH</code> e <code>RPOP</code>) para implementar padrões FIFO robustos.</p>

<h3>Fila de Processamento de Emails</h3>

<pre><code class="language-javascript">const redis = require(&#039;redis&#039;);

const client = redis.createClient();

client.connect();

// Produtor: adiciona tarefas à fila

async function adicionarEmailParaEnviar(para, assunto) {

const tarefa = JSON.stringify({ para, assunto, timestamp: Date.now() });

await client.lPush(&#039;fila:emails&#039;, tarefa);

console.log(&#039;Email adicionado à fila&#039;);

}

// Consumidor: processa emails

async function processarFilaEmails() {

while (true) {

// BRPOP bloqueia até haver item (timeout de 0 = espera indefinida)

const tarefa = await client.brPop(&#039;fila:emails&#039;, 0);

if (tarefa) {

const { para, assunto } = JSON.parse(tarefa.element);

console.log(Enviando email para ${para}: ${assunto});

// Chamar serviço de email real aqui

// Simular processamento

await new Promise(resolve =&gt; setTimeout(resolve, 1000));

}

}

}

// Em uma rota

app.post(&#039;/enviar-email&#039;, async (req, res) =&gt; {

await adicionarEmailParaEnviar(req.body.para, req.body.assunto);

res.json({ mensagem: &#039;Email enfileirado&#039; });

});

// Inicie o processador em background

processarFilaEmails().catch(console.error);</code></pre>

<p>Use <code>BRPOP</code> para esperar bloqueante em vez de polling contínuo. Isso economiza CPU e oferece latência previsível. Para cenários complexos (retry, dead letter queues), considere Bull, uma abstração que roda sobre Redis.</p>

<h2>Session Store: Persistência de Sessões</h2>

<p>Armazenar sessões em Redis permite compartilhá-las entre múltiplos servidores Node.js sem estado compartilhado. O middleware <code>connect-redis</code> integra seamlessly com Express.</p>

<h3>Configuração de Sessions com Redis</h3>

<pre><code class="language-javascript">const express = require(&#039;express&#039;);

const session = require(&#039;express-session&#039;);

const RedisStore = require(&#039;connect-redis&#039;).default;

const { createClient } = require(&#039;redis&#039;);

const app = express();

// Criar cliente Redis

const redisClient = createClient();

redisClient.connect();

// Configurar session store

app.use(session({

store: new RedisStore({ client: redisClient }),

secret: &#039;sua_chave_secreta_aqui&#039;,

resave: false,

saveUninitialized: false,

cookie: {

secure: false, // true em produção com HTTPS

httpOnly: true,

maxAge: 1000 60 60 * 24 // 24 horas

}

}));

// Usar sessão

app.get(&#039;/login&#039;, (req, res) =&gt; {

req.session.userId = 123;

req.session.username = &#039;joao_silva&#039;;

res.send(&#039;Sessão criada&#039;);

});

app.get(&#039;/perfil&#039;, (req, res) =&gt; {

if (req.session.userId) {

res.json({

mensagem: Bem-vindo, ${req.session.username},

userId: req.session.userId

});

} else {

res.status(401).send(&#039;Não autenticado&#039;);

}

});

app.get(&#039;/logout&#039;, (req, res) =&gt; {

req.session.destroy((err) =&gt; {

res.send(&#039;Sessão destruída&#039;);

});

});

app.listen(3000);</code></pre>

<p>Sessions em Redis são recuperáveis automaticamente ao reiniciar o servidor, diferente de memory store padrão. Cada sessão expira conforme <code>maxAge</code>, mantendo o Redis limpo. Em produção, use Redis com persistência (RDB ou AOF) para durabilidade máxima.</p>

<h2>Conclusão</h2>

<p>Redis com Node.js oferece quatro capacidades complementares: <strong>cache</strong> reduz latência em leituras repetidas, <strong>pub/sub</strong> coordena comunicação em tempo real entre componentes, <strong>filas</strong> desacoplam processamento assincronamente, e <strong>session store</strong> centraliza estado de usuários em arquiteturas distribuídas. Domine esses padrões e sua aplicação escalará horizontalmente sem gargalos. Comece com cache em endpoints lidos frequentemente, evoluindo para arquiteturas baseadas em eventos conforme sua aplicação cresce.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://github.com/redis/node-redis" target="_blank" rel="noopener noreferrer">Documentação Oficial Redis Node.js Client</a></li>

<li><a href="https://github.com/tj/connect-redis" target="_blank" rel="noopener noreferrer">Express Session com Redis</a></li>

<li><a href="https://redis.io/commands/" target="_blank" rel="noopener noreferrer">Redis Commands Reference</a></li>

<li><a href="https://github.com/OptimalBits/bull" target="_blank" rel="noopener noreferrer">Bull: Queue Library para Node.js</a></li>

<li><a href="https://www.manning.com/books/redis-in-action" target="_blank" rel="noopener noreferrer">Redis in Action - Josiah L. Carlson</a></li>

</ul>

Comentários

Mais em JavaScript Avançado

Guia Completo de Promises Internamente: Implementando uma Promise do Zero
Guia Completo de Promises Internamente: Implementando uma Promise do Zero

O Que é uma Promise e Por Que Implementar do Zero Uma Promise é um objeto Jav...

O que Todo Dev Deve Saber sobre Hooks Avançados em React: useReducer, useContext e useImperativeHandle
O que Todo Dev Deve Saber sobre Hooks Avançados em React: useReducer, useContext e useImperativeHandle

useReducer: Gerenciamento de Estado Complexo O é o hook ideal quando seu esta...

Guia Completo de Estratégias de Connection Pooling e Query Optimization em Node.js
Guia Completo de Estratégias de Connection Pooling e Query Optimization em Node.js

Connection Pooling em Node.js Connection pooling é uma técnica fundamental pa...