Migliori pratiche per i memory store

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Utilizza queste pratiche per organizzare i dati temporanei, distribuire il carico e rispondere ai problemi del memory store.

A seconda del tipo di struttura dati, MemoryStoreService applica limiti sulla memoria e sul numero di elementi in una struttura dati. Tutte le strutture dati sono anche vincolate da un limite globale di richieste per partizione.

Progettare chiavi e strutture dati

Consulta Utilizza modelli di chiavi statiche e prefissi in Migliori pratiche per i data store. Applica quei modelli sia alle chiavi che ai nomi delle strutture dati in modo che ogni server instradi gli stessi dati logici nella stessa posizione.

Scegli i tempi di scadenza che corrispondono a quanto a lungo i dati rimangono utili. Non utilizzare i memory store per registri di giocatori persistenti o dati che devono sopravvivere alla scadenza. Per aiuto nella scelta tra servizi, consulta Data store contro memory store.

Gestire i fallimenti delle richieste

Consulta Ritenta i fallimenti transitori in Migliori pratiche per i data store.

Preferire UpdateAsync rispetto a SetAsync

Consulta Preferisci UpdateAsync rispetto a SetAsync in Migliori pratiche per i data store. Le mappe hash e le mappe ordinate forniscono MemoryStoreHashMap:UpdateAsync() e MemoryStoreSortedMap:UpdateAsync() per questo modello.

Scaglionare le richieste ricorrenti

Consulta Scaglionare le richieste ricorrenti in Migliori pratiche per i data store.

Monitorare l'uso

Utilizza il Dashboard di Osservabilità del Memory Store per monitorare l'uso delle quote, il volume delle richieste e gli stati di risposta. Rivedi gli avvisi email integrati, configura avvisi personalizzati per metriche importanti del memory store e utilizza il Rapporto sugli Errori per indagare sui fallimenti.

Riduci le richieste, le dimensioni degli elementi e i tempi di scadenza prima di aumentare la capacità. Se l'uso legittimo supera le quote predefinite, valuta i Servizi Estesi.

Gestire i limiti delle mappe ordinate e delle code

Le mappe ordinate e le code hanno entrambi limiti sul numero massimo di elementi e sulla memoria totale massima. Inoltre, gli elementi in una di queste strutture dati risiedono sempre su una singola partizione. Ogni richiesta a una di queste strutture dati è una richiesta alla stessa partizione.

Quando una mappa ordinata o una coda raggiunge il suo limite di elementi o di memoria, rimuovi manualmente gli elementi non necessari o aggiungi una politica di scadenza. Se solo il limite di memoria causa throttling, riduci le dimensioni degli elementi rimuovendo informazioni non necessarie da chiavi e valori.

Se hai bisogno di tutti i tuoi elementi o stai sperimentando throttling a causa del throughput delle richieste, l'unica soluzione è lo sharding.

Distribuire il carico con lo sharding

Lo sharding è il processo di memorizzare un insieme di dati correlati su più strutture dati. In altre parole, significa prendere una struttura dati esistente ad alto throughput e sostituirla con più strutture più piccole che insieme contengono lo stesso insieme di dati dell'originale.

La sfida principale dello sharding è trovare un modo per distribuire i dati su più strutture dati in modo da mantenere la stessa funzionalità dell'originale.

Sebbene Roblox già partizioni le mappe hash, puoi ulteriormente shardarle distribuendo le richieste tra diverse chiavi.

Sharding di una mappa ordinata

Per shardare i registri dei giocatori in una mappa ordinata, utilizza l'aritmetica modulo per assegnare ogni Id a una delle mappe di un numero fisso. Il seguente esempio utilizza quattro mappe e instrada costantemente lo stesso utente alla stessa mappa:

Sharding di una Mappa Ordinata
-- Inizializza il MemoryStore Service
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Crea i tuoi bucket di Mappa Ordinata
local sm1 = MemoryStoreService:GetSortedMap("sm1")
local sm2 = MemoryStoreService:GetSortedMap("sm2")
local sm3 = MemoryStoreService:GetSortedMap("sm3")
local sm4 = MemoryStoreService:GetSortedMap("sm4")
local sortedMaps = { sm1, sm2, sm3, sm4 }
-- Funzione di supporto per recuperare il bucket corretto dalla Chiave dell'Elemento
local function getSortedMapBucket(userId)
local bucketIndex = (userId % #sortedMaps) + 1
return sortedMaps[bucketIndex]
end
-- Inizializza i giocatori con valore predefinito di 0
for _, player in game:GetService("Players"):GetPlayers() do
local userId = player.User.Id
local bucket = getSortedMapBucket(userId)
bucket:SetAsync(tostring(userId), 0, 600)
end
-- Recupera il valore di un giocatore
local player = game:GetService("Players"):GetPlayers()[1]
local userId = player.User.Id
local bucket = getSortedMapBucket(userId)
local playerScore = bucket:GetAsync(tostring(userId))
print(playerScore)

Sharding di una coda

Shardare una coda è più complicato rispetto a shardare una mappa ordinata. Sebbene tu voglia distribuire il throughput delle richieste su più code, aggiunte, letture e rimozioni avvengono sempre solo all'inizio o alla fine della coda.

Una soluzione è utilizzare una coda rotante, il che significa creare più code e ruotare tra di esse quando aggiungi o leggi un elemento:

  1. Crea diverse code e aggiungile a un array.
  2. Crea due puntatori locali. Uno rappresenta la coda da cui vuoi leggere e rimuovere elementi. L'altro rappresenta la coda a cui vuoi aggiungere elementi:
    • Per le operazioni di lettura, calcola il numero di elementi di cui hai bisogno da ciascuna coda, così come dove spostare il puntatore di lettura.
    • Per le operazioni di rimozione, passa gli ID dalla lettura a ciascuna coda.
    • Per le operazioni di aggiunta, aggiungi alla coda al puntatore di aggiunta e incrementa il puntatore.
Sharding di una Coda
-- Inizializza il MemoryStore Service
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Crea le tue Code
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- Metti le Code in un Array
local queueArr = { q1, q2, q3, q4 }
-- Crea due puntatori che rappresentano gli indici delle code di lettura e aggiunta
local readIndex = 1
local addIndex = 1
-- Crea una funzione locale che aggiorna gli indici in modo appropriato
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- Crea una funzione locale che legge n elementi dalla coda
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- ciclo attraverso ciascuna coda
for i = 1, 4, 1 do
-- determina se questa coda leggerà un elemento extra
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- leggi elementi da ciascuna coda
-- +1 elementi se corrisponde ai criteri di lettura extra
if diff < endIndex then
items[i], ids[i] = queue:ReadAsync(countPerQueue + 1, allOrNothing, waitTimeout)
else
items[i], ids[i] = queue:ReadAsync(countPerQueue, allOrNothing, waitTimeout)
end
end
readIndex = rotateIndex(readIndex, count)
return items, ids
end
-- Crea una funzione locale che rimuove n elementi dalla coda
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[i]
queue:RemoveAsync(ids[i])
end
end
-- Crea una funzione locale che aggiunge un elemento alla coda
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[addIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- Scrivi un po' di codice!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player.User.Id, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)

Mappe hash

Le mappe hash non hanno limiti individuali di memoria o conteggio degli elementi e sono automaticamente shardate, ma puoi comunque incontrare il throttling se le utilizzi in modo errato.

Ad esempio, considera un gioco con una mappa hash di dati, memorizzati come valore di una singola chiave chiamata metadata. Se questo metadata contiene un oggetto annidato con informazioni come ID del luogo, conteggio dei giocatori e altro, ogni volta che il metadata è necessario, non hai altra scelta che chiamare GetAsync("metadata") e recuperare l'intero oggetto. In questo caso, tutte le richieste vanno a una singola chiave e quindi a una singola partizione.

Invece di memorizzare tutti i metadata come un singolo oggetto annidato, memorizza ciascun campo accessibile in modo indipendente come la propria chiave in modo che la mappa hash possa sfruttare lo sharding automatico. Se hai bisogno di separazione tra i metadata e il resto della mappa hash, aggiungi un prefisso di denominazione, come metadata_user_count invece di user_count.

Se una o poche chiavi ricevono richieste frequenti, shardare quelle chiamate su più chiavi. Ad esempio, se tutti i server di gioco recuperano un valore da una chiave della mappa hash, le richieste potrebbero causare throttling della partizione. Per ridurre il carico, copia il valore su più chiavi e instrada ogni server a uno shard stabile.

© 2026 Roblox Corporation. Roblox, il logo Roblox e Powering Imagination sono tra i nostri marchi registrati e non registrati negli Stati Uniti. e altri paesi.