Banco de Dados

Banco de Dados Chave‑Valor com Valkey

O perfil Chave‑Valor é indicado quando os dados fazem parte do estado da aplicação e não podem ser tratados como simples resultados descartáveis. A capacidade de armazenamento é persistente e o plano comercial usa os produtos db-*.

Operações recomendadas

Use prefixos por domínio e defina TTL apenas quando o dado realmente expirar. NX é útil para criação condicional e locks curtos, mas locks de produção precisam de token único, expiração e liberação segura.

SET session:{user-id} <json> EX 3600
GET session:{user-id}
MSET profile:{user-id} <json> flags:{user-id} <json>
SET lock:{resource} <unique-token> NX EX 30

Não use KEYS * em produção. Prefira SCAN com limite de trabalho e mantenha o tamanho dos valores sob controle.

Node.js e TypeScript

npm install iovalkey
import Redis from 'iovalkey'
import { randomUUID } from 'node:crypto'

const source = process.env.VALKEY_URL
if (!source) throw new Error('VALKEY_URL is required')
const url = new URL(source)
const client = new Redis({
  host: url.hostname,
  port: Number(url.port),
  username: decodeURIComponent(url.username),
  password: decodeURIComponent(url.password),
  tls: { servername: url.hostname },
})

await client.set('session:user-42', JSON.stringify({ role: 'admin' }), 'EX', 3600)
const session = await client.get('session:user-42')
const created = await client.set('lock:invoice-42', randomUUID(), 'NX', 'EX', 30)
console.log({ session, lockCreated: created === 'OK' })
await client.quit()

Python

python -m pip install valkey
import json
import os
import uuid
from urllib.parse import urlparse
from valkey import Valkey

url = urlparse(os.environ["VALKEY_URL"])
client = Valkey(
    host=url.hostname, port=url.port, username=url.username, password=url.password,
    ssl=True, ssl_check_hostname=True, decode_responses=True,
)

client.set("session:user-42", json.dumps({"role": "admin"}), ex=3600)
session = client.get("session:user-42")
token = str(uuid.uuid4())
lock_created = client.set("lock:invoice-42", token, nx=True, ex=30)
print({"session": session, "lock_created": lock_created})
client.close()

Consistência e limites

  • Faça operações relacionadas em uma transação ou script quando elas precisarem ser atômicas.
  • Torne escritas e retries idempotentes; uma resposta de rede perdida não informa se o servidor aplicou a operação.
  • Não trate o perfil como banco relacional: não há joins, constraints ou consultas ad hoc.
  • Planeje a capacidade para chaves, valores, índices da aplicação e margem de crescimento.
  • Use o plano Cache quando o dado puder ser reconstruído; não use Chave‑Valor apenas para aproveitar o armazenamento.

Padrões recomendados

Use namespaces por domínio, como session:, lock: e counter:, para facilitar inspeção e invalidação seletiva. Defina limites de tamanho para valores serializados e prefira estruturas nativas quando elas reduzirem a duplicação. Para contadores, INCRBY é atômico no servidor; para vários campos relacionados, um script Lua ou transação pode manter a operação consistente.

Locks devem ter TTL e um token único. Ao liberar um lock, compare o token no servidor para não remover o lock de outro worker que o assumiu depois de uma expiração. Sessões devem ter expiração compatível com o ciclo de autenticação e uma estratégia clara para renovar o TTL. Em retries, use chaves de idempotência para que uma requisição repetida não crie efeitos duplicados.

O perfil Chave‑Valor não substitui um banco relacional: consultas ad hoc, joins e relatórios devem continuar no sistema apropriado. Faça backup lógico dos dados realmente importantes na aplicação e teste a restauração; persistência da instância não elimina a necessidade de uma política de recuperação.

Próximos passos

Nessa página