MemoryStoreService 是一个高吞吐量和低延迟的数据服务,可以从活动会话中的所有服务器访问快速内存数据存储。 内存存储 适合频繁且临时的数据快速更改且不需要持久,因为它们更快地访问并在达到最大使用寿命时消失。对于需要在会话之间持续的数据,请使用 数据存储。
数据结构
而不是直接访问原始数据,内存存储有三种原始数据结构在服务器之间共享快速处理:排序地图、队列和哈希地图。每个数据结构都很适合某些使用案例:
- 技能基于匹配 - 将用户信息,例如技能等级,保存在服务器之间的共享 队列 中,并使用大厅服务器定期运行匹配。
- 跨服务器交易和拍卖 - 启用不同服务器之间的通用交易,用户可以在具有实时变化价格的物品上投标,使用排序的键值对组合。
- 全球排行榜 - 在排序地图内的共享排行榜中存储和更新用户排名。
- 共享库存 - 将库存物品和统计数据保存在共享 哈希地图 中,用户可以同时使用库存物品与 друг другом。
- 永久数据的缓存 - 将永久数据同步到数据存储库复制到内存存储库 哈希地图 中,以便作为缓存并提高体验性能。
一通用来说,如果您需要基于特定键访问数据,请使用哈希地图。如果需要订购该数据,请使用排序的地图。如果您需要按特定顺序处理数据,请使用队列。
限制和配额
为了保持可扩展性和系统性能,内存存储有数据使用限额为内存大小、API请求和数据结构大小。
内存存储有基于过期时间的驱逐政策,也称为存活时间(TTL)。项目在过期后被驱逐,内存配额被释放以用于新的入口。当您达到内存限制时,所有后续的写入请求都会失败,直到项目过期或您手动删除它们。
内存大小限制
内存配额限制体验可以消耗的内存总量。它不是一个固定值。相反,它随着时间的推移会根据体验中的用户数量变化以下公式: 64KB + 1KB * [用户数量] 。限额适用于体验级别,而不是服务器等级。
当用户加入体验时,额外的内存容量立即可用。当用户离开体验时,配额不会立即减少。在限额重新评估为更低值之前,有一个追溯期为八天。
体验达到内存大小限制后,任何增加内存大小的 API 请求都会失败。要求减少或不更改内存大小仍然成功。
使用观察性仪表板,您可以使用 内存使用 图表实时查看体验的内存大小配额。
API 请求限制
对于 API 请求限制,有一个 请求单元 额度适用于所有 MemoryStoreService API 调用。配额为 1000 + 100 * [同时用户数量] 每分钟的请求单位。
大多数 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 响应状态代码的 按状态请求数量 和 API x状态请求 图表。了解有关如何解决这些错误的更多信息,请参阅排除故障。对于错误与相关的特定配额或限制,请参阅限制和配额。
状态代验证码 | 描述 |
---|---|
成功 | 成功。 |
数据结构内存超出限制 | 超过数据结构级别内存限制(100MB)。 |
数据更新冲突 | 由于同时更新造成冲突。 |
访问被拒绝 | 未获得访问体验数据的权限。该请求不消耗请求单位或使用配额。 |
内部错误 | 内部错误。 |
无效请求 | 请求没有必要信息或者有不正确的信息。 |
数据结构项超出限制 | 超过数据结构级别项目数限制(1M)。 |
未找到物品 | 在 或 中未找到项目。每 2 秒进行投票,直到找到队列中的项目为止返回此状态代码。 |
数据结构请求超出限制 | 超过数据结构级别请求单位限制(每分钟 100,000 个请求单位)。 |
分区请求超出限制 | 超过分区请求单位限制。 |
超过限制的总请求 | 超过了宇宙级请求单位限制。 |
总内存超过限制 | 超出了宇宙级别的内存限额。 |
物品价值尺寸太大 | 价值大小超出限制(32KB)。 |
下表列出客户端的状态代码,这些代码目前不可用于观察性仪表板。
状态代验证码 | 描述 |
---|---|
内部错误 | 内部错误。 |
未发布的地点 | 您必须发布这个地方才能使用 MemoryStoreService。 |
无效客户端访问 | MemoryStoreService必须从服务器调用。 |
无效的过期时间 | 字段“过期”时间必须在 0 和 3,888,000 之间。 |
无效请求 | 无法将值转换为 json。 |
无效请求 | 无法将 sortKey 转换为有效的数字或字符串 |
转换调用失败 | 无法调用变形回调函数。 |
请求限制 | 最近的内存存储请求触发了一个或多个限制。 |
更新冲突 | 超过了最大重试次数。 |
排除问题
下表列出并描述了每个响应状态代验证码的推荐解决方案:
错误 | 排除问题选项 |
---|---|
数据结构请求超限/分区请求超限 |
|
超过限制的总请求 | |
数据结构项超出限制 |
|
数据结构内存超出限制 | |
总内存超过限制 | |
数据更新冲突 |
调查以确定你是否有效地调用 MemoryStoreService 以避免冲突。理想情况下,你不应该发送过多的请求。: 一旦使用 MemoryStoreQueue:RemoveAsync() 方法阅读队列和排序地图,就会一致删除项目。 |
内部错误 |
|
无效请求 |
|
物品价值尺寸太大 |
|
在工作室测试和调试
在 MemoryStoreService 中的数据是被隔离在 Studio 和生产之间的,因此更改 Studio 中的数据不会影响生产行为。这意味着从工作室发出的 API 调用不能访问生产数据,可以让您在进入生产之前安全测试内存存储和新功能。
工作室测试与生产具有相同的 限制和配额。对于基于用户数量计算的配额,由于您是唯一的用户进行 Studio 测试,因此最终配额可能很小。当从工作室测试时,您可能还会注意到较高的延迟和较高的错误率,这是因为进行验证访问和权限的一些额外检查所导致的。
要了解有关如何在实时体验或工作室测试时调试内存存储的信息,请使用开发者控制台。