Dominando GET e SET no Redis: Operações Básicas de Dados
Domine os fundamentos do gerenciamento de dados no Redis com este guia abrangente sobre os comandos `GET` e `SET`. Aprenda armazenamento e recuperação básicos de strings, e explore opções avançadas essenciais como definição atômica (`NX`/`XX`) e expiração integrada de chaves (`EX`/`PX`). Descubra como esses comandos fundamentais são cruciais para construir camadas de cache de alto desempenho.
Dominando GET e SET no Redis: Operações Básicas de Dados
Os comandos GET e SET do Redis parecem quase simples demais. Escreva um valor. Leia um valor. Em aplicações reais, esses dois comandos estão por trás de sessões de login, flags de funcionalidades, limites de taxa, entradas de cache, locks de curta duração e atalhos do tipo "por favor, não consulte o banco de dados novamente".
Os detalhes importam porque o Redis faz exatamente o que você pede. Se você sobrescrever uma chave acidentalmente, ele não perguntará se você teve a intenção. Se você esquecer uma expiração em dados de cache, eles podem viver mais que a fonte de dados. Se você tratar uma chave ausente da mesma forma que uma string vazia, sua aplicação pode tomar a decisão errada.
O Modelo Chave-Valor do Redis
Antes de mergulhar nos comandos, é importante lembrar que o Redis opera em um modelo simples de armazenamento chave-valor. Cada dado (o valor) é acessado usando um identificador único (a chave). As chaves são strings, e os valores podem ser de vários tipos de dados (strings, listas, conjuntos, hashes, etc.). SET e GET lidam principalmente com o tipo de dado String, que é o tipo mais básico e frequentemente usado no Redis.
1. Definindo Dados: O Comando SET
O comando SET é usado para atribuir um valor a uma chave. Se a chave já contém dados, o comando SET sobrescreverá o valor existente. Sua sintaxe básica é direta.
Sintaxe Básica e Uso
A forma mais simples requer apenas a chave e o valor:
SET chave valor
Exemplo: armazenando o nome de exibição de um usuário:
127.0.0.1:6379> SET usuario:100:nome "Alice Johnson"
OK
127.0.0.1:6379> GET usuario:100:nome
"Alice Johnson"
Opções Avançadas do SET: NX, XX e Expiração
O poder do SET vem de seus argumentos opcionais, que permitem definição condicional atômica e gerenciamento de tempo de vida (TTL). Essas opções são vitais para implementar locks e caches corretamente.
Definição Condicional: NX e XX
Essas opções controlam quando uma operação de definição ocorre, prevenindo sobrescritas acidentais ou garantindo que uma sobrescrita aconteça apenas se a chave existir.
NX(Não Existe): Só define a chave se ela não existir. Isso é útil para operações "criar apenas" e padrões simples de lock.SET minha_chave_lock algum_valor_unico NXXX(Existe): Só define a chave se ela já existir. Isso é útil quando você quer atualizar uma chave conhecida sem criar uma nova por engano.SET sessao:token:456 novo_valor XX
B. Definindo Tempo de Expiração (TTL)
Para gerenciar memória e implementar cache baseado em tempo, você pode definir um tempo de expiração diretamente dentro do comando SET. Isso é muito mais eficiente do que definir a chave e depois chamar EXPIRE separadamente.
EX segundos: Define o tempo de expiração em segundos.PX milissegundos: Define o tempo de expiração em milissegundos.EXAT timestamp: Define a expiração para um timestamp Unix específico (segundos).PXAT timestamp: Define a expiração para um timestamp Unix específico (milissegundos).
Exemplo: definindo uma chave para expirar em uma hora:
127.0.0.1:6379> SET cache:produto:500 "Detalhes do Produto" EX 3600
OK
127.0.0.1:6379> TTL cache:produto:500
(integer) 3598
Use SET chave valor EX N ou PX N para entradas de cache. Isso torna a escrita e a expiração parte de um único comando, o que evita o bug comum onde a aplicação escreve uma chave de cache e falha antes de chamar EXPIRE.
Combinando Opções
Todas as opções podem frequentemente ser combinadas para operações atômicas complexas:
# Define a chave apenas se ela não existir, e faz ela expirar em 60 segundos
SET minha_configuracao "ativo" NX EX 60
2. Recuperando Dados: O Comando GET
O comando GET recupera o valor string associado a uma determinada chave. É uma das operações mais rápidas que o Redis realiza, muitas vezes completando em microssegundos.
Sintaxe Básica e Uso
GET chave
Exemplo: Recuperando o nome de usuário armazenado
127.0.0.1:6379> GET usuario:100:nome
"Alice Johnson"
Lidando com Chaves Inexistentes
Se a chave não existir, GET retorna uma resposta especial indicando que nada foi encontrado:
127.0.0.1:6379> GET chave_inexistente
(nil)
No código da aplicação, receber (nil) é a maneira padrão de determinar que o dado está faltando, geralmente acionando uma falha de cache onde a aplicação deve buscar os dados da fonte primária (como um banco de dados) e subsequentemente escrevê-los de volta no Redis.
Obtendo um Valor Enquanto Altera a Expiração: GETEX
O comando GET básico retorna apenas o valor. Ele não retorna o TTL restante. Se você precisar do TTL, use TTL chave ou PTTL chave como um comando separado.
GETEX é diferente: ele retorna o valor e altera a expiração da chave ao mesmo tempo. Isso é útil para comportamento de sessão deslizante, onde cada leitura estende o tempo de vida da sessão.
GETEX sessao:abc123 EX 1800
Isso lê o valor da sessão e redefine a expiração para 30 minutos. Não use isso casualmente para leituras normais de cache, porque cada leitura se torna uma operação do tipo escrita que altera os metadados da chave.
3. Aplicação Prática: Cache com GET e SET
O caso de uso fundamental para GET e SET é implementar um padrão simples de cache-aside.
Passos na lógica da aplicação:
- Tentar
GET produto:500. - Se o Redis retornar um valor, decodifique-o e retorne-o.
- Se o Redis retornar nil, busque o produto do banco de dados primário.
- Armazene o resultado serializado com
SET produto:500 <json> EX 300. - Retorne o resultado para o chamador.
Este padrão pode reduzir a carga do banco de dados, mas também cria uma janela de dados obsoletos. Se o produto mudar no banco de dados, o Redis pode continuar servindo o valor antigo até que o TTL expire ou sua aplicação invalide a chave. Escolha TTLs com base em quão errado os dados podem estar, não apenas em quanto tráfego você quer economizar.
Nomeando Chaves Sem Criar uma Bagunça
O Redis não exige uma convenção de nomenclatura, mas seu eu do futuro exigirá. Um padrão legível como usuario:100:nome, produto:500:sumario, ou taxa:usuario:100:login torna a depuração com redis-cli muito mais fácil.
Mantenha as chaves claras e razoavelmente curtas. Economizar alguns bytes nomeando uma chave como u:100:n raramente vale a confusão, a menos que você esteja operando em uma escala muito grande e tenha medido a sobrecarga das chaves. Para a maioria das equipes, consistência importa mais do que brevidade extrema.
Cuidado com valores fornecidos pelo usuário nas chaves. Se um endereço de e-mail, URL ou nome de locatário se tornar parte da chave, normalize-o primeiro. Caso contrário, pequenas diferenças de formatação podem criar entradas de cache duplicadas:
[email protected]
[email protected]
[email protected]
Todos esses podem representar o mesmo usuário para sua aplicação, mas chaves diferentes para o Redis.
Sobrescritas, Valores Vazios e Nil
SET sobrescreve por padrão:
SET config:modo "seguro"
SET config:modo "rapido"
GET config:modo
O valor final é "rapido". Se a sobrescrita for perigosa, use NX ou XX.
Também distinga uma chave ausente de um valor vazio. Nil no Redis significa que a chave está faltando. Uma string vazia é um valor armazenado real:
SET usuario:100:apelido ""
GET usuario:100:apelido
Sua biblioteca cliente pode representar esses de forma diferente: null, None, nil, uma string de bytes vazia ou uma string vazia. Verifique o comportamento do cliente em vez de adivinhar.
Padrão de Lock Seguro, Com Um Aviso
Você verá frequentemente este padrão:
SET lock:fatura:123 "trabalhador-7:1700000000" NX EX 30
Isso significa "crie este lock apenas se ele não existir, e expire-o após 30 segundos." A expiração não é opcional. Sem ela, um trabalhador que falhou pode deixar um lock para trás para sempre.
Para configurações simples de instância única do Redis, este padrão é muitas vezes suficiente para coordenação de baixo risco. Para locking distribuído crítico em falhas, deriva de clock e múltiplos nós Redis, use uma biblioteca bem revisada e entenda suas compensações. Um bug de lock pode se tornar um bug de corrupção de dados.
Depurando com redis-cli
Quando um caminho de GET ou SET se comporta de forma estranha, verifique a chave diretamente:
redis-cli GET produto:500
redis-cli TTL produto:500
redis-cli TYPE produto:500
TYPE é útil porque GET só funciona em valores string. Se a chave contém um hash, lista, conjunto ou conjunto ordenado, o Redis retorna um erro de tipo incorreto. Isso geralmente significa que duas partes da aplicação estão usando o mesmo nome de chave para propósitos diferentes.
Se você precisar inspecionar várias chaves relacionadas durante o desenvolvimento, SCAN é mais seguro que KEYS em um servidor de produção ocupado:
redis-cli SCAN 0 MATCH 'produto:500:*' COUNT 100
KEYS * pode bloquear o Redis enquanto ele escaneia o espaço de chaves. Tudo bem em uma instância local minúscula. É um mau hábito em produção.
Escolhendo TTLs em Sistemas Reais
A escolha do TTL é uma decisão de produto e operações, não um truque do Redis. Um cache de perfil de usuário pode tolerar cinco minutos de desatualização. Uma verificação de permissão pode precisar de um TTL muito mais curto ou invalidação explícita. Uma flag de funcionalidade pode precisar de atualizações quase imediatas se controla uma implantação arriscada.
Aqui estão três padrões comuns:
SET cache:produto:500 "<json>" EX 300
SET sessao:abc123 "<json>" EX 1800
SET taxa:usuario:100:login "1" EX 60 NX
O cache do produto pode ficar um pouco desatualizado. A sessão tem um tempo de vida claro. A chave de limite de taxa usa NX para que a primeira tentativa crie a janela e tentativas posteriores possam incrementar ou verificar chaves relacionadas dependendo do design.
Evite chaves de "cache para sempre" a menos que você tenha um caminho de invalidação claro. Um cache para sempre eventualmente se torna um segundo banco de dados, geralmente sem a disciplina operacional que você aplica ao banco de dados real.
Detalhes de Serialização
As strings do Redis são binary-safe. Elas podem conter JSON, MessagePack, dados compactados, contadores ou texto simples. O comando não se importa. Sua aplicação sim.
JSON é fácil de inspecionar:
SET produto:500 "{\"id\":500,\"name\":\"Lâmpada de Mesa\"}" EX 300
Formatos binários podem economizar espaço ou CPU em algumas aplicações, mas tornam a depuração no terminal mais difícil. A compressão pode ajudar para dados grandes repetidos, mas também adiciona custo de CPU e pode esconder o fato de que você está armazenando em cache objetos muito grandes.
Para contadores, não leia com GET, adicione na aplicação e escreva com SET se vários clientes podem atualizar a mesma chave. Use comandos de contador atômicos do Redis:
INCR pagina:visualizacao:500
EXPIRE pagina:visualizacao:500 86400
Para contadores com primeira escrita e expiração, use uma transação ou um pequeno script Lua se precisar de comportamento estrito. Caso contrário, seja claro sobre a condição de corrida que você está aceitando.
Evitando Colisões de Chaves
Duas equipes usando o mesmo banco de dados Redis podem acidentalmente reutilizar uma chave como usuario:100. Uma equipe armazena JSON com SET; outra armazena campos com HSET. O próximo GET retorna um erro de tipo incorreto, e ambas as equipes perdem tempo.
Namespaces ajudam:
loja:prod:usuario:100:perfil
loja:prod:sessao:abc123
faturamento:prod:fatura:9001
Você não precisa de chaves dolorosamente longas, mas inclua contexto suficiente para evitar colisões entre ambientes, serviços e tipos de dados. Se você compartilha o Redis entre aplicações, uma convenção de nomenclatura faz parte da interface.
Quando Não Usar GET e SET
Strings são o ponto de partida, não o modelo inteiro do Redis. Se você atualiza frequentemente um campo dentro de um blob JSON maior, um hash pode ser mais limpo:
HSET usuario:100 nome "Alice Johnson" email "[email protected]"
HGET usuario:100 email
Se você precisa de eventos ordenados, use streams ou listas. Se você precisa de verificações de associação, use conjuntos. Se você precisa de classificação, use conjuntos ordenados. Reescrever uma string serializada inteira para cada pequena mudança é simples no início, mas pode se tornar caro e complicado à medida que o objeto cresce.
Uma Pequena Lista de Verificação Antes de Publicar
Antes de publicar um novo caminho de GET e SET, faça algumas perguntas simples.
- Qual é o nome exato da chave?
- Dois serviços podem usar acidentalmente a mesma chave?
- A chave deve expirar?
- O que acontece quando o Redis retorna nil?
- A sobrescrita é aceitável, ou a escrita deve usar
NXouXX? - O valor é pequeno o suficiente para ser lido e escrito como uma única string?
- Você pode depurar o valor a partir do
redis-clise o comportamento em produção parecer errado?
Essas perguntas pegam a maioria dos erros básicos de string do Redis antes que eles se tornem incidentes. A sintaxe do comando é fácil. O ciclo de vida em torno da chave é onde os bugs geralmente se escondem.
GET e SET são comandos pequenos com muito peso operacional. Use expirações para dados de cache, use NX ou XX quando sobrescritas importam, trate nil como um estado separado e mantenha os nomes das chaves consistentes o suficiente para que alguém possa depurá-los a partir de um terminal. Quando as strings começarem a parecer apertadas, mova campos relacionados para hashes e use a estrutura de dados que corresponde ao padrão de acesso.