MemoryStoreService 是一個高吞吐量和低延遲的數據服務,提供快速的內存數據儲存,所有伺服器在實時會話中均可訪問。記憶體儲存 適合於頻繁且短暫的數據,這些數據變化迅速且不需要持久性,因為它們的訪問速度更快,並在達到最大壽命時消失。對於需要在會話之間持久化的數據,請使用 數據儲存。
數據結構
記憶體儲存有三種原始數據結構,這些結構在伺服器之間共享以便快速處理,而不是直接訪問原始數據:排序映射、隊列 和 哈希映射。每種數據結構都適合某些用例:
- 基於技能的配對 - 在伺服器之間的共享 隊列 中保存用戶信息,例如技能等級,並使用大廳伺服器定期進行配對。
- 跨伺服器交易和拍賣 - 允許不同伺服器之間的通用交易,用戶可以對實時變化的價格項目進行競標,使用 排序映射 的鍵值對。
- 全球排行榜 - 在共享的 排序映射 中存儲和更新用戶排名。
- 共享庫存 - 在共享的 哈希映射 中保存庫存項目和統計數據,用戶可以同時使用庫存項目。
- 持久數據的緩存 - 將您的持久數據同步並複製到可以作為緩存的記憶體儲存 哈希映射 中,以提高遊戲性能。
一般來說,如果您需要根據特定鍵訪問數據,請使用哈希映射。如果您需要數據有序,請使用排序映射。如果您需要以特定順序處理數據,請使用隊列。
限制和配額
為了維持可擴展性和系統性能,記憶體儲存對內存大小、API 請求和數據結構大小有數據使用配額。
記憶體儲存有一個基於過期時間的驅逐策略,也稱為生存時間(TTL)。項目在過期後被驅逐,並為新條目釋放內存配額。當您達到內存限制時,所有後續寫入請求將失敗,直到項目過期或您手動刪除它們。
內存大小配額
內存配額限制遊戲可以消耗的總內存量。這不是固定值;而是根據遊戲中的用戶數量隨時間變化,根據公式 64 KB + 1.2 KB * [用戶數量]。該配額適用於遊戲級別,而不是伺服器級別。
當用戶加入遊戲時,額外的內存配額會立即可用。當用戶離開遊戲時,配額不會立即減少。配額在八天的回溯期後重新評估為較低的值。
當您的遊戲達到內存大小配額後,任何增加內存大小的 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 狀態的請求 圖表中找到的所有狀態代碼及其描述。要了解如何解決這些錯誤,請參見 故障排除。有關錯誤所涉及的具體配額或限制,請參見 限制和配額。
| 狀態代碼 | 描述 |
|---|---|
| 成功 | 成功。 |
| DataStructureMemoryOverLimit | 超過數據結構級別內存大小限制(100 MB)。 |
| DataUpdateConflict | 由於並發更新而發生衝突。 |
| AccessDenied | 未經授權訪問遊戲數據。此請求不消耗請求單位或使用配額。 |
| InternalError | 內部錯誤。 |
| InvalidRequest | 請求缺少所需信息或信息格式錯誤。 |
| DataStructureItemsOverLimit | 超過數據結構級別項目數量限制(1M)。 |
| NoItemFound | 在 MemoryStoreQueue:ReadAsync() 或 MemoryStoreSortedMap:UpdateAsync() 中未找到項目。ReadAsync() 每 2 秒輪詢一次,並在找到隊列中的項目之前返回此狀態代碼。 |
| DataStructureRequestsOverLimit | 超過數據結構級別請求單位限制(每分鐘 100,000 請求單位)。 |
| PartitionRequestsOverLimit | 超過分區請求單位限制。 |
| TotalRequestsOverLimit | 超過宇宙級別請求單位限制。 |
| TotalMemoryOverLimit | 超過宇宙級別內存配額。 |
| ItemValueSizeTooLarge | 值大小超過限制(32 KB)。 |
以下表格列出了客戶端的狀態代碼,這些代碼目前在可觀察性儀表板上不可用。
| 狀態代碼 | 描述 |
|---|---|
| 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 測試中調試記憶體儲存的信息,請使用 開發者控制台。