MemoryStoreService ist ein Hochdurchsatz- und Niedriglatenz-Dienst, der schnellen Zugriff auf Speicherplatz für Daten in Echtzeit von allen Servern in einer aktiven Sitzung ermöglicht. Speicher für Daten eignet sich für häufige und flüchtige Daten, die sich schnell ändern und nicht dauerhaft sein müssen, da sie schneller zugänglich sind und verschwinden, wenn die maximale Lebensdauer erreicht ist. Verwenden Sie für Daten, die über Sitzungen hinweg bestehen bleiben müssen, Datenläden.
Datenstrukturen
Anstatt direkt auf Rohdaten zuzugreifen, verfügen Speicher für Daten über drei primitive Datenstrukturen, die serverübergreifend für eine schnelle Verarbeitung gemeinsam genutzt werden: sortierte Map, Warteschlange und Hash-Map. Jede Datenstruktur eignet sich gut für bestimmte Anwendungsfälle:
- Fähigkeitsbasiertes Matchmaking - Speichern Sie Benutzerinformationen, wie zum Beispiel die Fähigkeitsstufe, in einer gemeinsamen Warteschlange zwischen den Servern und verwenden Sie Lobbys, um regelmäßig Matchmaking durchzuführen.
- Serverübergreifender Handel und Auktionen - Ermöglichen Sie den universellen Handel zwischen verschiedenen Servern, bei dem Benutzer auf Gegenstände mit sich in Echtzeit ändernden Preisen bieten können, mit einer sortierten Map von Schlüssel-Wert-Paaren.
- Globale Bestenlisten - Speichern und aktualisieren Sie Benutzer-Rankings auf einer gemeinsamen Bestenliste innerhalb einer sortierten Map.
- Geteilte Inventare - Speichern Sie Inventarartikel und Statistiken in einer gemeinsamen Hash-Map, wo Benutzer Inventarartikel gleichzeitig nutzen können.
- Cache für persistente Daten - Synchronisieren und kopieren Sie Ihre persistenten Daten in einem Datenlager zu einer Speicher-Hash-Map, die als Cache fungieren kann und die Leistung Ihres Spiels verbessert.
Im Allgemeinen, wenn Sie auf Daten basierend auf einem bestimmten Schlüssel zugreifen müssen, verwenden Sie eine Hash-Map. Wenn diese Daten sortiert sein müssen, verwenden Sie eine sortierte Map. Wenn Sie Ihre Daten in einer bestimmten Reihenfolge verarbeiten müssen, verwenden Sie eine Warteschlange.
Grenzen und Quoten
Um die Skalierbarkeit und Systemleistung aufrechtzuerhalten, haben Speicher für Daten Datenverwendungsquoten für die Speichermenge, API-Anfragen und die Größe der Datenstruktur.
Speicher für Daten haben eine Räumungsrichtlinie, die auf der Ablaufzeit basiert, auch bekannt als Lebensdauer (TTL). Elemente werden nach ihrer Ablaufzeit geräumt, und das Speicherplatzkontingent wird für neue Einträge freigegeben. Wenn Sie das Speicherlimit erreichen, schlagen alle nachfolgenden Schreibanfragen fehl, bis Elemente ablaufen oder Sie diese manuell löschen.
Quotierung der Speichermenge
Das Speicherplatzkontingent begrenzt die gesamte Menge an Speicher, die ein Spiel verbrauchen kann. Es ist kein fester Wert; vielmehr ändert es sich im Laufe der Zeit je nach der Anzahl der Benutzer im Spiel gemäß der Formel 64KB + 1.2KB * [Anzahl der Benutzer]. Das Kontingent gilt auf Spielebene anstelle von Serverebene.
Wenn Benutzer dem Spiel beitreten, ist das zusätzliche Speicherplatzkontingent sofort verfügbar. Wenn Benutzer das Spiel verlassen, verringert sich das Kontingent nicht sofort. Es gibt eine Rückverfolgungszeit von acht Tagen, bis das Kontingent erneut auf einen niedrigeren Wert bewertet wird.
Nachdem Ihr Spiel das Quota für die Speichermenge erreicht hat, schlagen alle API-Anfragen, die die Speichermenge erhöhen, fehl. Anfragen, die die Speichermenge verringern oder nicht ändern, sind weiterhin erfolgreich.
Mit dem Überwachungs Dashboard können Sie das Speicherplatzkontingent Ihres Spiels in Echtzeit mithilfe des Speichernutzungs-Diagramms einsehen.
API-Anfragegrenzen
Eine Anfrageeinheit-Quote gilt für alle MemoryStoreService API-Aufrufe. Diese Quote beträgt 1000 + 120 * [Anzahl der gleichzeitigen Benutzer] Anfrageeinheiten pro Minute.
Die meisten API-Aufrufe verbrauchen nur eine Anfrageeinheit, mit einigen Ausnahmen:
MemoryStoreSortedMap:GetRangeAsync()
Verbraucht Einheiten basierend auf der Anzahl der zurückgegebenen Elemente. Wenn diese Methode beispielsweise 10 Elemente zurückgibt, zählt der Aufruf als 10 Anfrageeinheiten. Wenn sie eine leere Antwort zurückgibt, zählt es als eine Anfrageeinheit.
Verbraucht Einheiten basierend auf der Anzahl der zurückgegebenen Elemente, genau wie MemoryStoreSortedMap:GetRangeAsync(), verbraucht jedoch eine zusätzliche Einheit alle zwei Sekunden während des Lesens. Geben Sie die maximalen Lesezeit mit dem Parameter waitTimeout an.
MemoryStoreHashMap:UpdateAsync()
Verbraucht mindestens zwei Einheiten.
MemoryStoreHashMap:ListItemsAsync()
Verbraucht [Anzahl der gescannten Partitionen] + [zurückgegebene Elemente] Einheiten.
Das Anfragenkontingent wird ebenfalls auf Spielebene anstelle von Serverebene angewendet. Dies bietet Flexibilität bei der Zuweisung der Anfragen unter Servern, solange die Gesamtraten von Anfragen das Kontingent nicht überschreiten. Wenn Sie das Kontingent überschreiten, erhalten Sie eine Fehlermeldung, wenn der Dienst Ihre Anfragen drosselt.
Mit der verfügbaren Überwachungs -Funktion können Sie die Anbieterquoten Ihres Spiels in Echtzeit anzeigen.
Grenzen der Datenstrukturgröße
Für eine einzelne sortierte Map oder Warteschlange gelten die folgenden Größen- und Elementanzahlgrenzen:
- Maximale Anzahl von Elementen: 1.000.000
- Maximale Gesamtgröße (einschließlich Schlüssel für sortierte Maps): 100 MB
Grenzen pro Partition
Siehe Grenzen pro Partition.
Beste Praktiken
Um Ihr Speicherverbrauchsmuster optimal zu halten und zu vermeiden, dass Sie die Grenzen erreichen, befolgen Sie diese besten Praktiken:
Entfernen Sie verarbeitete Elemente. Durch konsequente Bereinigung gelesener Elemente mithilfe der Methode MemoryStoreQueue:RemoveAsync() für Warteschlangen und MemoryStoreSortedMap:RemoveAsync() für sortierte Maps können Sie Speicher freigeben und die Datenstruktur aktuell halten.
Setzen Sie die Ablaufzeit auf den kleinsten möglichen Zeitraum, wenn Sie Daten hinzufügen. Obwohl die Standard-Ablaufzeit sowohl für MemoryStoreQueue:AddAsync() als auch für MemoryStoreSortedMap:SetAsync() 45 Tage beträgt, kann das Festlegen der kürzest möglichen Zeit dazu beitragen, alte Daten automatisch zu bereinigen, um zu verhindern, dass sie Ihr Speicherplatzkontingent füllen.
- Speichern Sie keine große Menge an Daten mit einer langen Ablaufzeit, da dies das Risiko birgt, Ihr Speicherplatzkontingent zu überschreiten und potenziell Probleme zu verursachen, die Ihr gesamtes Spiel beeinträchtigen könnten.
- Löschen Sie immer entweder explizit nicht benötigte Elemente oder setzen Sie eine kurze Ablaufzeit für die Elemente.
- Allgemein sollten Sie für das Freigeben von Speicher explizites Löschen verwenden und die Ablaufzeit von Elementen als Sicherheitsmechanismus, um zu verhindern, dass unbenutzte Elemente Speicher über einen längeren Zeitraum belegen.
Halten Sie nur notwendige Werte im Speicher.
Zum Beispiel, für ein Auktionshaus-Spiel müssen Sie nur das höchste Gebot beibehalten. Sie können MemoryStoreSortedMap:UpdateAsync() für einen Schlüssel verwenden, um das höchste Gebot aufrechtzuerhalten, anstatt alle Gebote in Ihrer Datenstruktur zu verwalten.
Verwenden Sie exponentielles zurückgestufte, um unter den API-Anfragegrenzen zu bleiben.
Wenn Sie beispielsweise einen DataUpdateConflict erhalten, sollten Sie nach zwei Sekunden erneut versuchen, dann vier, acht usw., anstatt ständig Anfragen an MemoryStoreService zu senden, um die korrekte Antwort zu erhalten.
Teilen Sie große Datenstrukturen in mehrere kleinere auf, indem Sie Sharding verwenden.
Es ist oft einfacher, Daten in kleineren Strukturen zu verwalten, anstatt alles in einer großen Datenstruktur zu speichern. Dieser Ansatz kann auch helfen, Verbrauchs- und Ratenlimits zu vermeiden. Wenn Sie beispielsweise eine sortierte Map haben, die Präfixe für ihre Schlüssel verwendet, sollten Sie in Erwägung ziehen, jede Präfix in seine eigene sortierte Map zu trennen. Für ein besonders beliebtes Spiel könnten Sie sogar Benutzer in mehrere Karten basierend auf den letzten Ziffern ihrer Benutzer-IDs trennen.
Shard häufig aufgerufene Schlüssel in Hash-Maps mit mehreren Kopien des Schlüssels, um die Last zu verteilen.
Komprimieren Sie gespeicherte Werte.
Ziehen Sie in Betracht, den LZW Algorithmus zu verwenden, um die Größe des gespeicherten Wertes zu reduzieren.
Melden Sie sich für erweiterte Services an.
Sie können Ihre Speicher- und Anfragegrenzen erhöhen, indem Sie sich für erweiterte Services anmelden.
Überwachbarkeit
Das Überwachungs-Dashboard bietet Einblicke und Analysen zur Überwachung und Fehlersuche Ihrer Nutzung von Speicher für Daten. Mit in Echtzeit aktualisierten Diagrammen zu verschiedenen Aspekten Ihres Speicherverbrauchs und Ihrer API-Anfragen können Sie das Muster der Speichernutzung Ihres Spiels verfolgen, die aktuell zugewiesenen Quoten einsehen, den API-Status überwachen und potenzielle Probleme zur Leistungsoptimierung identifizieren.
Die folgende Tabelle listet alle Statuscodes der API-Antworten auf, die auf den Diagrammen Anzahl der Anfragen nach Status und Anfragen nach API x Status des Überwachungsdashboards verfügbar sind. Weitere Informationen zur Behebung dieser Fehler finden Sie unter Fehlerbehebung. Für das spezifische Quoten- oder Limit, das eine Fehlermeldung betrifft, siehe Grenzen und Quoten.
| Statuscode | Beschreibung |
|---|---|
| Erfolg | Erfolg. |
| DataStructureMemoryOverLimit | Überschreitet das Datenstrukturniveau für die Speichermenge (100MB). |
| DataUpdateConflict | Konflikt aufgrund gleichzeitiger Aktualisierung. |
| ZugriffVerweigert | Unbefugter Zugriff auf Spieldaten. Diese Anfrage verbraucht keine Anfrageeinheiten oder nutzt das Kontingent nicht. |
| InternerFehler | Interner Fehler. |
| UngültigeAnfrage | Die Anfrage enthält nicht die erforderlichen Informationen oder hat fehlerhafte Informationen. |
| DataStructureItemsOverLimit | Überschreitet die Anzahl der Elemente im Datenstrukturlevel (1M). |
| KeinElementGefunden | Kein Element in MemoryStoreQueue:ReadAsync() oder MemoryStoreSortedMap:UpdateAsync() gefunden. ReadAsync() pollt alle 2 Sekunden und gibt diesen Statuscode zurück, bis es Elemente in der Warteschlange findet. |
| DataStructureRequestsOverLimit | Überschreitet die Anfrageeinheitgrenze auf Datenstrukturebene (100.000 Anfrageeinheiten pro Minute). |
| PartitionRequestsOverLimit | Überschreitet die Partition-Anfrageeinheitgrenze. |
| GesamtAnfragenÜberLimit | Überschreitet die Anfrageeinheitgrenze auf Universumsebene. |
| GesamtSpeicherÜberLimit | Überschreitet das Speicherquotenlimit auf Universumsebene. |
| ElementWertGrößeZuGroß | Wertgröße überschreitet das Limit (32KB). |
Die folgende Tabelle listet Statuscodes von der Clientseite auf, die derzeit nicht im Überwachungs-Dashboard verfügbar sind.
| Statuscode | Beschreibung |
|---|---|
| InternerFehler | Interner Fehler. |
| UnveröffentlichtenPlatz | Sie müssen diesen Platz veröffentlichen, um MemoryStoreService verwenden zu können. |
| UngültigerClientZugriff | MemoryStoreService muss vom Server aus aufgerufen werden. |
| UngültigeAblaufzeit | Das Feld 'Ablaufzeit' muss zwischen 0 und 3.888.000 liegen. |
| UngültigeAnfrage | Wert kann nicht in json konvertiert werden. |
| UngültigeAnfrage | SortKey kann nicht in eine gültige Zahl oder Zeichenfolge konvertiert werden. |
| TransformCallbackFehlgeschlagen | Die Transformation Callback-Funktion konnte nicht aufgerufen werden. |
| AnfrageDrosselung | Neueste Anfragen an Speicher für Daten haben eines oder mehrere Limits erreicht. |
| AktualisierungsKonflikt | Maximale Anzahl an Wiederholungen überschritten. |
Fehlerbehebung
Die folgende Tabelle listet die empfohlenen Lösungen für jeden Antwortstatuscode auf:
| Fehler | Fehlerbehebungsoptionen |
|---|---|
| DataStructureRequestsOverLimit / PartitionRequestsOverLimit |
|
| GesamtAnfragenÜberLimit | |
| DataStructureItemsOverLimit |
|
| DataStructureMemoryOverLimit | |
| GesamtSpeicherÜberLimit | |
| DataUpdateConflict |
|
| Interner Fehler |
|
| Ungültige Anfrage |
|
| ElementWertGrößeZuGroß |
|
Testen und Debuggen im Studio
Die Daten in MemoryStoreService sind zwischen Studio und Produktion isoliert, sodass Änderungen an den Daten im Studio das Produktionsverhalten nicht beeinflussen. Das bedeutet, dass Ihre API-Aufrufe aus dem Studio nicht auf Produktionsdaten zugreifen, was es Ihnen ermöglicht, Speicher für Daten und neue Funktionen sicher zu testen, bevor Sie in die Produktion gehen.
Die Tests im Studio haben die gleichen Grenzen und Quoten wie die Produktion. Bei Quoten, die auf der Anzahl der Benutzer basieren, kann das resultierende Kontingent sehr klein sein, da Sie der einzige Benutzer bei den Tests im Studio sind. Wenn Sie aus dem Studio testen, könnten Sie auch eine leicht höhere Latenz und erhöhte Fehlerquoten bemerken im Vergleich zur Verwendung in der Produktion, da einige zusätzliche Prüfungen durchgeführt werden, um den Zugriff und die Berechtigungen zu überprüfen.
Für Informationen, wie Sie einen Speicher für Daten in Live-Spielen oder beim Testen im Studio debuggen, verwenden Sie die Entwicklerkonsole.