MemoryStoreService 是一个高性能和低延迟的数据服务,提供快速的内存数据存储可以从所有服务器在实时会话中访问。 内存存储 适合快速更新和不需要持续的数据,因为它们在最大寿命时更快访问和消失,因此在会话之间使用 数据存储</
数据结构
而不是直接访问原始数据,记忆存储有三种原始数据结构在服务器之间共享,以便进行快速处理:排序地图、队列和哈希地图。每种数据结构都有适合某些使用场景的好用例子:
- 基于技能的匹配 - 保存用户信息,例如技能等级,在共享 队列 中,并使用大厅服务器来定期运行匹配。
- 跨服务器交易和拍卖 - 启用在不同服务器之间的“实时交易”,用户可以在具有实时价格变化的物品上 bid,并且使用 排序 的钥匙值对子组合。
- 全球排行榜 - 在排序地图内的共享排行榜上存储和更新用户排名。
- 共享库存 - 保存库存物品和统计数据在共享 哈希地图 中,用户可以同时使用库存物品。
- 为持久数据缓存 - 在数据存储中同步并复制你的持久数据到内存存储 hash map ,可以作为缓存使用,并提高您的体验性能。
一通用来说,如果您需要按特定键访问数据,请使用哈希地图。 如果您需要顺序访问数据,请使用排序地图。 如果您需要处理您的数据以特定顺序,请使用队列。
限制和配额
为了确保可扩展性和系统性能,存储器的内存有数据使用率限制,用于存储大小、API 请求和数据结构大小。
存储器的驱逐政策基于过期时间,也称为生存时间 (TTL)。它们在过期后被驱逐,并且存储器的存储空间为新入口。当您击中内存上限时,所有后续的写入请求都会失败,直到它们过期或您手动删除它们。
内存大小 quota
内存 quota 限制体验可以消耗的总内存量。它不是固定值。相反,它随着时间的推移而改变。根据以下公式: 64KB + 1KB * [用户数] 。内容量适用于体验级别,而不是服务器等级别。
当用户加入体验时,额外的内存 quota 可立即使用。当用户离开体验时,quota 不会立即减少。在 quota 重新评估为低值之前,有八天的追踪期。
您的体验触发记忆体容量上限时,无论API请求是否增加记忆体容量,它们都会失败。不过,减少或不更改记忆体容量的请求仍然会成功。
使用可观察性仪表板,您可以使用 记忆使用 图表实时查看您的体验的内存大小。
API 请求限制
对于 API 请求限制,有一个 请求单元 quota 适用于所有 MemoryStoreService API 调用。 quota 是 1000 + 100 * [number of concurrent users] 请求单位每分钟。
大多数 API 调用只会消耗一个请求单位,但有几个例外:
MemoryStoreSortedMap:GetRangeAsync()
根据返回的物品数量进行单位消耗。例如,如果此方法返回 10 个物品,调用将计为 10 个请求单位。如果返回空的响应,将计为一个请求单位。
根据返回的项目数量进行单元消耗,就像 MemoryStoreSortedMap:GetRangeAsync() ,但在读取时每两秒消耗额外的单元。 指定 waitTimeout 参数。
MemoryStoreHashMap:UpdateAsync()
消耗最少两个单位。
MemoryStoreHashMap:ListItemsAsync()
消耗 [分区扫描数] + [返回的物品] 单位。
体验级别还在服务器级别而不是服务器等级别上应用请求上限。这提供了灵活性来在服务器之间分配请求,总请求率不超过上限。如果您超过上限,您将收到错误响应,当服务器减速您的请求。
使用可用的可观察性功能,您可以实时查看您的体验的请求单位 quota。
数据结构大小限制
对于单个排序的地图或队列,以下尺寸和物品数量限制适用:
- 最大物品数量: 1,000,000
- 最大总体 size (包括排序地图的钥匙):100 MB
每个分区限制
最佳实践
要确保您的内存使用模式最佳,并避免击打限制,请遵循以下最佳实践:
移除处理的物品。 使用 MemoryStoreQueue:RemoveAsync() 方法清洁地清除队列上的读取物品,并使用 MemoryStoreSortedMap:RemoveAsync() 方法清洁排序的地图可以释放内存并保持数据结构的更新。
在添加数据时将过期时间设置为最小的时间框。 尽管默认过期时间为 45 天为 both MemoryStoreQueue:AddAsync() 和 MemoryStoreSortedMap:SetAsync() , 设置最短的时间可以自动清理旧数据以防止它们填充您的内存使用率。
- 不要存储大量数据,因为它会超过您的内存 quota,并且可能会导致可能会导致问题,会导致您的整个体验。
- 总是删除不需要的项目或设置一个短项目的过期。
- 一般来说,你应该使用明确的删除来释放内存和物品过期作为安全机制,以防止未使用的物品占用内存,从而导致更长时间的使用不可用的物品。
只需要在内存中保存必要的值。
例如,对于拍卖体验,您只需要维持最高拍卖。您可以使用 MemoryStoreQueue:UpdateAsync() 在一个键上使用,以保持最高拍卖而不是保留所有拍卖在您的数据结构中。
使用 倍数后退 来帮助您保持在 API 请求限制下。
例如,如果您收到了一个 DataUpdateConflict ,您可以在两秒后重试,然后四,八等等,而不是一直发送请求到 2>Class.MemoryStoreService2> 以获得正确的回应。
使用 分段 将巨数据结构拆分为多个更小的结构。
管理数据通常更容易在较小的结构中管理数据,而不是将数据存储在一个大的数据结构中。此方法还可以帮助避免使用和率限制。例如,如果您有使用前缀为其键的排序地图,请考虑将每个前缀分离为其自己的排序地图。对于特别受欢迎的体验,您甚至可以根据用户的用户 ID 的最后几位数分离用户。
压缩存储的值。
例如,请考虑使用 LZW 算法来减少存储值的大小。
可观察性
观察性仪表板 为您的内存存储使用提供洞察和分析。通过在不同方面的实时更新图表上实时更新图表,您可以跟踪您的内存使用率,查看当前分配的 quotas,监控 API 状态,并识别可能影响性能优化的潜在问题。
下表列出和描述 API 响应可用在可见度仪表板的 请求数量按状态 和 请求 API x 状态 图形中的所有状态代码。有关解决这些错误的更多信息,请参阅 排查 。有关特定 quota 或限制错误的详细信息,请参阅 1>限制1> 。
状态代码 | 描述 |
---|---|
成功 | 成功。 |
数据结构存储限制 | 超过了数据结构级别内存大小限制(100MB)。 |
数据更新冲突 | 因同时更新而导致冲突。 |
访问被拒绝 | 无权访问体验数据。此请求不会消耗请求单位或使用额外的 quota。 |
内部错误 | 内部错误。 |
无效请求 | 请求没有要求必要信息或有不正确的信息。 |
数据结构项目超限 | 超过了数据结构级别物品数量限制(1M)。 |
未找到物品 | 在 MemoryStoreQueue:ReadAsync() 或 MemoryStoreSortedMap:UpdateAsync() 中找不到项目。 ReadAsync() 每 2 秒进行调用,直到它在队列中找到项目。 |
数据结构请求限制 | 超过了数据结构级别请求限制(每分钟 100,000 个请求单位)。 |
分区请求超限 | 超过了分区请求单位限制。 |
总请求超限 | 超过宇宙级请求单位限制。 |
总内存上限 | 超过宇宙级内存 quota 。 |
项目价值太大 | 值大小超出限制(32KB)。 |
下表列出了客户端的状态代码,这些代码目前不会在可视性仪表板上可用。
状态代码 | 描述 |
---|---|
内部错误 | 内部错误。 |
未发布的地方 | 您必须发布此地方才能使用 MemoryStoreService。 |
无效的客户端访问 | MemoryStoreService 必须从服务器调用。 |
无效的过期时间 | “有效期”字段必须在 0 和 3,888,000 之间。 |
无效请求 | 无法将值转换为 JSON。 |
无效请求 | 无法将排序键转换为有效的数字或字符串。 |
变形回调失败 | 无法调用变形回调函数。 |
请求限制 | 最近的 MemoryStores 请求触发了一个或多个限制。 |
更新冲突 | 超过了最多重试次数的上限。 |
排障
下表列出并描述每个响应状态代验证码的推荐解决方案:
错误 | 排除选项 |
---|---|
数据结构请求限制/分区请求限制 |
|
总请求超限 | |
数据结构项目超限 |
|
数据结构存储限制 | |
总内存上限 | |
数据更新冲突 | 在多个请求之间实现一种短 |
内部错误 |
文件一个 bug 报告 ,描述您的体验 Universe ID 的问题。 > |
无效请求 |
|
项目价值太大 |
|
在工作室测试和调试
数据在 MemoryStoreService 之间是由 Studio 和生产隔离的,因此在 Studio 中更改数据不会影响生产行为。这意味着 Studio 的 API 调用不会访问生产数据,以便您可以安全地测试存储存储和新功能,然后进入生产。
Studio 测试具有与生产相同的 限制和额外奖励 。 对于根据用户数量计算的额外奖励,您可以使用 Studio 测试的实例进行测试。 当从 Studio 测试时,您可能会注意到 Studio 测试的实例的延迟和错误率比在生产中使用更高。
有关如何在实时体验或在工作室测试时调试存储空间的信息,请使用开发者控制器。