背景:看似边缘的功能,往往会触到核心状态
坐骑系统看似只是移动速度变快,但它会影响移动校验、技能释放、地图区域、战斗状态、采集交互和客户端表现。玩家点击上马后,客户端希望立即播放动画;服务端则要判断是否在禁止区域、是否处于战斗、是否被控制、坐骑是否可用。坐骑状态同步就是在手感和权威裁决之间找平衡。
如果客户端自行切换坐骑状态,外挂可以伪造速度;如果服务端每次都等待完整裁决再表现,手感会很重。更麻烦的是,区域边界和战斗打断会让上马流程进入中间态,客户端和服务端稍有不同步就会出现瞬移或速度异常。
坐骑应作为角色移动状态机的一部分,由服务端权威确认。客户端可以预测播放,但所有速度、碰撞、技能限制和区域禁用都以服务端状态为准。服务端下发 mountStateVersion,客户端按版本校正。
架构视图
stateDiagram-v2
[*] --> OnFoot
OnFoot --> Mounting: 请求上马
Mounting --> Mounted: 服务端确认
Mounting --> OnFoot: 条件失败
Mounted --> Dismounting: 下马/受击/进禁区
Dismounting --> OnFoot
Mounted --> Restricted: 进入限制区域
Restricted --> OnFoot
这张图只画主链路。实际落地时,还要补上配置版本、权限检查、灰度策略、审计日志、异常补偿和客服查询。游戏服务端的架构图不是为了显得复杂,而是为了提前确认:谁拥有权威状态,谁只是读模型,失败后怎么恢复,玩家看到什么结果。
设计要点 1:先定义业务承诺
架构设计的第一步不是选数据库或消息队列,而是定义业务承诺。玩家点击按钮后,系统承诺立即生效、稍后生效,还是只生成一个待确认请求?客户端展示的内容是确定结果、预估结果,还是可变状态?这些承诺不同,服务端模型也完全不同。
坐骑速度校验要读取服务端状态,而不是客户端标记。进入禁骑区域时,服务端先切状态再广播速度修正。客户端预测失败时只回滚坐骑表现和速度,不应重置整个角色状态。
业务承诺必须写到接口契约里。只在产品文档或口头沟通里约定,很容易被后续调用方误解。比如“奖励预览不保证最终到账完全一致”这种规则,如果没有服务端字段表达,客户端就只能用固定文案硬解释。
设计要点 2:区分事实、计划和读模型
事实表示已经发生的事情,计划表示系统准备做但还没完成的事情,读模型表示为了查询和展示而整理出的结果。很多混乱来自这三者混用。比如报名表既当计划又当最终名单,任务进度既当事实又当展示,设置整包既当用户输入又当服务端策略。
事实要尽量不可变,修复时追加调整记录;计划要有状态机和过期时间;读模型要能从事实重建。这个划分会让代码多几层,但换来的是可审计、可恢复、可解释。
当读模型和事实不一致时,系统应该相信事实。读模型错误不是灾难,只要能重建;事实丢失才是真正危险。
设计要点 3:让规则集中,不要散落在入口里
游戏业务入口很多:客户端按钮、自动任务、后台工具、补偿脚本、队伍跟随、跨服同步。如果每个入口都自己判断规则,迟早会有一个入口漏掉。规则应该集中在领域服务或规则模块中,所有入口都调用同一套判定。
集中规则不等于做一个万能规则引擎。更现实的做法是为每个领域建立稳定的判定接口,例如 canEnterScene、canGrantReward、canJoinVoice、canTradeItem、canSyncSetting。这些接口返回允许、拒绝原因、所需动作和当前版本。
拒绝原因要稳定。客户端需要展示,客服需要解释,数据分析需要聚合。临时文案不能当原因码。
设计要点 4:中间态要可查询
真实系统里,很多流程不会瞬间完成。第三方语音 token 可能签发失败,活动报名可能等待冻结,奖励发放可能转邮件,设置同步可能等待另一端合并。中间态如果不可查询,玩家看到的就是卡住,客服看到的就是未知。
每个中间态都应有状态、开始时间、过期时间、最后错误和可执行动作。后台面板可以据此展示“等待成员确认”“奖励已转邮件”“正在重算进度”“等待第三方语音服务恢复”。
可查询并不意味着所有细节都暴露给玩家。玩家只需要看到能行动的信息,客服和研发需要看到更完整的状态链。不同角色看到不同视图,但底层证据应该来自同一套记录。
设计要点 5:把版本作为系统语言
配置会变,规则会变,客户端会变,玩家状态也会变。没有版本字段,系统就无法判断一次请求基于哪个事实。版本字段是跨服务沟通的语言:配置版本、规则版本、读模型版本、状态版本、客户端能力版本都很重要。
版本要随事件传播。下游读模型处理事件时,如果发现事件版本旧于当前状态,就忽略;客户端提交请求时带上自己看到的版本,服务端可以判断是否需要刷新。
版本还能帮助复盘。一次活动争议发生后,研发能查到玩家当时命中了哪个规则版本、看到哪个预览版本、最终按哪个发放版本结算。没有这些信息,只能猜。
数据模型建议
建议把数据拆成四层。第一层是权威状态,例如当前设置、当前资格、当前绑定关系、当前频道成员。第二层是事实流水,例如解锁、报名、投票、抽取、发放、同步。第三层是操作记录,例如某次请求的幂等键、参数、状态和错误。第四层是读模型,例如列表页、排行榜、聊天展示、客服摘要。
权威状态要小,事实流水要完整,操作记录要可查询,读模型要能重建。四者各自职责清楚,系统才不会因为一个展示需求改坏核心状态。
字段上要避免只有 boolean。实际业务需要 status、reason、version、source、expireAt、updatedAt、operationId、idempotencyKey。字段多一点不是问题,字段缺失导致无法解释才是问题。
幂等与并发
高风险操作都要有业务幂等键。幂等键应来自业务语义,而不是每次请求随机生成。比如一次奖励领取可以用 sourceType+sourceId+playerId,一次报名可以用 eventId+teamId,一次设置同步可以用 playerId+settingKey+clientRevision。
并发处理要靠状态机和版本,而不是只靠锁。锁能保护一小段写入,状态机能保护完整流程。旧请求迟到时,版本检查会拒绝它;重复请求到达时,幂等记录会返回第一次结果。
对于多端、多入口操作,字段级合并比整包覆盖更安全。玩家在手机改隐私设置,在电脑改快捷键,不应该互相覆盖。每个字段有自己的版本和更新时间,服务端才能做合理合并。
失败路径与补偿
失败要分层。业务条件不满足是拒绝,依赖短暂失败是可重试,配置缺失是发布事故,状态长期停留是流程异常。不同失败类型对应不同处理:返回原因、进入重试、冻结入口、死信人工处理。
补偿不能绕过主流程。补发奖励、修复进度、恢复设置、释放名额都应调用同一套领域接口,并写入事实流水。否则补偿解决了一个问题,又制造了新的状态不一致。
超时后要能查询。调用方不确定请求是否成功时,应该用 operationId 查询结果,而不是盲目再发一个不同请求。查询接口是幂等体系的重要组成部分。
性能与容量
这类系统大多不是每秒百万 QPS,但会有明显峰值。活动开启、赛季结束、版本更新、主播开团、公会战报名截止前,某些接口会突然升高。容量估算要按这些业务峰值设计,而不是看日常平均。
读模型要为高频展示服务。聊天、好友、排行榜、活动页这类读多写少场景,不应每次查核心状态。核心状态通过事件刷新读模型,读模型再服务高频查询。这样既保护核心服务,也让展示更稳定。
写入链路要控制扇出。一次状态变化可能触发通知、读模型、日志、统计、客服索引。可以用 outbox 和异步消费者处理,但要监控消费延迟。异步不是不用管,而是把延迟显式化。
观测与审计
指标要覆盖业务结果。成功率、拒绝率、处理中数量、超时数量、补偿数量、读模型延迟、事件积压都应该能看。只看 HTTP 200 没意义,因为业务拒绝和技术成功可能同时发生。
审计要记录变更前后状态、来源、版本和原因。特别是人工操作、补偿脚本、活动配置变更、跨服同步,都要能追到具体操作人或系统来源。
客服查询应提供简化证据链。比如玩家为什么没拿到奖励,后台能看到预览版本、领取请求、发放结果、邮件托底;玩家为什么不能进语音,后台能看到队伍状态、禁言状态、token 签发记录。
上线验证
上线前先做影子验证或只读验证。新规则先计算结果但不生效,对比旧逻辑差异。差异符合预期后,再用小范围灰度承接真实流量。
测试用例要覆盖边界:重复请求、旧版本客户端、配置热更、服务重启、队列延迟、人工补偿、读模型重建。只测正常路径会让系统看起来很稳,但线上问题往往来自边界组合。
回滚方案要包括数据。代码回滚不能自动撤销已经写出的状态,配置回滚也不能自动修复读模型。上线前要准备冻结入口、停止消费、重建读模型、追加修正事件和人工处理入口。
线上案例化复盘
真实线上问题常常不是某一行代码错,而是多个合理动作叠加后产生不合理结果。玩家重复点击,客户端超时,服务端重试,运营改配置,读模型延迟,客服人工补偿,这些动作单独看都正常,叠在一起就可能出事。
复盘时不要只问“为什么报错”,还要问“系统为什么没挡住旧请求”“为什么客服查不到证据”“为什么补偿绕过了幂等”“为什么读模型延迟没有报警”。这些问题的答案,才会推动架构变稳。
每次事故都应沉淀成规则、测试和面板。只修代码不补校验,下次还会在另一个入口重现。
交付检查清单
- 是否区分权威事实、操作计划和展示读模型。
- 是否有稳定状态机和中间态查询。
- 是否所有高风险操作都有业务幂等键。
- 是否返回稳定原因码,而不是临时文案。
- 是否记录配置版本、状态版本和客户端能力版本。
- 是否有 outbox 或等价机制保证事件不丢。
- 是否支持读模型重建和补偿审计。
- 是否做过重复请求、超时、重启、配置回滚和旧客户端测试。
清单里的每一项都很实际。游戏服务器端架构不是追求抽象漂亮,而是让系统在玩家高峰、网络波动、运营调整和人工介入时仍然可信。
小结
坐骑状态同步架构的重点,是把一个容易被当成“附属功能”的模块,放回服务端架构的状态治理体系里。只要它影响玩家体验、资产、资格、权限或展示可信度,就需要有权威状态、幂等、版本、审计和补偿。
先把这些基础能力做好,后续扩展新玩法、新入口、新平台时就不会反复推倒重来。系统可以不复杂,但边界必须清楚;功能可以逐步演进,但证据链不能缺席。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。