Cache gerenciado
O componente Cache da Zenifra usa Valkey atualmente e foi projetado para dados que podem ser reconstruídos a partir de uma fonte de verdade. O armazenamento é descartável: reinícios, expiração e eviction podem remover entradas sem representar perda de dados da aplicação.
Padrão cache-aside
- Leia a chave no Valkey.
- Em caso de miss, consulte a fonte de verdade.
- Grave o resultado com TTL e, quando possível, um pequeno jitter.
- Invalide a chave quando a fonte de verdade mudar.
GET catalog:product:42
SET catalog:product:42 <json> EX 300
DEL catalog:product:42Nunca armazene tokens, senhas ou dados regulados sem uma política de proteção adequada. Use namespaces, limite o tamanho dos valores e monitore a taxa de hit/miss.
Node.js e TypeScript
npm install iovalkeyimport Redis from 'iovalkey'
import { randomInt } from 'node:crypto'
async function loadProductFromSource() {
return { id: 42, name: 'example' }
}
const url = new URL(process.env.VALKEY_URL ?? '')
const client = new Redis({
host: url.hostname,
port: Number(url.port),
username: decodeURIComponent(url.username),
password: decodeURIComponent(url.password),
tls: { servername: url.hostname },
})
const key = 'catalog:product:42'
const cached = await client.get(key)
const value = cached ?? JSON.stringify(await loadProductFromSource())
if (!cached) await client.set(key, value, 'EX', 300 + randomInt(0, 30))
console.log(value)
await client.quit()Substitua loadProductFromSource() pela consulta real da aplicação. O exemplo usa jitter para reduzir expirações simultâneas; em alto volume, combine-o com lock curto ou request coalescing.
Python
python -m pip install valkeyimport json
import os
import random
from urllib.parse import urlparse
from valkey import Valkey
def load_product_from_source():
return {"id": 42, "name": "example"}
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,
)
key = "catalog:product:42"
cached = client.get(key)
value = cached or json.dumps(load_product_from_source())
if cached is None:
client.set(key, value, ex=300 + random.randint(0, 30))
print(value)
client.close()Substitua load_product_from_source() pela consulta da aplicação. Para evitar cache stampede, apenas um worker deve reconstruir uma chave em expiração; os demais podem aguardar ou usar um valor stale por uma janela curta.
O que não fazer
- Não trate Cache como armazenamento permanente.
- Não use TTL infinito para dados que podem crescer sem limite.
- Não faça
KEYS *para limpar o cache; use namespaces eSCANou invalidação por chave. - Não deduza que um hit significa que o dado está atualizado; defina uma política de invalidação.
Operação segura
Escolha TTLs de acordo com a velocidade de mudança da fonte, não com o tamanho do plano. Um TTL muito curto aumenta carga e latência; um TTL muito longo deixa dados obsoletos. Jitter aleatório evita que milhares de chaves expirem no mesmo segundo. Quando uma reconstrução for cara, use um lock curto com token e permita que leitores recebam um valor stale por uma janela controlada.
Monitore hit rate, miss rate, latência, erros de serialização e quantidade de evictions. Um aumento de misses pode indicar invalidação excessiva ou capacidade insuficiente, enquanto um hit rate alto não prova que o conteúdo está correto. Defina uma forma de invalidar por entidade após escritas na fonte, e trate falha do Cache como um caminho normal: a aplicação deve consultar a origem e continuar funcionando sem os dados descartáveis.