Abhängig vom eingebenerzwingt MemoryStoreService Grenzen auf die Speicher und die Anzahl der Elemente in einer Datenstruktur.Alle Datenstrukturen sind auch durch ein globales Per-Partition-Anforderungslimit beschränkt.
Jedes Roblox-Erlebnis hat das Memory-Store-Beobachtungs-Dashboard, das eine Reihe von Diagrammen enthält, die Sie zur Überwachung der Nutzung des Speichers verwenden können.
Sortierte Karten und Warteschlangen
Sortierte Karten und Warteschlangen haben beide Einschränkungen der maximalen Anzahl von Artikeln und der maximalen Gesamtspeicher.Zusätzlich befinden sich die Elemente in einer dieser Datenstrukturen immer auf einer einzigen Partition.Jede Anfrage an eine dieser Datenstrukturen ist eine Anfrage an die gleiche Partition.
Wenn eine sortierte Karte oder Warteschlangen ihr Element- oder Speicherlimit erreicht, ist der beste Weg, unnötige Elemente manuell zu entfernen oder eine Verfallszeit für Elemente hinzuzufügen.Alternativ kannst du versuchen, die Größe deiner Elemente zu reduzieren, indem du unnötige Informationen aus deinen Schlüsseln und Werten entfernst.
Wenn du alle deine Artikel benötigst oder aufgrund der Anforderungsauslastung eine Verlangsamung erlebst, ist die einzige Lösung das Zerlegen.
Zerschmettern
Sharding ist der Prozess des Speicherns einer Reihe verwandter Daten über mehrere Datenstrukturen.Mit anderen Worten, es bedeutet, eine vorhandene, hochskalierbare Datenstruktur zu nehmen und sie durch mehrere kleinere zu ersetzen, die zusammen die gleiche Datenmenge enthalten wie die ursprüngliche.
Die wichtigste Herausforderung bei der Zerschlagung ist es, einen Weg zu finden, die Daten auf mehrere Datenstrukturen aufzuteilen, ohne die gleiche Funktionalität wie die ursprüngliche zu verlieren.
Eine sortierte Karte zerschneiden
Um eine sortierte Karte zu zerschneiden, betrachte die Aufteilung deiner Daten in alphabetische Unterabschnitte mit Zeichenbereichen.Angenommen, du hast zum Beispiel nur Schlüssel mit dem ersten Buchstaben von A-Z und glaubst, dass vier sortierte Karten für deinen aktuellen Anwendungsfall und zukünftiges Wachstum ausreichen:
- Die erste Karte kann A-G, die zweite H-N, die dritte O-T und die vierte U-Z abdecken.
- Um ein Artikeleinzufügen oder abzurufen, verwende die entsprechende Karte basierend auf dem Startzeichen des Artikel.
Eine sortierte Karte zerschneiden
-- MemoryStore-Service initialisieren
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Erstelle deine sortierten Karten-Bucket
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- Helferfunktion, um den richtigen Bucket aus dem Artikel-Schlüssel zu extrahieren
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
-- Spielernamen mit Standardwert von 0 initialisieren
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- Werte eines Spieler:inabrufen
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)
Eine Warteschlange aufteilen
Die Zerteilung einer Warteschlange ist komplizierter als die Zerteilung einer sortierten Karte.Obwohl du die Anforderungsauslastung über mehrere Warteschlangen verteilen möchtest, geschieht das Hinzufügen, Lesen und Entfernen nur jeweils an der Vorder- oder Rückseite der Warteschlange.
Eine Lösung besteht darin, eine drehende Warteschlange zu verwenden, was bedeutet, mehrere Warteschlangen zu erstellen und sich zwischen ihnen zu drehen, wenn Sie ein Artikelhinzufügen oder lesen:
Erstelle mehrere Warteschlangen und füge sie einem Array hinzu.
Erstellen Sie zwei lokale Zeiger. Einer repräsentiert die Warteschlange, von der Sie Artikel lesen und entfernen möchten. Der andere repräsentiert die Warteschlange, in die Sie Artikel hinzufügen möchten:
- Für Lesevoperationen berechnen Sie die Anzahl der Artikel, die Sie aus jeder Warteschlange benötigen, sowie den Ort, an den der Lesepfeil bewegt werden muss.
- Für Entfernungsvorgänge geben Sie die IDs von der Lektüre auf jede Warteschlange weiter.
- Für Hinzufügungsoperationen füge zum Hinzufügungspunkt der Warteschlange hinzu und erhöhe den Punkt.
Eine Warteschlange aufteilen
-- MemoryStore-Service initialisieren
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Erstelle deine Warteschlangen
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- Stelle die Warteschlangen in ein Array
local queueArr = { q1, q2, q3, q4 }
-- Erstelle zwei Zeiger, die die Indizes der Lese- und Hinzufügungs-Warteschlangen darstellen
local readIndex = 1
local addIndex = 1
-- Erstelle eine lokale Funktion, die die Indizes angemessen aktualisiert
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- Erstelle eine lokale Funktion, die n Artikel aus der Warteschlange liest
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- schleife durch jede warteschlange
for i = 1, 4, 1 do
-- entscheiden, ob diese warteschlange ein zusätzliches artikellesen wird
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- artikel aus jeder warteschlange lesen
-- +1 artikel, wenn zusätzliche lesekriterien erfüllt sind
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
-- Erstelle eine lokale Funktion, die n Elemente aus der Warteschlange entfernt
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
queue:RemoveAsync(ids[i])
end
end
-- Erstelle eine lokale Funktion, die ein Element in die Warteschlange hinzufügt
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[readIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- Schreibe etwas Codes!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)
Hash-Karten
Hash-Karten haben keine einzelnen Speicher- oder Artikelanzahlgrenzen und werden automatisch zerbrochen, aber du kannst immer noch Verzögerungen erleben, wenn du sie schlecht verwendest.
Denken wir beispielsweise an ein Erlebnis mit einer Hash-Karte von Spieldaten, die als Wert eines einzelnen Schlüssels namens metadata gespeichert ist.Wenn diese Metadaten ein verschachteltes Objekt mit Informationen wie Platz-ID, Spieleranzahl und mehr enthalten, hast du jedes Mal, wenn das Metadaten benötigt wird, keine andere Wahl, als GetAsync("metadata") anzurufen und das gesamte Objekt abzurufen.In diesem Fall gehen alle Anfragen an einen einzigen Schlüssel und damit an eine einzige Partition.
Anstatt alle Metadaten als ein einzelnes, verschachteltes Objekt zu speichern, ist der bessere Ansatz, jedes Feld als eigene Schlüssel zu speichern, damit die Hash-Karte die automatische Zerschneidung nutzen kann.Wenn Sie eine Trennung zwischen Metadaten und dem Rest der Hash-Karte benötigen, fügen Sie einen Namenspräfix hinzu (z. B. metadata_user_count anstatt nur user_count ).