Cloudflare
KV
Cloudflare KV
Produção
Padrões
Cache
Limites

KV in produzione: i modelli che funzionano e quelli che inizialmente ingannano

Modelli di utilizzo di Cloudflare KV che funzionano in produzione: trucco dei metadati, memorizzazione nella cache a livello di modulo, chiave di indice per list() e anti-pattern che esauriscono rapidamente il livello gratuito.

KV in produzione: i modelli che funzionano e quelli che inizialmente ingannano

Mille scritture al giorno sembrano sufficienti finché non si mette in produzione qualcosa con utenti reali. Un sistema di login che scrive un token di sessione sul KV per autenticazione esaurisce questo limite con mezz'ora di traffico moderato. Il primo confronto con i limiti reali della KV avviene raramente nella messa in scena.

Il livello gratuito, ovvero 100.000 letture e 1.000 scritture al giorno, è stato progettato per riflettere il modello di utilizzo corretto: molte letture, poche scritture. Quando un team utilizza KV in modo coerente con questo modello, il livello gratuito dura a lungo. Se utilizzato come banca di sessione o archivio di stati per utente, il limite viene visualizzato nella prima settimana.

Modelli che funzionano

L'uso più efficace di KV è l'archiviazione della configurazione dell'applicazione letta ripetutamente e modificata raramente. Un JSON con flag di prodotto, parametri aziendali, whitelist, endpoint di terze parti: questo tipo di dati cambia in base all'azione amministrativa, non all'utente. Una scrittura sul KV si propaga a tutti i PoP e serve milioni di richieste senza costi rilevanti. Un team che scrive a questa chiave dieci volte al mese e la legge dieci milioni di volte rientra comodamente nel livello gratuito.

La memorizzazione nella cache dell'HTML renderizzato segue lo stesso principio. Un post sul blog, una pagina di prodotto, un risultato di ricerca che non cambia per utente: lo visualizzi una volta, lo salvi nel KV con un TTL appropriato e lo servi direttamente dalla cache PoP per eventuali richieste successive. Il costo del rendering diminuisce, la latenza diminuisce e il numero di scritture diventa proporzionale alla frequenza degli aggiornamenti dei contenuti, non al volume del traffico.

Anche i token di sessione con TTL sono adatti, purché la sessione sia scrivibile una volta. Scrivi il token al momento dell'autenticazione (una scrittura per accesso) e lo leggi ad ogni richiesta successiva. Se un utente accede una volta e rimane attivo per ore, il rapporto lettura/scrittura è eccellente. Ciò che rompe questo modello è la sessione con stato mutabile: ogni aggiornamento dei dati della sessione diventa una scrittura e il costo esplode.

Il trucco con i metadati

Ciascuna chiave nel KV può contenere fino a 1024 byte di metadati JSON arbitrari, separati dal valore stesso. Questo campo viene restituito da getWithMetadata() insieme al valore, in un'unica operazione — senza costi di lettura aggiuntivi.

L'uso pratico è memorizzare le informazioni insieme al valore che dovresti analizzare o dedurre in un altro modo. Per un file binario salvato in KV, i metadati possono contenere Content-Type, ETag, data di creazione, dimensione originale ed eventuali intestazioni HTTP rilevanti. Il lavoratore legge la chiave, riceve valore e metadati in una chiamata e assembla la risposta HTTP con le intestazioni corrette senza alcuna ricerca aggiuntiva o logica di analisi.

Questo funziona anche per il controllo delle versioni leggero. Salva la versione o il timestamp dell'ultimo aggiornamento nei metadati. Qualsiasi consumatore può verificare se sta leggendo la versione prevista senza cercare un secondo dato.

Il problema di prestazioni di list()

list() è l'operazione KV più costosa in termini di prestazioni relative, ed è quella che compare più frequentemente sui percorsi che non dovrebbero utilizzarla. Una chiamata a list() in uno spazio dei nomi con 100mila chiavi è lenta (la latenza dipenderà dalla dimensione dello spazio dei nomi e del cursore) e conta come un'operazione su elenco, che ha una quota separata: 1mila operazioni al giorno nel livello gratuito, 0,50 dollari al milione in quello a pagamento.

Il vero problema è usare list() nel percorso caldo di una richiesta. Se ogni richiesta deve scoprire quali chiavi esistono per fornire una risposta, hai inserito un'operazione di gestione dei dati all'interno del percorso delle prestazioni critiche.

La soluzione è mantenere una chiave di indice. Scrivi una chiave come __index__ nel KV il cui valore è un JSON con l'elenco delle chiavi dello spazio dei nomi o solo gli identificatori necessari per la logica. Quando lo spazio dei nomi cambia, aggiorni l'indice insieme alla scrittura principale. Il costo è di una scrittura aggiuntiva per operazione di scrittura. Il vantaggio è che qualsiasi lettura dell'indice è una lettura normale, con latenza della cache e senza i problemi di ridimensionamento di list().

Questo modello presenta l'ovvia limitazione che l'indice deve essere mantenuto sincronizzato manualmente. Se disponi di più writer, l'assenza di operazioni atomiche in KV crea una finestra di incoerenza nell'indice. Per gli spazi dei nomi con scrittura singola o scrittura controllata da un singolo writer, il modello funziona bene.

Caching a livello di modulo: l'ottimizzazione che nessuno documenta esplicitamente

I lavoratori su Cloudflare funzionano su isolati V8. Un singolo isolato può soddisfare migliaia di richieste prima di essere sfrattato. Le variabili dichiarate nell'ambito del modulo, all'esterno del gestore, persistono tra le richieste finché l'isolamento è attivo.

Ciò crea un'opportunità di ottimizzazione semplice ed efficace per i dati di configurazione. Invece di fare env.CONFIG.get('settings') in ogni richiesta, dichiari una variabile nell'ambito del modulo e cerchi il KV solo quando non è stato ancora inizializzato:

let config = null; export default { async fetch(request, env) { config = config ?? await env.CONFIG.get('settings', { type: 'json' }); // usa config } };

La prima richiesta di isolamento legge il KV. Tutte le richieste successive per lo stesso isolato utilizzano il valore in memoria. Per i dati che cambiano raramente (configurazione del prodotto, indicatori di funzionalità) questo elimina la lettura KV di quasi tutte le richieste, riducendo la latenza e il consumo delle operazioni di lettura.

L'implicazione è che un aggiornamento del KV non si riflette immediatamente in tutti i lavoratori: ogni isolato continuerà a utilizzare il valore memorizzato nella cache finché non verrà eliminato. Per i dati in cui sono accettabili da 60 secondi a pochi minuti di ritardo, il compromesso è eccellente. Per i dati che devono essere aggiornati immediatamente in tutti i lavoratori, questo modello non è adatto.

Cosa non mettere in produzione senza ripensarci

L'utilizzo di KV come coda di lavoro non funziona. Senza operazioni atomiche, due Worker possono leggere lo stesso lavoro, elaborarlo in duplicato e contrassegnarlo come completo in modo indipendente. Il risultato è un'elaborazione duplicata senza meccanismo di rilevamento.

Il salvataggio dei dati utente modificabili in base alla chiave utente non si adatta bene al limite di scrittura. Un'applicazione con 10mila utenti attivi al giorno che aggiorna i dati del profilo anche una volta per sessione è già nell'ordine di grandezza del limite pagato di 1 milione di scritture mensili - e il costo per scrittura di $ 0,50/milione inizia ad apparire quando si va oltre.

Gli spazi dei nomi con un'elevata densità di chiavi e la frequente necessità di essere elencati rappresentano una trappola per le prestazioni. list() è lento negli spazi dei nomi di grandi dimensioni e non dovrebbe trovarsi nel percorso della richiesta. Se il tuo caso d'uso richiede elenchi frequenti, il modello di dati deve essere modificato, con chiavi di indice gestite manualmente o con uno strumento diverso.

Cosa rivela il livello gratuito sul design

I limiti del livello gratuito – 100.000 letture per 1.000 scritture – sono un documento di progettazione sotto mentite spoglie. Il rapporto 100:1 tra letture e scritture non è arbitrario. Descrive il carico di lavoro per cui è stato costruito il KV. Qualsiasi utilizzo che inverte o si avvicina a questo rapporto non rientra nel modello operativo previsto e incontrerà limitazioni in termini di costi, prestazioni o coerenza che non compaiono nei test a basso volume.

Leggi anche