MemoryStoreService to usługa danych o wysokiej przepustowości i niskim opóźnieniu, która zapewnia szybkie przechowywanie danych w pamięci dostępne ze wszystkich serwerów w aktywnej sesji. Pamięciowe magazyny są odpowiednie dla częstych i efemerycznych danych, które szybko się zmieniają i nie muszą być trwałe, ponieważ są szybsze w dostępie i znikają po osiągnięciu maksymalnego czasu życia. W przypadku danych, które muszą być trwałe między sesjami, użyj magazynów danych.
Struktury danych
Zamiast bezpośrednio uzyskiwać dostęp do surowych danych, pamięciowe magazyny mają trzy podstawowe struktury danych współdzielone między serwerami w celu szybkiego przetwarzania: posortowana mapa, kolejka i mapa haszująca. Każda struktura danych jest dobrze dopasowana do określonych przypadków użycia:
- Dopasowywanie oparte na umiejętnościach - Zapisz informacje o użytkownikach, takie jak poziom umiejętności, w współdzielonej kolejce między serwerami i użyj serwerów lobby do okresowego przeprowadzania dopasowań.
- Handel i aukcje między serwerami - Umożliw uniwersalny handel między różnymi serwerami, gdzie użytkownicy mogą licytować przedmioty z cenami zmieniającymi się w czasie rzeczywistym, z posortowaną mapą par klucz-wartość.
- Globalne rankingi - Przechowuj i aktualizuj rankingi użytkowników na współdzielonej tablicy wyników w posortowanej mapie.
- Wspólne inwentarze - Zapisz przedmioty inwentarza i statystyki w współdzielonej mapie haszującej, gdzie użytkownicy mogą jednocześnie korzystać z przedmiotów inwentarza.
- Cache dla danych trwałych - Synchronizuj i kopiuj swoje trwałe dane w magazynie danych do pamięciowej mapy haszującej, która może działać jako cache i poprawić wydajność twojej gry.
Ogólnie, jeśli potrzebujesz uzyskać dostęp do danych na podstawie konkretnego klucza, użyj mapy haszującej. Jeśli potrzebujesz, aby te dane były uporządkowane, użyj posortowanej mapy. Jeśli potrzebujesz przetwarzać swoje dane w określonej kolejności, użyj kolejki.
Limity i kwoty
Aby utrzymać skalowalność i wydajność systemu, pamięciowe magazyny mają kwoty użycia danych dla rozmiaru pamięci, żądań API i rozmiaru struktury danych.
Pamięciowe magazyny mają politykę usuwania opartą na czasie wygaśnięcia, znaną również jako czas życia (TTL). Przedmioty są usuwane po wygaśnięciu, a kwota pamięci jest zwalniana dla nowych wpisów. Gdy osiągniesz limit pamięci, wszystkie kolejne żądania zapisu nie powiodą się, aż przedmioty wygaśnie lub ręcznie je usuniesz.
Kwota rozmiaru pamięci
Kwota pamięci ogranicza całkowitą ilość pamięci, którą gra może zużywać. Nie jest to stała wartość; zamiast tego zmienia się w czasie w zależności od liczby użytkowników w grze zgodnie z formułą 64 KB + 1.2 KB * [liczba użytkowników]. Kwota dotyczy poziomu gry, a nie poziomu serwera.
Gdy użytkownicy dołączają do gry, dodatkowa kwota pamięci jest dostępna natychmiast. Gdy użytkownicy opuszczają grę, kwota nie zmniejsza się natychmiast. Istnieje okres śledzenia wynoszący osiem dni, zanim kwota zostanie ponownie oceniona na niższą wartość.
Po osiągnięciu limitu rozmiaru pamięci w twojej grze, wszelkie żądania API, które zwiększają rozmiar pamięci, zawsze się nie powiodą. Żądania, które zmniejszają lub nie zmieniają rozmiaru pamięci, nadal będą się powodzić.
Dzięki pulpitowi obserwowalności możesz w czasie rzeczywistym przeglądać kwotę rozmiaru pamięci swojej gry za pomocą wykresu Użycie pamięci.
Limity żądań API
Kwota jednostek żądań dotyczy wszystkich wywołań API MemoryStoreService. Ta kwota wynosi 1000 + 120 * [liczba jednoczesnych użytkowników] jednostek żądań na minutę.
Większość wywołań API zużywa tylko jedną jednostkę żądania, z kilkoma wyjątkami:
MemoryStoreSortedMap:GetRangeAsync()
Zużywa jednostki w zależności od liczby zwróconych przedmiotów. Na przykład, jeśli ta metoda zwraca 10 przedmiotów, wywołanie liczy się jako 10 jednostek żądań. Jeśli zwraca pustą odpowiedź, liczy się jako jedna jednostka żądania.
Zużywa jednostki w zależności od liczby zwróconych przedmiotów, podobnie jak MemoryStoreSortedMap:GetRangeAsync(), ale zużywa dodatkową jednostkę co dwie sekundy podczas odczytu. Określ maksymalny czas odczytu za pomocą parametru waitTimeout.
MemoryStoreHashMap:UpdateAsync()
Zużywa minimum dwie jednostki.
MemoryStoreHashMap:ListItemsAsync()
Zużywa [liczba partycji skanowanych] + [przedmioty zwrócone] jednostek.
Kwota żądań jest również stosowana na poziomie gry, a nie na poziomie serwera. Zapewnia to elastyczność w alokacji żądań między serwerami, o ile całkowita szybkość żądań nie przekracza kwoty. Jeśli przekroczysz kwotę, otrzymasz odpowiedź o błędzie, gdy usługa ograniczy twoje żądania.
Dzięki funkcji obserwowalności możesz w czasie rzeczywistym przeglądać kwotę jednostek żądań swojej gry.
Limity rozmiaru struktury danych
Dla pojedynczej posortowanej mapy lub kolejki obowiązują następujące limity rozmiaru i liczby przedmiotów:
- Maksymalna liczba przedmiotów: 1,000,000
- Maksymalny całkowity rozmiar (w tym klucze dla posortowanej mapy): 100 MB
Limity na partycję
Zobacz limity na partycję.
Najlepsze praktyki
Aby utrzymać optymalny wzór użycia pamięci i uniknąć osiągnięcia limitów, stosuj się do tych najlepszych praktyk:
Usuwaj przetworzone przedmioty. Regularne czyszczenie odczytanych przedmiotów za pomocą metody MemoryStoreQueue:RemoveAsync() dla kolejek i MemoryStoreSortedMap:RemoveAsync() dla posortowanych map może zwolnić pamięć i utrzymać strukturę danych na bieżąco.
Ustaw czas wygaśnięcia na jak najkrótszy czas podczas dodawania danych. Chociaż domyślny czas wygaśnięcia wynosi 45 dni zarówno dla MemoryStoreQueue:AddAsync(), jak i MemoryStoreSortedMap:SetAsync(), ustawienie najkrótszego możliwego czasu może automatycznie oczyścić stare dane, aby zapobiec ich zapełnieniu twojej kwoty użycia pamięci.
- Nie przechowuj dużej ilości danych z długim czasem wygaśnięcia, ponieważ ryzykujesz przekroczenie swojej kwoty pamięci i potencjalnie spowodowanie problemów, które mogą zniszczyć całą twoją grę.
- Zawsze albo jawnie usuwaj niepotrzebne przedmioty, albo ustaw krótki czas wygaśnięcia przedmiotu.
- Ogólnie rzecz biorąc, powinieneś używać jawnego usuwania do zwalniania pamięci, a wygaśnięcia przedmiotów jako mechanizmu zabezpieczającego, aby zapobiec zajmowaniu pamięci przez nieużywane przedmioty przez dłuższy czas.
Przechowuj w pamięci tylko niezbędne wartości.
Na przykład, w grze o aukcjach, musisz tylko utrzymywać najwyższą ofertę. Możesz użyć MemoryStoreSortedMap:UpdateAsync() na jednym kluczu, aby utrzymać najwyższą ofertę, zamiast przechowywać wszystkie oferty w swojej strukturze danych.
Użyj ekspansywnego opóźnienia, aby pomóc pozostać poniżej limitów żądań API.
Na przykład, jeśli otrzymasz DataUpdateConflict, możesz spróbować ponownie po dwóch sekundach, potem czterech, ośmiu itd., zamiast ciągle wysyłać żądania do MemoryStoreService, aby uzyskać poprawną odpowiedź.
Podziel ogromne struktury danych na mniejsze, stosując sharding.
Często łatwiej jest zarządzać danymi w mniejszych strukturach niż przechowywać wszystko w jednej dużej strukturze danych. To podejście może również pomóc uniknąć limitów użycia i szybkości. Na przykład, jeśli masz posortowaną mapę, która używa prefiksów dla swoich kluczy, rozważ oddzielenie każdego prefiksu do własnej posortowanej mapy. W przypadku szczególnie popularnej gry możesz nawet podzielić użytkowników na wiele map w oparciu o ostatnie cyfry ich identyfikatorów użytkowników.
Shard często dostępne klucze w mapach haszujących z wieloma kopiami klucza, aby rozłożyć obciążenie.
Kompresuj przechowywane wartości.
Na przykład, rozważ użycie algorytmu LZW do zmniejszenia rozmiaru przechowywanych wartości.
Zapisz się do Rozszerzonych Usług.
Możesz zwiększyć swoje limity przechowywania i żądań, przystępując do Rozszerzonych Usług.
Obserwowalność
Pulpit Obserwowalności zapewnia wgląd i analizy do monitorowania i rozwiązywania problemów z użyciem twojego magazynu pamięci. Dzięki wykresom aktualizowanym w czasie rzeczywistym na różnych aspektach użycia pamięci i żądań API możesz śledzić wzór użycia pamięci swojej gry, przeglądać aktualnie przydzielone kwoty, monitorować status API i identyfikować potencjalne problemy w celu optymalizacji wydajności.
Poniższa tabela wymienia i opisuje wszystkie kody statusu odpowiedzi API dostępne na wykresach Liczba żądań według statusu i Żądania według API x Status na Pulpicie Obserwowalności. Aby uzyskać więcej informacji na temat rozwiązywania tych błędów, zobacz Rozwiązywanie problemów. Aby uzyskać szczegółową kwotę lub limit, do którego odnosi się błąd, zobacz Limity i kwoty.
| Kod statusu | Opis |
|---|---|
| Sukces | Sukces. |
| DataStructureMemoryOverLimit | Przekracza limit rozmiaru pamięci na poziomie struktury danych (100 MB). |
| DataUpdateConflict | Konflikt z powodu równoczesnej aktualizacji. |
| AccessDenied | Brak uprawnień do dostępu do danych gry. To żądanie nie zużywa jednostek żądań ani nie wykorzystuje kwoty. |
| Błąd wewnętrzny | Błąd wewnętrzny. |
| InvalidRequest | Żądanie nie zawiera wymaganych informacji lub zawiera błędne informacje. |
| DataStructureItemsOverLimit | Przekracza limit liczby przedmiotów na poziomie struktury danych (1M). |
| NoItemFound | Nie znaleziono przedmiotu w MemoryStoreQueue:ReadAsync() lub MemoryStoreSortedMap:UpdateAsync(). ReadAsync() sprawdza co 2 sekundy i zwraca ten kod statusu, aż znajdzie przedmioty w kolejce. |
| DataStructureRequestsOverLimit | Przekracza limit jednostek żądań na poziomie struktury danych (100,000 jednostek żądań na minutę). |
| PartitionRequestsOverLimit | Przekracza limit jednostek żądań na partycję. |
| TotalRequestsOverLimit | Przekracza limit jednostek żądań na poziomie uniwersum. |
| TotalMemoryOverLimit | Przekracza limit kwoty pamięci na poziomie uniwersum. |
| ItemValueSizeTooLarge | Rozmiar wartości przekracza limit (32 KB). |
Poniższa tabela wymienia kody statusu z strony klienta, które obecnie nie są dostępne na Pulpicie Obserwowalności.
| Kod statusu | Opis |
|---|---|
| Błąd wewnętrzny | Błąd wewnętrzny. |
| UnpublishedPlace | Musisz opublikować to miejsce, aby używać MemoryStoreService. |
| InvalidClientAccess | MemoryStoreService musi być wywoływane z serwera. |
| InvalidExpirationTime | Pole 'expiration' musi być między 0 a 3,888,000. |
| InvalidRequest | Nie można przekonwertować wartości na json. |
| InvalidRequest | Nie można przekonwertować sortKey na prawidłową liczbę lub ciąg. |
| TransformCallbackFailed | Nie udało się wywołać funkcji zwrotnej transformacji. |
| RequestThrottled | Ostatnie żądania MemoryStores osiągnęły jeden lub więcej limitów. |
| UpdateConflict | Przekroczono maksymalną liczbę prób. |
Rozwiązywanie problemów
Poniższa tabela wymienia i opisuje zalecane rozwiązanie dla każdego kodu statusu odpowiedzi:
| Błąd | Opcje rozwiązywania problemów |
|---|---|
| DataStructureRequestsOverLimit / PartitionRequestsOverLimit |
|
| TotalRequestsOverLimit | |
| DataStructureItemsOverLimit |
|
| DataStructureMemoryOverLimit | |
| TotalMemoryOverLimit | |
| DataUpdateConflict |
Przykład przerywania żądania |
| Błąd wewnętrzny |
|
| InvalidRequest |
|
| ItemValueSizeTooLarge |
|
Testowanie i debugowanie w Studio
Dane w MemoryStoreService są izolowane między Studio a produkcją, więc zmiana danych w Studio nie wpływa na zachowanie produkcji. Oznacza to, że twoje wywołania API z Studio nie uzyskują dostępu do danych produkcyjnych, co pozwala na bezpieczne testowanie pamięciowych magazynów i nowych funkcji przed przejściem do produkcji.
Testowanie w Studio ma te same limity i kwoty co produkcja. W przypadku kwot obliczanych na podstawie liczby użytkowników, wynikowa kwota może być bardzo mała, ponieważ jesteś jedynym użytkownikiem podczas testowania w Studio. Podczas testowania z poziomu Studio możesz również zauważyć nieco wyższe opóźnienia i podwyższone wskaźniki błędów w porównaniu do użycia w produkcji z powodu dodatkowych kontroli, które są wykonywane w celu weryfikacji dostępu i uprawnień.
Aby uzyskać informacje na temat debugowania magazynu pamięci w grach na żywo lub podczas testowania w studio, użyj Konsoli dewelopera.