关于 roblox-data
面向 Roblox 数据持久化、跨服务器临时状态和配额协调的技能,帮助设计 DataStoreService、MemoryStoreService 与 MessagingService 的使用方式。它强调数据类型选择、并发写入、缓存、配额和重试处理。
主要功能
- 01持久化数据结构与版本迁移
- 02DataStore 与 OrderedDataStore 选择
- 03MemoryStore 队列、映射与排序映射
- 04跨服务器消息协调
- 05并发、缓存、配额与重试策略
适用场景
- 01设计玩家存档与数据迁移
- 02构建匹配队列或临时跨服状态
- 03协调多个服务器的通知与状态更新
- 04排查数据服务节流和写入冲突
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ flatbedj/ roblox-skills --skill roblox-data安装后在 Claude Code 中输入/roblox-data确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cross-server-messaging.mddata-store-best-practices.mddata-stores-guides.mddata-stores-vs-memory-stores-comparison.mdmemory-store-best-practices-limits-and-observability.mdmemory-stores-guides.mdversioning-listing-caching-limits-and-observability.md详细介绍
roblox-data
适用场景
当任务主要涉及 Roblox 数据持久性、跨服务器共享状态或配额感知型协调时,请使用此技能:
- 设计持久化玩家存档、类似全局配置的记录,或其他
DataStoreService用法。 - 在标准数据存储和有序数据存储之间进行选择。
- 设计存档负载、架构版本、迁移和元数据。
- 决定何时使用
SetAsync()、UpdateAsync()、IncrementAsync()或版本 API。 - 使用
MemoryStoreService设计临时跨服务器系统。 - 在内存存储队列、有序映射和哈希映射之间进行选择。
- 使用
MessagingService协调多个服务器。 - 处理限流、请求预算、重试、退避、竞争和可观测性。
- 分析过时读取、缓存行为、幂等性和多服务器正确性。
当任务主要涉及以下内容时,请勿使用此技能:
- 远程事件安全、客户端到服务器的验证或一般游戏网络通信。
- OAuth 流程、API 密钥设置或一般 Open Cloud 身份验证。
- 数据服务以外的广泛引擎 API 查询。
决策规则
- 对于可表示为数字、字符串、布尔值、表或缓冲区的持久化跨会话数据,请使用标准数据存储。
- 仅当存储的值为数字,且主要需求是持久化排名或排序检索时,才使用有序数据存储。
- 与其将相关字段分散到多个持久化键中,不如优先将一个相关对象存储在一个持久化键中。
- 当多个服务器可能写入同一个键,或新值取决于当前值时,优先使用
UpdateAsync()。 - 对于频繁、临时、用于协调且可以过期的共享数据,请使用内存存储。
- 对于按键查找以及需要在大量键之间扇出查询的场景,请使用内存存储哈希映射。
- 当顺序很重要,或需要按排序键进行范围读取时,请使用内存存储有序映射。
- 对于有序工作处理、匹配队列或领取并移除工作流,请使用内存存储队列。
- 对于短暂的广播信号、扇出通知或唤醒协调,请使用
MessagingService,而不要将其用作持久化事实来源。 - 如果任务主要涉及远程调用、向客户端复制数据或信任边界,请转交给
roblox-networking。 - 如果任务主要涉及通用运行时结构或脚本放置,请转交给
roblox-core。 - 如果任务主要涉及成员查找、签名或类发现,请转交给
roblox-api。 - 如果请求包含超出范围的内容,只回答其中与数据服务相关的部分,并排除其余内容。
说明
- 选择服务前,先判断状态类型:
- 跨会话持久存在。
- 临时存在,但跨服务器共享。
- 仅用于广播协调。
- 数值排名,还是任意结构化数据。
- 选择满足需求的最精简原语:
- 持久对象使用标准数据存储。
- 持久数值排名使用有序数据存储。
- 键控的临时状态使用哈希映射。
- 有序的临时状态使用有序映射。
- 需要认领并处理工作项时使用队列。
- 可从其他状态重新生成的通知使用消息传递。
- 对持久化存档,定义稳定的架构:
- 尽可能让每个键对应一个自包含对象。
- 在值中包含架构版本字段。
- 仅在加载时,或加载后的首次写入时执行迁移。
- 让键、作用域和存储名称简短且可预测。
- 设计并发写入:
- 对有竞争的键,优先使用
UpdateAsync()。 - 确保回调具有确定性,且不会让出执行权。
- 对无效更新返回
nil,以中止更新。 - 如果不打算清除现有元数据和用户 ID,就要保留它们。
- 对有竞争的键,优先使用
- 设计读取时,考虑缓存行为:
- 将
GetAsync()视为会在本地短暂缓存的操作。 - 只有在新鲜度足够重要、值得额外消耗预算时,才使用无缓存读取。
- 除非设计考虑了数据过时的情况,否则避免在写入后立即从另一台服务器读取。
- 将
- 将配额纳入设计:
- 在突发性持久写入前检查请求预算。
- 如果能提升原子性并节省预算,就将相关的持久数据批量合并到一个对象中。
- 在满足用例的前提下,尽量缩短内存存储的 TTL。
- 处理完后立即移除队列和有序映射中的项目。
- 为重试和故障进行设计:
- 使用
pcall()包装网络调用。 - 使用指数退避重试瞬时故障。
- 当许多服务器可能同时重试时,加入抖动或错开重试时间。
- 尽可能让可重试操作具有幂等性。
- 使用
- 利用可观测性形成闭环:
- 监控数据存储的请求数量、限流情况和配额使用情况。
- 监控内存存储的内存使用量、请求单元使用量和限流状态。
- 使用仪表板确认瓶颈来自全局配额、单键竞争还是热点分区。
- 将消息传递用作协调层,而非存储:
- 发布精简事件。
- 根据需要重新读取或更新数据存储或内存存储中的权威状态。
- 假设消息可能延迟或重复,并确保处理程序能够安全处理。
- 确保指导内容不超出范围:
- 聚焦于持久化、临时共享状态、配额和并发。
- 不要偏离到远程安全、游戏玩法网络通信或身份验证流程。
使用参考资料
- 打开
references/data-stores-guides.md,了解标准数据存储与有序数据存储、核心 CRUD 模式、元数据、序列化和存档结构决策。 - 打开
references/data-store-best-practices.md,了解持久化架构布局、键组织、存储规范和清理策略。 - 打开
references/versioning-listing-caching-limits-and-observability.md,了解版本历史、前缀列举、缓存行为、限制、请求预算、限流和仪表板。 - 打开
references/memory-stores-guides.md,了解如何在队列、有序映射和哈希映射之间进行选择,以及各自的核心 API 模式。 - 打开
references/memory-store-best-practices-limits-and-observability.md,了解 TTL 策略、分片、分区压力、请求单元预算、竞争处理和仪表板。 - 打开
references/cross-server-messaging.md,了解主题设计、发布-订阅流程,以及将消息传递与持久或临时状态配合使用的协调模式。 - 如果首先需要决定由哪一类服务负责存储数据,请打开
references/data-stores-vs-memory-stores-comparison.md。
检查清单
- 将状态划分为持久状态、跨服务器临时状态或仅广播状态。
- 所选服务符合持久性和排序要求。
- 持久化键使用稳定的架构,并包含明确的版本字段。
- 可能发生竞争时,持久化写入使用
UpdateAsync()。 - 有序数据存储仅用于数值排名数据。
- 已考虑缓存行为和读取过期数据的风险。
- 设计中已考虑请求预算、配额和限流行为。
- 内存存储的 TTL 有意设置得较短,并明确了清理路径。
- 处理后移除队列项;排序映射或哈希映射中的过期项也会被清理。
- 使用消息进行协调,而不是将其作为事实来源。
- 重试逻辑使用
pcall()和退避机制,而不是紧密循环。 - 不包含远程安全、OAuth 或通用 API 查询相关内容。
常见错误
- 在多个服务器可能并发写入的热点键上使用
SetAsync()。 - 没有充分理由,却将一个持久化玩家档案拆分到多个互不相关的键中。
- 使用有序数据存储来保存结构化数据块或元数据繁多的记录。
- 忘记
GetAsync()可能在几秒内返回缓存值。 - 将内存存储当作持久化存储。
- 需要随机键访问或扫描时,却使用队列,而哈希映射更适合这些场景。
- 将所有哈希映射流量集中到一个热点键,导致触发分区限流。
- 为临时内存存储项设置过长的 TTL,导致过期数据占满配额。
- 将
MessagingService作为可恢复状态的唯一事实来源。 - 遇到限流或冲突时立即重试,引发协同重试风暴。
示例
选择合适的服务
- 保存玩家档案:使用标准数据存储,每个玩家键对应一个对象。
- 全时期金币排行榜:使用以玩家标识符为键、以数值为值的有序数据存储。
- 匹配池:使用内存存储队列。
- 带排名的跨服务器拍卖板:使用内存存储排序映射。
- 以服务器 ID 为键的共享临时房间注册表:使用内存存储哈希映射。
- 在各服务器间强制执行缓存刷新工作流:发送消息,并重新读取数据存储或内存存储。
对存在竞争的持久化保存使用 UpdateAsync()
local DataStoreService = game:GetService("DataStoreService")
local profileStore = DataStoreService:GetDataStore("PlayerProfiles")
local function saveCoins(userId, delta)
return profileStore:UpdateAsync(("player/%d"):format(userId), function(current, keyInfo)
current = current or {schemaVersion = 1, coins = 0}
current.coins += delta
return current, keyInfo:GetUserIds(), keyInfo:GetMetadata()
end)
end
使用消息唤醒工作进程,而不是保存状态
-- Publish: "queue has work"
-- Receiver: read the queue or map, then process authoritative state there.
评论
支持 Markdown