Node.js com Redis
Node.js e Redis são uma combinação natural. Esta lição aborda o uso do Redis com Node.js.
Clientes Redis para Node.js
Clientes Redis Node.js mais utilizados:
- ioredis: rico em recursos, suporta cluster, sentinel, scripts Lua
- redis (node-redis): cliente oficial, simples de usar
- redis (v3): versão mais antiga, amplamente usada
💡 Recomendação: Novos projetos devem usar ioredis ou node-redis v4+.
ioredis
Instalação
BASH
npm install ioredis
Conexão Básica
JAVASCRIPT
const Redis = require('ioredis');
// Conectar ao Redis
const redis = new Redis({
host: 'localhost',
port: 6379,
// password: 'sua_senha',
db: 0
});
// Testar conexão
redis.ping().then(result => {
console.log(result); // 'PONG'
});
Operações de String
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
// SET e GET
async function stringDemo() {
// SET
await redis.set('nome', 'Alice');
// GET
const nome = await redis.get('nome');
console.log(nome); // 'Alice'
// SET com expiração
await redis.set('session', 'dados', 'EX', 3600); // Expira após 1 hora
// MSET e MGET
await redis.mset('key1', 'valor1', 'key2', 'valor2');
const values = await redis.mget('key1', 'key2');
console.log(values); // ['valor1', 'valor2']
// INCR
await redis.set('counter', 0);
const count = await redis.incr('counter');
console.log(count); // 1
// DEL
await redis.del('nome');
}
stringDemo();
Operações de Hash
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function hashDemo() {
// HSET e HGET
await redis.hset('user:1', 'name', 'Alice');
await redis.hset('user:1', 'age', 25);
const name = await redis.hget('user:1', 'name');
console.log(name); // 'Alice'
// HMSET
await redis.hmset('user:2', {
name: 'Bob',
age: 30,
city: 'Beijing'
});
// HGETALL
const user = await redis.hgetall('user:2');
console.log(user); // { name: 'Bob', age: '30', city: 'Beijing' }
// HKEYS e HVALS
const keys = await redis.hkeys('user:2');
const values = await redis.hvals('user:2');
// HDEL
await redis.hdel('user:2', 'city');
// HINCRBY
await redis.hincrby('user:2', 'age', 1);
}
hashDemo();
Operações de Lista
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function listDemo() {
// LPUSH e RPUSH
await redis.lpush('mylist', 'valor1', 'valor2');
await redis.rpush('mylist', 'valor3');
// LRANGE
const list = await redis.lrange('mylist', 0, -1);
console.log(list); // ['valor2', 'valor1', 'valor3']
// LPOP e RPOP
const left = await redis.lpop('mylist');
const right = await redis.rpop('mylist');
// LLEN
const length = await redis.llen('mylist');
}
listDemo();
Operações de Conjunto
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function setDemo() {
// SADD
await redis.sadd('myset', 'a', 'b', 'c');
// SMEMBERS
const members = await redis.smembers('myset');
console.log(members); // Set { 'a', 'b', 'c' }
// SISMEMBER
const exists = await redis.sismember('myset', 'a');
console.log(exists); // 1 (true)
// SREM
await redis.srem('myset', 'a');
// SINTER, SUNION, SDIFF
await redis.sadd('set1', 'a', 'b', 'c');
await redis.sadd('set2', 'b', 'c', 'd');
const inter = await redis.sinter('set1', 'set2');
console.log(inter); // Set { 'b', 'c' }
}
setDemo();
Operações de Conjunto Ordenado
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function zsetDemo() {
// ZADD
await redis.zadd('leaderboard', 100, 'player1', 200, 'player2', 150, 'player3');
// ZRANGE
const top = await redis.zrange('leaderboard', 0, -1, 'WITHSCORES');
console.log(top); // ['player1', '100', 'player3', '150', 'player2', '200']
// ZREVRANGE (maior para menor)
const topDesc = await redis.zrevrange('leaderboard', 0, 2, 'WITHSCORES');
// ZSCORE
const score = await redis.zscore('leaderboard', 'player1');
console.log(score); // '100'
// ZINCRBY
await redis.zincrby('leaderboard', 50, 'player1');
// ZREM
await redis.zrem('leaderboard', 'player1');
}
zsetDemo();
Pub/Sub
JAVASCRIPT
const Redis = require('ioredis');
// Assinante
const subscriber = new Redis();
subscriber.subscribe('news', 'sports');
subscriber.on('message', (channel, message) => {
console.log(`Canal: ${channel}, Mensagem: ${message}`);
});
// Publicador
const publisher = new Redis();
setInterval(() => {
publisher.publish('news', `Mensagem de notícias ${Date.now()}`);
}, 1000);
Pipelining
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function pipelineDemo() {
const pipeline = redis.pipeline();
pipeline.set('key1', 'value1');
pipeline.set('key2', 'value2');
pipeline.set('key3', 'value3');
pipeline.get('key1');
const results = await pipeline.exec();
console.log(results);
// [ [ null, 'OK' ], [ null, 'OK' ], [ null, 'OK' ], [ null, 'value1' ] ]
}
pipelineDemo();
Transações
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function transactionDemo() {
const multi = redis.multi();
multi.set('key1', 'value1');
multi.set('key2', 'value2');
multi.incr('counter');
const results = await multi.exec();
console.log(results);
}
transactionDemo();
Gerenciamento de Conexão
ioredis tem pool de conexão integrado — nenhuma configuração extra é necessária:
JAVASCRIPT
const Redis = require('ioredis');
// Conexão única (pool automático)
const redis = new Redis({
host: 'localhost',
port: 6379,
maxRetriesPerRequest: 3,
enableReadyCheck: true
});
// Modo cluster
const cluster = new Redis.Cluster([
{ host: '127.0.0.1', port: 7000 },
{ host: '127.0.0.1', port: 7001 },
{ host: '127.0.0.1', port: 7002 }
]);
node-redis (Cliente Oficial)
Instalação
BASH
npm install redis
Uso Básico
JAVASCRIPT
const { createClient } = require('redis');
async function main() {
// Criar cliente
const client = createClient({
url: 'redis://localhost:6379'
});
// Conectar
await client.connect();
// SET e GET
await client.set('key', 'valor');
const value = await client.get('key');
console.log(value); // 'valor'
// Operações de hash
await client.hSet('user:1', 'name', 'Alice');
const name = await client.hGet('user:1', 'name');
// Operações de lista
await client.lPush('mylist', 'valor1');
const list = await client.lRange('mylist', 0, -1);
// Operações de conjunto
await client.sAdd('myset', 'a', 'b', 'c');
const members = await client.sMembers('myset');
// Fechar conexão
await client.quit();
}
main();
Pub/Sub
JAVASCRIPT
const { createClient } = require('redis');
async function pubsub() {
const subscriber = createClient();
await subscriber.connect();
// Assinar
await subscriber.subscribe('news', (message) => {
console.log(`Recebido: ${message}`);
});
const publisher = createClient();
await publisher.connect();
// Publicar
await publisher.publish('news', 'Olá Mundo');
}
pubsub();
Exemplos Práticos
Exemplo 1: Decorador de Cache
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
function cache(expire = 3600) {
return function(target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function(...args) {
const cacheKey = `${propertyKey}:${JSON.stringify(args)}`;
// Tentar obter do cache
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// Executar método original
const result = await originalMethod.apply(this, args);
// Armazenar em cache
await redis.set(cacheKey, JSON.stringify(result), 'EX', expire);
return result;
};
return descriptor;
};
}
class UserService {
@cache(300)
async getUser(userId) {
console.log(`Consultando banco de dados: userId=${userId}`);
return { id: userId, name: `User${userId}` };
}
}
Exemplo 2: Lock Distribuído
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
const { v4: uuidv4 } = require('uuid');
class DistributedLock {
constructor(key, expire = 10) {
this.key = `lock:${key}`;
this.expire = expire;
this.identifier = uuidv4();
}
async acquire() {
const result = await redis.set(
this.key,
this.identifier,
'NX',
'EX',
this.expire
);
return result === 'OK';
}
async release() {
const script = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`;
const result = await redis.eval(script, 1, this.key, this.identifier);
return result === 1;
}
}
// Usando o lock
async function withLock(key, callback) {
const lock = new DistributedLock(key);
try {
while (!(await lock.acquire())) {
await new Promise(resolve => setTimeout(resolve, 100));
}
return await callback();
} finally {
await lock.release();
}
}
// Exemplo
await withLock('resource', async () => {
console.log('Executando lógica de negócio');
});
Exemplo 3: Limitador de Taxa
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
async function rateLimit(key, limit = 10, period = 60) {
const current = Math.floor(Date.now() / 1000);
const windowStart = current - period;
const results = await redis
.multi()
.zremrangebyscore(key, 0, windowStart)
.zcard(key)
.zadd(key, current, `${current}`)
.expire(key, period)
.exec();
const count = results[1][1];
return count < limit;
}
// Usando o limitador de taxa
async function apiHandler(userId) {
const allowed = await rateLimit(`api:${userId}`, 10, 60);
if (allowed) {
console.log('Requisição permitida');
return { success: true };
} else {
console.log('Requisição negada');
return { success: false, error: 'Limite de taxa excedido' };
}
}
Exemplo 4: Fila de Mensagens
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
class MessageQueue {
constructor(name) {
this.name = `queue:${name}`;
}
async push(message) {
await redis.rpush(this.name, JSON.stringify(message));
}
async pop(timeout = 0) {
const result = await redis.blpop(this.name, timeout);
if (result) {
return JSON.parse(result[1]);
}
return null;
}
async size() {
return await redis.llen(this.name);
}
}
// Produtor
const queue = new MessageQueue('tasks');
await queue.push({ task: 'send_email', to: 'user@example.com' });
// Consumidor
while (true) {
const task = await queue.pop(5);
if (task) {
console.log('Processando tarefa:', task);
} else {
break;
}
}
Tratamento de Erros
JAVASCRIPT
const Redis = require('ioredis');
const redis = new Redis();
redis.on('error', (error) => {
console.error('Erro Redis:', error);
});
redis.on('connect', () => {
console.log('Redis conectado');
});
redis.on('ready', () => {
console.log('Redis pronto');
});
redis.on('close', () => {
console.log('Conexão Redis fechada');
});
❓ Perguntas Frequentes
P Como escolher entre ioredis e node-redis?
R ioredis tem mais recursos (cluster, sentinel). node-redis é o cliente oficial. ioredis é recomendado.
P ioredis é thread-safe?
R Sim. ioredis tem pool de conexão integrado e pode ser compartilhado entre módulos.
P Como lidar com desconexões?
R ioredis reconecta automaticamente. Você pode ouvir eventos de error e connect.
P Como funcionam as operações assíncronas?
R Todas as operações ioredis retornam Promises. Use async/await ou .then().
P Como implemento pool de conexão?
R ioredis tem pool de conexão integrado — nenhuma configuração extra é necessária.
📖 Resumo
- ioredis: rico em recursos, suporta cluster, sentinel, scripts Lua
- node-redis: cliente oficial, simples de usar
- Todas as operações são assíncronas, retornando Promises
- Suporta pipelining, transações, pub/sub
- Pool de conexão integrado e reconexão automática
- Exemplos práticos: cache, locks distribuídos, limitação de taxa, filas de mensagens
📝 Atividades
- Operações básicas: Use ioredis para operações de string, hash e lista
- Pipeline: Use pipelining para definir 1000 chaves em lote, compare o desempenho
- Pub/Sub: Implemente um sistema simples de mensagens pub/sub
- Prático: Implemente um lock distribuído simples ou limitador de taxa
Parabéns!
Você completou todas as 26 lições do tutorial Redis! Próximos passos:
- Pratique: aplique Redis em projetos reais
- Aprofunde: aprenda sobre cluster Redis, sentinel, scripts Lua
- Otimize: aprenda otimização de desempenho Redis e melhores práticas



