Redis para Azure: Guia Completo de Deploy
Introdução
Redis é uma daquelas ferramentas que, depois que você aprende a usar direito, passa a enxergar em praticamente todo sistema distribuído. Cache de sessão, fila de mensagens, rate limiting, ranking em tempo real: a lista de casos de uso é longa. Agora, quando você combina Redis com a infraestrutura da Azure, ganha algo que vai além de subir uma instância em uma VM qualquer. Você ganha um serviço gerenciado com replicação automática, failover transparente, integração nativa com Virtual Networks e monitoramento via Azure Monitor.
Neste guia, vou cobrir desde a criação do recurso até padrões de código em TypeScript que você pode levar direto para produção. O foco aqui é infraestrutura real: comandos CLI que funcionam, configuração que faz sentido e decisões de arquitetura que vão te poupar dor de cabeça às 3 da manhã.
Por Que Usar Redis na Azure
Vantagens do Azure Cache for Redis
O Azure Cache for Redis não é apenas um Redis hospedado. É um serviço PaaS que abstrai toda a complexidade operacional de manter um cluster Redis em produção. Você não precisa se preocupar com patching do sistema operacional, configuração de persistência em disco, ou orquestração de failover entre réplicas.
Existem três tiers disponíveis, cada um para um cenário diferente:
- Basic: instância única sem SLA. Serve para desenvolvimento e testes.
- Standard: duas réplicas com failover automático e SLA de 99,9%.
- Premium: suporte a clustering, persistência em disco (RDB), Virtual Network e georéplica.
- Enterprise: baseado no Redis Enterprise, com módulos como RediSearch, RedisJSON e RedisTimeSeries.
Casos de Uso Reais Onde Essa Combinação Brilha
Trabalho com Azure Cache for Redis há anos e os cenários onde ele se prova indispensável são consistentes. Em aplicações de e-commerce, usamos Redis para cache de catálogo de produtos e gerenciamento de sessões de carrinho de compras. Em plataformas SaaS multi-tenant, ele atua como camada de rate limiting por tenant (tema que já exploramos no post sobre Rate Limiting Inteligente com Redis e Node.js). Em sistemas de mensageria, Redis Streams substituem soluções mais pesadas quando a latência precisa ser mínima. E em dashboards de analytics, sorted sets permitem rankings e leaderboards em tempo real com complexidade O(log N).
Setup do Azure Cache for Redis com CLI
Criando o Recurso via Azure CLI
Antes de qualquer código, vamos subir a infraestrutura. Prefiro sempre usar a CLI em vez do portal: é reproduzível, versionável e pode entrar em um pipeline de CI/CD.
// Esses são os comandos Azure CLI que você executaria no terminal.
// Estou documentando aqui para referência.
// 1. Criar o resource group
// az group create --name rg-redis-producao --location brazilsouth
// 2. Criar a instância Redis (Standard C1 com 1GB)
// az redis create \
// --name redis-vivocodigo-prod \
// --resource-group rg-redis-producao \
// --location brazilsouth \
// --sku Standard \
// --vm-size c1 \
// --enable-non-ssl-port false \
// --minimum-tls-version 1.2
// 3. Obter a connection string
// az redis list-keys \
// --name redis-vivocodigo-prod \
// --resource-group rg-redis-producaoAlguns pontos importantes sobre essa configuração. Desabilitar a porta não-SSL é obrigatório em produção. Forçar TLS 1.2 como mínimo elimina vulnerabilidades conhecidas em versões anteriores. E escolher a região brazilsouth reduz a latência para usuários no Brasil.
Configuração de Rede com Private Endpoint
Em ambientes corporativos, expor o Redis na internet pública é inaceitável. O caminho correto é usar Private Endpoints:
az network private-endpoint create \
--name pe-redis-prod \
--resource-group rg-redis-producao \
--vnet-name vnet-producao \
--subnet subnet-dados \
--private-connection-resource-id $(az redis show \
--name redis-vivocodigo-prod \
--resource-group rg-redis-producao \
--query id -o tsv) \
--group-id redisCache \
--connection-name redis-private-connectionCom isso, o tráfego entre sua aplicação e o Redis nunca sai da rede privada da Azure.
Exemplo Prático: Cache de API com TypeScript
Conectando ao Azure Cache for Redis com ioredis
Vamos ao código. O primeiro exemplo implementa um padrão de cache-aside para respostas de API. Essa é provavelmente a integração mais comum que você vai precisar:
import Redis from "ioredis";
interface CacheConfig {
host: string;
port: number;
password: string;
tls: boolean;
keyPrefix: string;
defaultTTL: number;
}
interface CachedResponse<T> {
data: T;
cachedAt: string;
source: "cache" | "origin";
}
class AzureRedisCache {
private client: Redis;
private defaultTTL: number;
constructor(config: CacheConfig) {
this.defaultTTL = config.defaultTTL;
this.client = new Redis({
host: config.host,
port: config.port,
password: config.password,
tls: config.tls ? { rejectUnauthorized: true } : undefined,
keyPrefix: config.keyPrefix,
retryStrategy(times: number): number | null {
if (times > 3) {
console.error(
`Redis: falha após ${times} tentativas. Desistindo.`
);
return null;
}
const delay = Math.min(times * 200, 2000);
console.warn(`Redis: reconectando em ${delay}ms (tentativa ${times})`);
return delay;
},
maxRetriesPerRequest: 3,
enableReadyCheck: true,
lazyConnect: true,
});
this.client.on("error", (err) => {
console.error("Redis connection error:", err.message);
});
this.client.on("ready", () => {
console.log("Redis: conexão estabelecida com sucesso");
});
}
async connect(): Promise<void> {
await this.client.connect();
}
async getOrFetch<T>(
key: string,
fetcher: () => Promise<T>,
ttlSeconds?: number
): Promise<CachedResponse<T>> {
const ttl = ttlSeconds ?? this.defaultTTL;
try {
const cached = await this.client.get(key);
if (cached !== null) {
const parsed = JSON.parse(cached) as { data: T; cachedAt: string };
return { ...parsed, source: "cache" };
}
} catch (err) {
console.warn(`Redis GET falhou para key=${key}:`, err);
// Em caso de falha no cache, seguimos para o fetcher.
// O sistema continua funcionando, apenas sem cache.
}
const data = await fetcher();
const cachedAt = new Date().toISOString();
try {
const payload = JSON.stringify({ data, cachedAt });
await this.client.set(key, payload, "EX", ttl);
} catch (err) {
console.warn(`Redis SET falhou para key=${key}:`, err);
}
return { data, cachedAt, source: "origin" };
}
async invalidate(pattern: string): Promise<number> {
const keys = await this.client.keys(pattern);
if (keys.length === 0) return 0;
// Remove o prefixo porque keys() retorna com prefixo,
// mas del() adiciona o prefixo novamente
const pipeline = this.client.pipeline();
for (const key of keys) {
pipeline.del(key.replace(this.client.options.keyPrefix ?? "", ""));
}
await pipeline.exec();
return keys.length;
}
async disconnect(): Promise<void> {
await this.client.quit();
}
}
// Uso em uma aplicação real
const cache = new AzureRedisCache({
host: "redis-vivocodigo-prod.redis.cache.windows.net",
port: 6380,
password: process.env.REDIS_PRIMARY_KEY!,
tls: true,
keyPrefix: "api:v1:",
defaultTTL: 300,
});
async function handleProductRequest(productId: string) {
await cache.connect();
const result = await cache.getOrFetch(
`product:${productId}`,
async () => {
// Simulando chamada ao banco de dados
const response = await fetch(
`https://api.internal/products/${productId}`
);
return response.json();
},
600 // Cache de 10 minutos para produtos
);
console.log(`Produto retornado via ${result.source}`);
return result;
}O detalhe mais importante desse código é a estratégia de fallback. Quando o Redis falha (e em produção, ele vai falhar eventualmente), a aplicação continua funcionando. O cache nunca deve ser um ponto único de falha.
Exemplo Prático: Sessões Distribuídas com Express
Gerenciamento de Sessão em Cluster
O segundo exemplo resolve um problema clássico de aplicações distribuídas: sessões compartilhadas entre múltiplas instâncias.
import express from "express";
import session from "express-session";
import RedisStore from "connect-redis";
import Redis from "ioredis";
function createSessionMiddleware(): express.RequestHandler {
const redisClient = new Redis({
host: "redis-vivocodigo-prod.redis.cache.windows.net",
port: 6380,
password: process.env.REDIS_PRIMARY_KEY!,
tls: { rejectUnauthorized: true },
retryStrategy(times: number): number | null {
if (times > 5) return null;
return Math.min(times * 300, 3000);
},
db: 1, // Usar database separada para sessões
});
redisClient.on("error", (err) => {
console.error("Redis Session Store error:", err.message);
});
const store = new RedisStore({
client: redisClient,
prefix: "sess:",
ttl: 86400, // 24 horas em segundos
disableTouch: false, // Renovar TTL a cada acesso
});
return session({
store,
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
name: "sid",
cookie: {
secure: true,
httpOnly: true,
maxAge: 86400000, // 24 horas em milissegundos
sameSite: "strict",
},
});
}
const app = express();
app.use(createSessionMiddleware());
app.post("/api/login", async (req, res) => {
// Após autenticação bem-sucedida
req.session.userId = "user-123";
req.session.tenant = "empresa-abc";
req.session.roles = ["admin", "editor"];
res.json({ message: "Login realizado com sucesso" });
});
app.get("/api/profile", (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ error: "Não autenticado" });
}
res.json({
userId: req.session.userId,
tenant: req.session.tenant,
roles: req.session.roles,
});
});
app.listen(3000, () => {
console.log("Servidor rodando na porta 3000");
});Usar db: 1 para sessões é uma prática que recomendo fortemente. Separar sessões do cache de API permite que você faça FLUSHDB no database de cache sem destruir as sessões dos seus usuários.
Boas Práticas para Redis na Azure em Produção
Configuração e Sizing
Escolher o tamanho correto da instância é mais arte do que ciência, mas existem regras confiáveis. Comece monitorando a métrica usedmemory no Azure Monitor. Se ela ultrapassar 80% de forma consistente, é hora de escalar. Para o tier Premium com clustering, distribua os dados em pelo menos 3 shards para balancear a carga de forma adequada.
Segurança
Nunca, em hipótese alguma, exponha seu Redis na internet pública. Use Private Endpoints conforme demonstrado acima. Rotacione as chaves de acesso periodicamente com o comando:
az redis regenerate-keys \
--name redis-vivocodigo-prod \
--resource-group rg-redis-producao \
--key-type PrimaryConsidere usar Managed Identity em vez de connection strings quando possível. Isso elimina o risco de credenciais vazadas em repositórios de código.
Monitoramento e Alertas
Configure alertas no Azure Monitor para as métricas que realmente importam: Server Load acima de 70%, Cache Misses em tendência de alta, Connected Clients próximo do limite e Used Memory RSS acima de 80%. Um dashboard com essas quatro métricas já cobre 90% dos problemas que você vai encontrar.
Padrões de Resiliência
Implemente circuit breaker na camada de cache. Se o Redis ficar indisponível, sua aplicação deve degradar graciosamente e buscar os dados direto da origem. O exemplo de código do getOrFetch acima já implementa esse padrão com os blocos try/catch.
Use TTLs sempre. Dados sem expiração são o caminho mais rápido para um OOM (Out of Memory) em produção. Mesmo para dados que "nunca mudam", defina um TTL generoso de 24 horas como salvaguarda.
Serialização e Chaves
Padronize o formato das suas chaves usando separadores com dois pontos, como api:v1:product:123. Isso facilita a inspeção manual, permite invalidação por padrão com KEYS ou SCAN, e mantém o Redis organizado quando você tem centenas de milhares de chaves.
Para serialização, JSON funciona bem na maioria dos casos. Se a performance de serialização se tornar um gargalo (algo raro, mas possível com payloads grandes), considere MessagePack como alternativa.
Conclusão
Redis na Azure é uma combinação que funciona muito bem quando configurada com cuidado. O Azure Cache for Redis elimina a carga operacional de manter a infraestrutura, enquanto você se concentra em escrever código que resolve problemas de negócio.
Os pontos que mais importam para levar daqui: use sempre TLS e Private Endpoints, implemente fallbacks para quando o cache falhar, separe databases por domínio (cache, sessões, filas) e monitore as métricas certas. Com esses fundamentos no lugar, você tem uma camada de cache que aguenta produção de verdade.
Guias Relacionados
Explore mais guias técnicos
Mais de 100 guias práticos de integração entre frameworks, ferramentas e plataformas.
Ver todos os guias