MemoryStoreService 是一個高吞吐量和低延遲的資料服務,提供可從所有伺服器訪問的快速記憶體儲存。在所有活動會話中,記憶體儲存 適合於頻繁且瞬息萬變的資料,這些資料不需要持久性,因為它們的存取速度更快,並且在達到最大生命週期時會消失。對於需要在會話之間持久化的資料,請使用 資料儲存。
資料結構
記憶體儲存不直接訪問原始資料,而是有三種在伺服器之間共享的原始資料結構,以便快速處理:排序映射、佇列 和 雜湊映射。每種資料結構都適合某些特定的用例:
- 技能匹配 - 在伺服器之間使用共享 佇列 保存用戶信息,如技能等級,並使用大廳伺服器定期運行匹配。
- 伺服器之間交易和拍賣 - 在不同伺服器之間啟用普遍交易,使用具有實時變化價格的鍵值對的 排序映射 來出價。
- 全球排行榜 - 在共享的 排序映射 中存儲和更新用戶排名。
- 共享物品清單 - 在共享的 雜湊映射 中保存物品及統計資料,用戶可以同時使用彼此的物品。
- 持久資料的快取 - 將您的持久資料在資料儲存中同步並複製到記憶體儲存 雜湊映射 中,該映射可作為快取並改善您的遊戲性能。
一般來說,如果您需要根據特定鍵訪問資料,請使用雜湊映射。如果您需要資料按順序排列,請使用排序映射。如果您需要以特定順序處理資料,請使用佇列。
限制與配額
為了維持可擴展性和系統性能,記憶體儲存對記憶體大小、API 請求和資料結構大小設有限制。
記憶體儲存有基於過期時間的驅逐政策,也稱為生命週期 (TTL)。項目在過期後被驅逐,之後記憶體配額會釋放出來以容納新條目。當您達到記憶體限制時,所有後續的寫入請求會失敗,直到項目過期或您手動刪除它們。
記憶體大小配額
記憶體配額限制了一個遊戲可以消耗的記憶體總量。這不是固定值,而是根據遊戲中的用戶數量隨時間變化,根據公式 64KB + 1.2KB * [用戶數量] 計算。該配額是在遊戲層級上應用,而不是伺服器層級。
當用戶加入遊戲時,額外的記憶體配額會立即可用。當用戶離開遊戲時,配額不會立即減少。在配額重新評估為較低值之前,會有八天的追溯期。
當您的遊戲達到記憶體大小限制時,任何增加記憶體大小的 API 請求都會失敗。減少或不變更記憶體大小的請求仍會成功。
透過 可觀察性 儀表板,您可以實時查看遊戲的記憶體大小配額,使用 記憶體使用情況 圖表。
API 請求限制
所有 MemoryStoreService API 調用將應用 請求單元 配額,每分鐘 1000 + 120 * [同時用戶數] 的請求單位。
大多數 API 調用只消耗一個請求單元,只有少數例外:
MemoryStoreSortedMap:GetRangeAsync()
根據返回的項目數消耗單位。例如,如果這個方法返回 10 項,則該調用計算為 10 個請求單位。如果返回空回應,則計算為一個請求單位。
根據返回的項目數消耗單位,就像 MemoryStoreSortedMap:GetRangeAsync() 一樣,但在讀取時每兩秒消耗額外的單位。用 waitTimeout 參數指定最大讀取時間。
MemoryStoreHashMap:UpdateAsync()
消耗最少兩個單位。
MemoryStoreHashMap:ListItemsAsync()
消耗 [掃描到的分區數] + [返回的項目數] 單位。
請求配額同樣適用於遊戲層級,而不是伺服器層級。這提供了靈活性,只要總請求速率不超過配額,就可以在伺服器之間分配請求。如果您超過了配額,服務將限流,並在請求時返回錯誤響應。
通過可用的 可觀察性 功能,您可以實時查看遊戲的請求單位配額。
資料結構大小限制
對於單個排序映射或佇列,適用以下大小和項目數限制:
- 最大項目數:1,000,000
- 最大總大小(包括排序映射的鍵):100 MB
每分區限制
請參見 每分區限制。
最佳實踐
為了保持記憶體使用模式最佳,並避免觸發 限制,請遵循以下最佳實踐:
刪除已處理的項目。 持續使用 MemoryStoreQueue:RemoveAsync() 方法清理佇列的讀取項目,並使用 MemoryStoreSortedMap:RemoveAsync() 清理排序映射,可以釋放記憶體並保持資料結構的最新。
在添加資料時將過期時間設置為可能的最短時間。 雖然 MemoryStoreQueue:AddAsync() 和 MemoryStoreSortedMap:SetAsync() 的默認過期時間均為 45 天,但設置最短時間可以自動清理舊資料,以防止它們填滿您的記憶體使用配額。
- 不要存儲大量資料及長時間過期,因為這風險超過您的記憶體配額,並可能導致問題破壞整個遊戲。
- 始終要明確刪除不需要的項目,或設置短期項目過期時間。
- 通常,您應使用明確刪除來釋放記憶體,而使用項目過期作為安全機制,以防未使用的項目長時間佔據記憶體。
僅在記憶體中保留必要的值。
例如,對於拍賣行遊戲,您只需維護最高出價。您可以在一個鍵上使用 MemoryStoreSortedMap:UpdateAsync() 來保持最高出價,而不是在資料結構中保留所有出價。
使用 指數退避 來幫助保持在 API 請求限制之下。
例如,如果您收到 DataUpdateConflict,可以在兩秒後重試,然後是四秒、八秒等,而不是持續向 MemoryStoreService 發送請求以獲得正確的回應。
通過 分片 將巨大的資料結構拆分為多個較小的結構。
通常,在較小的結構中管理資料更容易,而不是將所有內容存儲在一個大型資料結構中。這種方法也有助於避免使用和速率限制。例如,如果您有一個使用前綴作為鍵的排序映射,考慮將每個前綴分開為自己的排序映射。對於特別受歡迎的遊戲,您甚至可以根據用戶 ID 的最後幾位數字將用戶分成多個映射。
分片 在雜湊映射中經常訪問的鍵,使用多個相同的鍵以分散負載。
壓縮儲存的值。
例如,考慮使用 LZW 算法來減小儲存值的大小。
註冊擴展服務。
您可以通過註冊 擴展服務 來增加儲存和請求限制配額。
可觀察性
可觀察性儀表板 提供有關監控和故障排除記憶體儲存使用情況的見解和分析。通過實時更新不同方面的記憶體使用和 API 請求的圖表,您可以跟踪遊戲的記憶體使用模式,查看當前已分配的配額,監控 API 狀態,並識別潛在的性能優化問題。
以下表格列出了所有可在可觀察性儀表板的 根據狀態的請求數量 和 根據 API x 狀態的請求 圖表中找到的 API 響應的狀態碼及描述。如需了解如何解決這些錯誤的更多信息,請參見 故障排除。有關錯誤所涉及的具體配額或限制,請參見 限制與配額。
| 狀態碼 | 描述 |
|---|---|
| 成功 | 成功。 |
| DataStructureMemoryOverLimit | 超過資料結構層級記憶體大小限制 (100MB)。 |
| DataUpdateConflict | 由於同時更新而產生衝突。 |
| AccessDenied | 未經授權訪問遊戲資料。該請求不消耗請求單位或使用配額。 |
| InternalError | 內部錯誤。 |
| InvalidRequest | 請求沒有所需的信息或信息格式錯誤。 |
| DataStructureItemsOverLimit | 超過資料結構層級項目數限制 (1M)。 |
| NoItemFound | 在 MemoryStoreQueue:ReadAsync() 或 MemoryStoreSortedMap:UpdateAsync() 中未找到項目。ReadAsync() 每 2 秒輪詢一次,直到找到佇列中的項目為止,則返回此狀態碼。 |
| DataStructureRequestsOverLimit | 超過資料結構層級請求單位限制 (每分鐘 100,000 請求單位)。 |
| PartitionRequestsOverLimit | 超過分區請求單位限制。 |
| TotalRequestsOverLimit | 超過宇宙級請求單位限制。 |
| TotalMemoryOverLimit | 超過宇宙級記憶體配額。 |
| ItemValueSizeTooLarge | 值大小超過限制 (32KB)。 |
以下表格列出了來自客戶端的狀態碼,這些狀態碼目前在可觀察性儀表板上不可用。
| 狀態碼 | 描述 |
|---|---|
| InternalError | 內部錯誤。 |
| UnpublishedPlace | 您必須發佈此地點以使用 MemoryStoreService。 |
| InvalidClientAccess | MemoryStoreService 必須從伺服器調用。 |
| InvalidExpirationTime | 欄位 'expiration' 時間必須在 0 和 3,888,000 之間。 |
| InvalidRequest | 無法將值轉換為 json。 |
| InvalidRequest | 無法將 sortKey 轉換為有效的數字或字符串。 |
| TransformCallbackFailed | 無法調用轉換回調函數。 |
| RequestThrottled | 最近的 MemoryStores 請求達到一個或多個限制。 |
| UpdateConflict | 超過最大重試次數。 |
故障排除
以下表格列出了每個響應狀態碼的建議解決方案:
| 錯誤 | 故障排除選項 |
|---|---|
| DataStructureRequestsOverLimit / PartitionRequestsOverLimit |
|
| TotalRequestsOverLimit | |
| DataStructureItemsOverLimit |
|
| DataStructureMemoryOverLimit | |
| TotalMemoryOverLimit | |
| DataUpdateConflict |
|
| 內部錯誤 |
|
| InvalidRequest |
|
| ItemValueSizeTooLarge |
|
在 Studio 測試和除錯
MemoryStoreService 中的資料在 Studio 和生產環境之間是隔離的,因此在 Studio 中更改資料不會影響生產行為。這意味著您在 Studio 的 API 調用不會訪問生產資料,允許您安全地測試記憶體儲存和新功能,然後再進入生產環境。
Studio 測試具有與生產相同的 限制與配額。對於根據用戶數計算的配額,結果可能非常小,因為您是唯一的 Studio 測試用戶。當從 Studio 進行測試時,您可能還會注意到稍微較高的延遲,以及相較於生產環境使用情況,錯誤率的升高,這是由于為了驗證訪問和權限而進行的某些額外檢查。
有關如何在活動遊戲或在 Studio 測試時除錯記憶體儲存的資訊,請使用 開發者控制台。