A seconda del inserisci / scrividi struttura di dati, MemoryStoreService impone limiti sulla memoria e sul numero di oggetti in una struttura di dati.Tutte le strutture dei dati sono anche vincolate da un limite globale per richiesta per partizione.
Ogni esperienza Roblox ha la Dashboard di osservabilità del Memory Store, che include un insieme di grafici che puoi utilizzare per monitorare l'utilizzo del memory store.
Mappe e code ordinate
Le mappe ordinate e le code hanno entrambi limiti sul numero massimo di oggetti e sulla memoria totale massima.Inoltre, gli elementi in una di queste strutture di dati risiedono sempre su una singola partizione.Ogni richiesta a una di quelle strutture di dati è una richiesta alla stessa partizione.
Quando una mappa ordinata o code raggiunge il suo limite di oggetti o memoria, il miglior corso d'azione è rimuovere gli oggetti non necessari manualmente o aggiungendo una politica di scadenza per gli oggetti.In alternativa, se solo il limite di memoria causa il rallentamento, puoi provare a ridurre le dimensioni dei tuoi oggetti rimuovendo le informazioni non necessarie dalle tue chiavi e valori.
Se hai bisogno di tutti i tuoi oggetti o stai riscontrando rallentamenti a causa del traffico delle richieste, l'unica soluzione è lo sharding.
Frammentazione
Sharding è il processo di memorizzazione di un insieme di dati correlati attraverso più strutture di dati.In altre parole, significa prendere una struttura di dati esistente ad alto volume e sostituirla con più piccole, che insieme contengono lo stesso set di dati dell'originale.
La sfida chiave per lo sharding è trovare un modo per distribuire i dati su più strutture di dati in modo da mantenere la stessa funzionalità dell'originale.
Sharding una mappa ordinata
Per frammentare una mappa ordinata, considera di dividere i tuoi dati in sottosezioni alfabetiche con intervalli di caratteri.Ad esempio, supponiamo che tu abbia solo chiavi con la prima lettera da A-Z e credi che quattro mappe ordinate siano sufficienti per il tuo caso d'uso attuale e per la crescita futura:
- La prima mappa può coprire A-G, la seconda H-N, la terza O-T e la quarta U-Z.
- Per inserire o recuperare un Articolo, usa la mappa appropriata in base al personaggio iniziale dell'Articolo.
Sharding una mappa ordinata
-- Inizializza il servizio MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Crea i tuoi secchi di mappa ordinati
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- Funzione aiutante per recuperare il secchiello corretto dalla chiave dell'oggetto
local function getSortedMapBucket(itemKey)
if (itemKey >= "a" and itemKey < "h") then
return sm_AtoG
elseif (itemKey < "n") then
return sm_HtoM
elseif (itemKey < "u") then
return sm_NtoT
else
return sm_UtoZ
end
end
-- Inizializza i nomi del giocatore con il valore predefinito di 0
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- Recupera il valore di un Giocatore
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)
Dividere una coda
Frammentare una coda è più complicato di frammentare una mappa ordinata.Anche se vuoi distribuire il flusso di richieste attraverso più code, aggiunge, legge e rimuove avvengono solo alla fine o all'inizio della coda.
Una soluzione è utilizzare una coda rotante, che significa creare più code e ruotare tra di esse quando aggiungi o leggi un Articolo:
Crea diverse code e aggiungile a un vettore.
Crea due punti locali. Uno rappresenta la coda da cui vuoi leggere e rimuovere gli elementi. L'altro rappresenta la coda a cui vuoi aggiungere gli elementi:
- Per le operazioni di lettura, calcola il numero di elementi di cui hai bisogno da ciascuna coda, nonché dove spostare il puntatore di lettura.
- Per le operazioni di rimozione, passa gli ID dalla lettura a ciascuna coda.
- Per aggiungere operazioni, aggiungi alla coda al punto di aggiunta e incrementa il puntatore.
Dividere una coda
-- Inizializza il servizio MemoryStore
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 della lettura e aggiungi le code
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 oggetti dalla coda
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- 循环 attraverso ogni coda
for i = 1, 4, 1 do
-- determina se questa coda leggerà un articoloin più
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- leggi gli elementi di ogni coda
-- +1 oggetti se corrisponde a 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 oggetti dalla coda
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
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[readIndex]
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, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)
Mappe di hash
Le mappe di hash non hanno limiti di memoria o conteggio oggetti individuali e vengono automaticamente frammentate, ma puoi ancora incontrare il throttling se le usi male.
Ad esempio, considera un'esperienza con una mappa di hash di dati di gioco, memorizzata come il valore di una singola chiave chiamata metadata .Se questo metadata contiene un oggetto nidato con informazioni come l'ID del luogo, il conteggio del giocatore e altro ancora, ogni volta che è necessario il metadata 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.
Piuttosto che memorizzare tutti i metadati come un singolo oggetto annidato, l'approccio migliore è quello di memorizzare ogni campo come sua propria chiave in modo che la mappa di hash possa beneficiare di uno sharding automatico.Se hai bisogno di separazione tra metadata e il resto della mappa hash, aggiungi un prefisso di nome (ad esempiometadata_user_count piuttosto che solo user_count ).