Preview
KV Store é um serviço de armazenamento de chave-valor distribuído que opera em toda a rede da Azion. Ele permite que você persista e recupere pequenos pedaços de dados com latência muito baixa de qualquer lugar onde seus usuários estejam, sem precisar gerenciar servidores.
A API JavaScript foi projetada para ser compatível com a API do Cloudflare Workers KV, facilitando a migração de aplicações existentes para a plataforma da Azion.
Casos de uso típicos incluem:
- Sessões e tokens de autenticação
- Feature flags e configurações de testes A/B
- Preferências de usuário e personalização
- Cache de respostas de API e fragmentos computados
- Contadores de rate limit e chaves de idempotência
- Estado do carrinho de compras ou rascunho
Como funciona
O KV Store organiza dados em namespaces, onde cada namespace contém um conjunto independente de chaves. Veja como o sistema opera:
- Os dados são organizados em namespaces que contêm conjuntos independentes de chaves.
- Cada item é endereçado por uma chave que é única dentro de seu namespace.
- Os valores podem ser armazenados como texto, JSON, ArrayBuffer ou ReadableStream.
- Os dados são replicados entre os pontos de presença globais para maximizar a disponibilidade e o desempenho de leitura.
- Operações de chave única são atômicas por chave. Transações de múltiplas chaves não são suportadas.
Recursos de implementação
| Escopo | Recurso |
|---|---|
| Gerenciar KV Store com Functions | Como gerenciar KV Store com Functions |
| Referência da API KV Store | Azion API - KV Store |
Resiliência de dados
O KV Store usa uma arquitetura distribuída com replicação entre os nodes da Azion. Novas gravações são aceitas e propagadas para réplicas para garantir durabilidade e alta disponibilidade. Leituras são servidas da réplica saudável mais próxima para minimizar a latência.
Namespaces
Um namespace é um espaço de chaves isolado. Use namespaces para segmentar dados por aplicação, ambiente ou carga de trabalho.
Padrões recomendados
- Use namespaces separados para ambientes de produção e staging.
- Prefixe chaves para modelar hierarquia, por exemplo:
users/123/profile,flags/new-ui,carts/region-br/user-42. - Mantenha as chaves curtas e significativas; prefira alguns segmentos do tipo caminho em vez de longos identificadores opacos.
Convenções de nomenclatura
- Os nomes devem ser únicos dentro da sua conta.
- Os nomes devem ter entre 3 e 63 caracteres.
- Use letras minúsculas, números, hifens e underscores.
- Os nomes devem corresponder ao padrão:
^[a-zA-Z0-9_-]+$
Gerenciando namespaces via API
Você pode gerenciar namespaces usando a API da Azion. O endpoint base é:
https://api.azion.com/v4/workspace/kv/namespacesCriar um namespace
curl -X POST "https://api.azion.com/v4/workspace/kv/namespaces" \ -H "Authorization: Token SEU_TOKEN_API" \ -H "Content-Type: application/json" \ -d '{"name": "meu-namespace"}'Resposta (201 Created):
{ "name": "meu-namespace", "created_at": "2025-01-24T14:15:22Z", "last_modified": "2025-01-24T14:15:22Z"}Listar namespaces
curl -X GET "https://api.azion.com/v4/workspace/kv/namespaces" \ -H "Authorization: Token SEU_TOKEN_API" \ -H "Accept: application/json"Parâmetros de consulta:
| Parâmetro | Tipo | Descrição |
|---|---|---|
fields | string | Lista separada por vírgulas de nomes de campos para incluir na resposta |
page | integer | Número da página dentro do conjunto de resultados paginados |
page_size | integer | Número de itens por página |
Recuperar um namespace
curl -X GET "https://api.azion.com/v4/workspace/kv/namespaces/{namespace}" \ -H "Authorization: Token SEU_TOKEN_API" \ -H "Accept: application/json"Interação com KV Store via Functions
Você pode interagir com o KV Store diretamente de suas Functions usando a
classe Azion.KV. Os exemplos abaixo ilustram padrões comuns para criar, ler,
atualizar e excluir dados.
Inicializando o cliente KV
Você pode inicializar o cliente KV usando o construtor ou o método open:
// Usando o namespace padrãoconst kv = new Azion.KV();
// Usando um namespace específicoconst kv = new Azion.KV("meu-namespace");
// Usando o método openconst kv = await Azion.KV.open("meu-namespace");Armazenando dados (put)
Armazene valores em diferentes formatos:
async function handleRequest(request) { const kv = new Azion.KV(); const key = "sessao-usuario";
// Armazenar um valor string await kv.put(key, "dados-da-sessao-aqui");
// Armazenar um objeto JSON await kv.put(key, { userId: 123, role: "admin" });
// Armazenar um ArrayBuffer const encoder = new TextEncoder(); const buffer = encoder.encode("dados binários").buffer; await kv.put(key, buffer);
// Armazenar com opções (metadados e expiração) await kv.put(key, "valor", { metadata: { created_by: "user-42" }, expiration: Math.floor(Date.now() / 1000) + 3600, // expira em 1 hora expirationTtl: 3600 // alternativa: TTL em segundos });
return new Response("Dados armazenados", { status: 200 });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Armazenando dados grandes com streams
Para payloads grandes, use ReadableStream para transmitir dados de forma eficiente:
async function handleRequest(request) { const kv = new Azion.KV(); const key = "arquivo-grande"; const dataSizeInKB = 500; const totalSize = dataSizeInKB * 1024; const chunkSize = 64 * 1024; // chunks de 64KB
const stream = new ReadableStream({ async start(controller) { const encoder = new TextEncoder(); const numChunks = Math.ceil(totalSize / chunkSize);
for (let i = 0; i < numChunks; i++) { const currentChunkSize = Math.min(chunkSize, totalSize - i * chunkSize); const chunk = "a".repeat(currentChunkSize); controller.enqueue(encoder.encode(chunk)); } controller.close(); }, });
await kv.put(key, stream);
return new Response("Dados grandes armazenados", { status: 200 });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Recuperando dados (get)
Recupere valores em diferentes formatos:
async function handleRequest(request) { const kv = new Azion.KV(); const key = "sessao-usuario";
// Obter como texto (padrão) const textValue = await kv.get(key, "text");
// Obter como JSON const jsonValue = await kv.get(key, "json"); console.log(`User ID: ${jsonValue.userId}`);
// Obter como ArrayBuffer const bufferValue = await kv.get(key, "arrayBuffer"); const decoder = new TextDecoder("utf-8"); const decodedString = decoder.decode(bufferValue);
// Obter como ReadableStream const streamValue = await kv.get(key, "stream");
// Tratar chaves inexistentes (retorna null) const missing = await kv.get("chave-inexistente", "text"); if (missing === null) { console.log("Chave não encontrada"); }
return new Response(textValue, { status: 200 });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Recuperando múltiplas chaves
Recupere múltiplos valores em uma única operação:
async function handleRequest(request) { const kv = new Azion.KV();
const keys = ["usuario-1", "usuario-2", "usuario-3"]; const data = await kv.get(keys, "text");
// Retorna um objeto com pares chave-valor // Chaves inexistentes têm valores null console.log(JSON.stringify(data));
return new Response(JSON.stringify(data), { headers: { "Content-Type": "application/json" }, status: 200, });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Recuperando dados com metadados
Use getWithMetadata para recuperar tanto o valor quanto seus metadados associados:
async function handleRequest(request) { const kv = new Azion.KV(); const key = "sessao-usuario";
// Armazenar com metadados await kv.put(key, "valor-sessao", { metadata: { created_by: "user-42", version: 1 } });
// Recuperar com metadados const data = await kv.getWithMetadata(key, "text"); console.log(`Valor: ${data.value}`); console.log(`Metadados: ${JSON.stringify(data.metadata)}`);
// Funciona com múltiplas chaves também const keys = ["chave1", "chave2"]; const multiData = await kv.getWithMetadata(keys, "text");
return new Response(JSON.stringify(data), { headers: { "Content-Type": "application/json" }, status: 200, });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Lendo streams
Processe dados em stream de forma incremental:
async function handleRequest(request) { const kv = new Azion.KV(); const key = "arquivo-grande";
const stream = await kv.get(key, "stream");
if (stream instanceof ReadableStream) { const decoder = new TextDecoder(); let text = "";
for await (const chunk of stream) { text += decoder.decode(chunk, { stream: true }); } text += decoder.decode();
console.log(`Recuperados ${text.length} caracteres`); }
// Ou retorne o stream diretamente na resposta return new Response(stream);}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Excluindo dados
Remova uma chave do armazenamento:
async function handleRequest(request) { const kv = new Azion.KV(); const key = "sessao-usuario";
await kv.delete(key);
return new Response("Chave excluída", { status: 200 });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Trabalhando com Unicode e caracteres especiais
O KV Store suporta chaves e valores codificados em UTF-8 e UTF-16:
async function handleRequest(request) { const kv = new Azion.KV();
// Chave UTF-16 (Chinês: "Minha Chave") const key = "我的钥匙";
// Valor UTF-16 com emojis const value = "🌍🌎🌏 Hello World 你好 世界";
await kv.put(key, value);
const retrieved = await kv.get(key, "text"); console.log(`Chave: ${key}, Valor: ${retrieved}`);
return new Response("OK", { status: 200 });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Excluindo namespaces
Exclua um namespace inteiro programaticamente:
async function handleRequest(request) { const namespaceName = "meu-namespace";
// Excluir o namespace await Azion.KV.delete(namespaceName);
return new Response("Namespace excluído", { status: 200 });}
addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));});Referência de métodos
A classe Azion.KV fornece os seguintes métodos:
Construtor e inicialização
| Método | Descrição |
|---|---|
new Azion.KV() | Cria uma instância KV usando o namespace padrão |
new Azion.KV(name) | Cria uma instância KV para o namespace especificado |
Azion.KV.open(name) | Abre um namespace de forma assíncrona |
Azion.KV.delete(name) | Exclui um namespace |
Operações de dados
| Método | Parâmetros | Retorna | Descrição |
|---|---|---|---|
put(key, value, options?) | key: stringvalue: string | object | ArrayBuffer | ReadableStreamoptions: { metadata?, expiration?, expirationTtl? } | Promise<void> | Armazena um valor |
get(key, type?, options?) | key: string | string[]type: “text” | “json” | “arrayBuffer” | “stream”options: { cacheTtl? } | Promise<value | null> | Recupera um valor |
getWithMetadata(key, type?, options?) | key: string | string[]type: “text” | “json” | “arrayBuffer” | “stream”options: { cacheTtl? } | Promise<{'{value, metadata}'}> | Recupera valor com metadados |
delete(key) | key: string | Promise<void> | Exclui uma chave |
Opções do put
| Opção | Tipo | Descrição |
|---|---|---|
metadata | object | Metadados personalizados para associar à chave (máx 1024 bytes JSON-serializado) |
expiration | number | Timestamp Unix (segundos) quando a chave expira |
expirationTtl | number | Time-to-live em segundos a partir de agora |
Opções do get
| Opção | Tipo | Descrição |
|---|---|---|
cacheTtl | number | Tempo em segundos para armazenar o resultado em cache localmente (mínimo 60 segundos) |
Tipos do get
| Tipo | Retorna | Descrição |
|---|---|---|
"text" | string | Retorna o valor como uma string UTF-8 (padrão) |
"json" | object | Faz parse do valor como JSON |
"arrayBuffer" | ArrayBuffer | Retorna dados binários brutos |
"stream" | ReadableStream | Retorna um stream legível para valores grandes |
Limites
Estes são os limites padrão:
| Limite | Valor |
|---|---|
| Taxa de gravação por chave | Até 1 gravação por segundo para a mesma chave |
| Tamanho da chave | Até 512 bytes (UTF-8) |
| Tamanho dos metadados | Até 1024 bytes (JSON-serializado) |
| Tamanho do valor | Até 25 MB por item |
| Comprimento do nome do namespace | 3-63 caracteres |
Mínimo expirationTtl | 60 segundos |
Mínimo cacheTtl | 60 segundos |
Estes são os limites padrão para cada Plano de Serviço:
| Escopo | Developer | Business | Enterprise | Mission Critical |
|---|---|---|---|---|
| Namespaces | 1000 | 1000 | 1000 | 1000 |
| Tamanho máximo do arquivo | 200 MB | 500 MB | 2 GB | 2 GB |
| Armazenamento máximo por conta | 5 GB | 50 GB | 300 GB | 300 GB |
Limitações
As seguintes operações não são suportadas:
- Listar chaves: Não existe um método
list()para enumerar chaves dentro de um namespace. Projete sua aplicação para rastrear chaves externamente, se necessário. - Transações de múltiplas chaves: Operações são atômicas por chave, mas não há suporte para transações que abrangem múltiplas chaves.
- Gerenciamento de namespaces a partir de functions: Namespaces devem ser criados e gerenciados via API da Azion ou Console, não de dentro de functions.