目录
这是《MMO 服务器开发》四卷本第三卷《分布式与跨服》的完整目录。
卷一《网络与并发内核》把网络底座从零造了出来,卷二《单服架构与玩法系统》把玩法系统装了进来。到卷二结束,aegis 已经是一个能登录、能移动、能打怪、能交易、能组队进副本的单服服务端,并且跑出了单服承载数字。
但真实的 MMO 不是一台机器。它有分区、有分服、有跨服战场、有全球同服的排行榜;它的网关是一群、场景服是一群、战斗服是临时开出来的;它要处理「玩家在 A 服、好友在 B 服」「战场开在第三组机器上」「掉落结算发生在另一个进程里」。这一卷就是把单服变成集群。
这一卷要解决什么
从单服到集群,难点不在「把进程多起几个」,而在于四件事同时成立:
- 彼此能找到。进程数一多,IP 和端口就不能写死在配置里。谁上线了、谁挂了、某个实例现在在哪台机器上,需要一个所有节点都认的目录。
- 调用能兜住。跨进程调用会超时、会重试、会打爆下游。没有超时预算和背压,一次慢查询就能把整条链路拖垮。
- 状态不串味。玩家数据、场景状态、战场结算分散在不同进程里,一旦写入者不唯一,就会出现「两个进程都以为自己是权威」的经典事故。
- 账能对上。跨服结算、跨服务发奖、跨库转账,任何一步都可能半成功。最终一致不是「运气好就一致」,而是一套能对账、能补偿、能修复的机制。
这四件事各自都有成熟方案,但游戏服务端的取舍和通用后端不一样:它容忍短时间的最终一致,却不能容忍玩家看到自己的装备凭空消失;它可以把场景状态整个丢进内存,却必须在崩溃后能重建;它追求低延迟,因此很多「等一等就一致」的方案在这里不可接受。这一卷的每一节都会把这个取舍摊开讲。
这一卷写给谁
| 你现在的状态 | 这一卷给你的东西 |
|---|---|
| 已经读完卷一、卷二 | 把 aegis 从单进程推到多进程,最后跑出跨服战场端到端验收 |
| 会写业务后端,没做过游戏服务端 | 看清游戏场景下分布式取舍与通用后端的差异(状态归属、延迟预算、玩家可见的一致性) |
| 做过分布式系统,没做过 MMO | 看清 MMO 特有的问题:会话粘性、场景所有权、跨服资产归属 |
| 只想查某个具体问题 | 按 §「全书章节索引」跳读;每章第 1 节都有与站内既有架构文的分工表 |
四类读者,四种收获
读过前两卷的读者:这一卷是唯一一卷要求「多进程真跑」的——很多节会同时起三到五个进程,用真实的注册中心把它们连起来。你会看到单机测试全绿、多机一跑就崩的那些问题,以及它们各自怎么修。
通用后端出身的读者:你熟悉的那套(幂等、重试、熔断、最终一致)在这里依然成立,但边界不同。最典型的分歧是:通用后端把「读到的数据稍微旧一点」视为可接受,游戏服务端在玩家自己的资产上不接受,在别人身上的数值上却能接受。这一卷会把这条线画出来。
只关心某一块的读者:第 2–3 章讲发现与调用,第 7 章讲 ID,第 8–10 章讲缓存、持久化与事务。每章第 1 节的分工表会告诉你「这一章对应的站内既有架构文是哪几篇」,可以先读那几篇建立判断力,再回来读实现。
准备上线的人:第 4 章(网关与会话粘性)、第 5 章(调度与崩溃恢复)、第 11 章(端到端验收与承载数字)是必读。发布会掉线、节点会崩溃、战场会开不起来——这三章讲的都是「出事时怎么办」。
这一卷与卷二的关系
| 卷二《单服架构与玩法系统》 | 卷三《分布式与跨服》 | |
|---|---|---|
| 进程数 | 1 个逻辑服(可单进程跑完) | 多个进程:网关、场景、战斗、世界、目录 |
| 状态 | 都在一个进程里,单写者清晰 | 分散在多个进程,需要所有权与租约 |
| 通信 | 进程内函数调用 + 客户端帧 | 进程间 RPC + 消息总线 |
| ID | 单服自增即可 | 必须全局唯一且可回拨容错 |
| 一致性 | 单进程事务 | 跨服务补偿、对账、最终一致 |
| 验收 | 单服可玩 + 单服承载数字 | 跨服战场端到端 + 集群承载数字 |
卷二造出来的 aegis 单服版本不会在这一卷被推翻。卷三做的是把它拆开、连起来,并且保持卷二的所有玩法断言依然通过——如果一个改动让单服玩法测试红了,那这个改动就是错的。
可运行性口径
这一卷第一次大量依赖真实中间件。所有中间件都在本机以独立容器运行,端口与用户自己的实例完全错开:
| 服务 | 本机地址 | 用途 |
|---|---|---|
| etcd 3.6.4 | http://127.0.0.1:32379 | 服务注册、Leader 选举 |
| NATS 2 | nats://127.0.0.1:34222 | 节点间消息总线 |
| Consul 1.20 | http://127.0.0.1:38500 | 服务发现与健康检查对照 |
| Redis 7 | 127.0.0.1:26379 | 缓存、分布式锁、排行榜 |
| Postgres 17 | 127.0.0.1:25432 | 角色数据、分库分表 |
每节的层级口径如下:
| 层级 | 含义 | 本卷典型场景 |
|---|---|---|
| L1 | 纯逻辑,go test 可跑 | 雪花算法、号段分配、一致性哈希、路由表计算 |
| L2 | 起真进程 / 连真中间件并断言 | 注册与心跳、Leader 选举、RPC 超时、缓存失效、分片路由 |
| L2J | Java 对照实现,经 Docker 真跑 | 3.3 gRPC-Go vs gRPC-Java |
| L3 | 仅静态校验 | K8s 清单、etcd 部署配置 |
| L4 | 不可复现,正文显式标注 | 跨地域真实延迟、公网 DDoS |
| B | 基准,软告警不硬失败 | 集群承载数字、发现开销、RPC 吞吐 |
本卷没有「讲一讲就算过」的节。凡是写进正文的代码,都在本机真跑过;凡是报出的数字,都来自本机实跑。基准数字一律标注「同机相对量级,绝对数值不可移植」。
三条阅读路径
路径 A:顺序通读(约 4 周)
从第 1 章开始,按顺序读完 11 章。这条路径最完整:先建立「什么时候该拆」的判断力,再逐块把发现、调用、网关、调度、跨服、ID、缓存、持久化、事务补齐,最后用第 11 章的跨服战场端到端验收把全部零件装起来。适合准备从零搭建集群的人。
路径 B:直奔「跨服能打一场」(约 2 周)
读 1.1 → 2.1 → 2.2 → 4.1 → 5.1 → 5.2 → 6.1 → 6.3 → 11.1 → 11.2。这条路径跳过缓存与持久化的细节,只关心「两个不同服的人怎么被匹配到同一场战斗里,打完之后的奖励怎么正确回到各自的服」。适合已经有单服、想先看到跨服跑起来的人。
路径 C:只关心数据安全(约 2 周)
读 1.2 → 7.1 → 7.3 → 8.1 → 9.2 → 9.3 → 10.1 → 10.2 → 10.3。这条路径全部围绕「资产不能凭空多、也不能凭空少」:ID 全局唯一、缓存不返回旧值、落库不脏写、分片再均衡不丢数据、跨服务事务能补偿、对账能发现差异。适合接手线上数据的人。
全书章节索引
第一部分:为什么拆、怎么找到彼此(第 1–3 章)
| 节 | 文章 | 核心内容 |
|---|---|---|
| 1.1 | 分区分服与集群拓扑 | 分区、分服、全球同服三种形态;网关 / 场景 / 战斗 / 世界 / 目录五类节点的职责边界 |
| 1.2 | 什么时候该拆、什么时候不该 | 拆分成本清单:一次 RPC 换来什么、付出什么;单服能扛到多少人才值得拆 |
| 1.3 | 本书范围与站内服务治理文章的分工 | 与站内既有架构文的分工总纲;把边界编码成可查询的表 |
| 2.1 | 注册与健康检查 | 节点注册、TTL 租约、健康检查三态;etcd 真跑 |
| 2.2 | Leader 选举与服务所有权 | 租约、fencing token、脑裂防护;服务所有权怎么落到代码 |
| 2.3 | 对照:etcd / NATS / Consul 在本机的真跑选型 | 三套中间件在本机真跑同一套注册与发现,对照延迟与运维成本 |
| 3.1 | 协议与超时预算 | 跨进程调用的超时预算怎么分配;超时了到底算成功还是失败 |
| 3.2 | 重试、熔断与背压 | 重试的幂等前提、熔断阈值、背压如何防止雪崩 |
| 3.3 | 双栈对照:gRPC-Go vs gRPC-Java | 同一份载荷在两种栈上的实现与实测对照 |
第二部分:连接落在哪、实例开在哪(第 4–5 章)
| 节 | 文章 | 核心内容 |
|---|---|---|
| 4.1 | 连接位置与路由目录 | 谁持有连接、路由目录怎么维护、玩家换服时连接怎么处理 |
| 4.2 | 粘性策略与发布期行为 | 会话粘性的三种实现与代价;发布期间玩家会看到什么 |
| 4.3 | 连接排空(draining) | 优雅下线:停止接受新连接、通知客户端、等旧连接自然结束 |
| 5.1 | 实例调度器 | 场景服 / 战斗服 / 世界服的调度模型;实例生命周期 |
| 5.2 | 分配 Broker 与容量评估 | 实例开在哪台机器、容量怎么评估、开不出来时怎么排队 |
| 5.3 | 崩溃恢复与状态重建 | 进程崩了之后,内存里的场景状态怎么重建 |
第三部分:跨服与全局唯一(第 6–7 章)
| 节 | 文章 | 核心内容 |
|---|---|---|
| 6.1 | 跨服报名与匹配 | 跨服报名、跨服匹配队列、匹配结果的归属与通知 |
| 6.2 | 跨服聊天与消息路由 | 跨服频道的订阅关系;消息怎么找到人 |
| 6.3 | 资产归属与跨服结算 | 战场奖励算在哪个服、怎么回传、失败了怎么办 |
| 7.1 | 雪花算法从零实现 | 位布局、worker id 分配、生成吞吐实测 |
| 7.2 | 号段模式 | 号段预取、双 buffer 切换、数据库压力对照 |
| 7.3 | 时钟回拨与容错 | 回拨的三种成因与三种应对;拒绝生成 vs 等待 vs 借位 |
第四部分:状态、缓存与一致性(第 8–10 章)
| 节 | 文章 | 核心内容 |
|---|---|---|
| 8.1 | Redis 使用与失效策略 | 缓存键设计、失效时机、缓存与数据库的先后顺序 |
| 8.2 | 缓存预热与击穿防护 | 预热、单飞(singleflight)、逻辑过期、热点 key |
| 8.3 | 读写分离与读模型 | 写模型与读模型分离;读写延迟带来的可见性问题 |
| 9.1 | 角色数据模型 | 角色数据怎么拆表、什么进主表什么进扩展表 |
| 9.2 | 落库与脏写防护 | 版本号、乐观锁、定时落库与退出落库;旧数据覆盖怎么防 |
| 9.3 | 分片与再均衡 | 分片键选择、一致性哈希、再均衡期间的读写 |
| 10.1 | 跨服务事务与补偿 | Saga 与 TCC 的取舍;补偿动作必须幂等 |
| 10.2 | 对账与数据修复工单 | 对账口径、差异分级、修复工单的审批与留痕 |
| 10.3 | 事件溯源与审计 | 事件流、快照、审计日志;怎么回答「这件装备是怎么到他那儿的」 |
第五部分:综合(第 11 章)
| 节 | 文章 | 核心内容 |
|---|---|---|
| 11.1 | 跨服战场端到端 | 从两个服各来一队人,到打完结算回各自服的完整链路 |
| 11.2 | 多进程编排与验收 | 一次拉起全部节点、按顺序验收、失败时怎么定位 |
| 11.3 | 集群承载数字 | 集群级基准:节点数、连接数、跨服吞吐与延迟 |
《晨曦大陆》跨服战场验收清单
卷三的终点是「跨服能打一场」。下面是可复现的十步验收,每一步都能在命令行跑出来:
| # | 步骤 | 断言 |
|---|---|---|
| 1 | 拉起 etcd / NATS / Redis / Postgres | 四个容器健康,端口可连 |
| 2 | 启动目录服务与三台网关 | 注册中心里出现 4 个节点,心跳续约正常 |
| 3 | 启动两个场景服(scene-a、scene-b) | 节点各自注册,路由表包含两台场景服 |
| 4 | 玩家 1 连 gateway-01 登录到 scene-a | 会话建立,路由目录记录连接位置 |
| 5 | 玩家 2 连 gateway-02 登录到 scene-b | 两名玩家分属不同服 |
| 6 | 两人各自发起跨服报名 | 报名落到跨服队列,带上各自的服号 |
| 7 | 匹配器撮合出一场战场 | 分配 Broker 开出一个战斗实例并返回地址 |
| 8 | 两人被通知并进入同一战斗实例 | 战斗实例内能看到两个来自不同服的玩家 |
| 9 | 战斗结束,结算发奖 | 奖励分别回写到各自的服,账目守恒 |
| 10 | 杀掉 scene-a 进程 | 玩家被迁移或重连;重连后资产与战斗前一致 |
每一节长什么样
每节都是同一套骨架,读起来可预期:
- 开头 2–4 段:这一节解决什么问题、为什么难、本节怎么做。
- 3–4 个 H2 小节:每一小节讲清一个决策点,并且给出能真跑的代码。
- 代码块:每一块都在本机跑过,块头标注
// file:/// tier:/// verify:。看到// verify:就可以直接复制执行。 - 实测结论:有数字的节给出同机实测数字,并说明「绝对数值不可移植」。
- 阅读导航:最后一行是上一节 / 下一节的链接,可以一路顺着读下去。
学完之后你能做什么
- 判断一个 MMO 项目该不该拆,拆到什么粒度,代价是什么。
- 用真实中间件把一群进程连起来,让它们彼此发现、选举、心跳、排空。
- 把「跨服打一场」这条链路端到端搭出来,并证明结算的账是对得上的。
- 处理分布式 ID、缓存失效、脏写、分片再均衡、跨服务补偿这些具体问题。
- 在节点崩溃、网络抖动、发布重启这些真实场景下,知道先看什么、怎么止血。
常见问题速查
| 问题 | 去哪一节 |
|---|---|
| 我的项目到底要不要拆成多进程? | 1.2 |
| 服务注册用什么?etcd / NATS / Consul 怎么选? | 2.1、2.3 |
| 两个节点同时以为自己是主,怎么办? | 2.2 |
| RPC 超时了,业务到底成功没有? | 3.1 |
| 下游一直慢,怎么不让它拖垮上游? | 3.2 |
| 玩家换服了,他的连接怎么办? | 4.1、4.2 |
| 发布时怎么不掉线? | 4.3 |
| 战斗服怎么开、开在哪、开不出来怎么办? | 5.1、5.2 |
| 场景服崩了,玩家数据会不会丢? | 5.3 |
| 不同服的人怎么匹配到一起? | 6.1 |
| 战场奖励算谁的?发错了怎么修? | 6.3 |
| 为什么不能用数据库自增做主键? | 7.1 |
| 号段模式和雪花算法怎么选? | 7.2 |
| 服务器时间回拨了,ID 会不会重复? | 7.3 |
| 缓存和数据库不一致怎么办? | 8.1 |
| 热点 key 把 Redis 打挂了怎么办? | 8.2 |
| 玩家刚写完就看到旧数据? | 8.3 |
| 角色数据怎么拆表? | 9.1 |
| 玩家数据被旧版本覆盖了怎么办? | 9.2 |
| 加机器之后数据怎么搬? | 9.3 |
| 跨服发奖发了一半怎么办? | 10.1 |
| 怎么发现线上账目对不上? | 10.2 |
| 怎么查清一件装备是怎么到某个玩家手里的? | 10.3 |
本卷的代码约定
为了让「每一节都能真跑」这条承诺可验证,本卷的代码块遵循统一约定:
- 每个能跑的代码块,前三行是
// file:(还原路径)、// tier:(层级)、// verify:(验证命令)。把这三行连同代码复制到对应目录,// verify:里的命令可以直接执行。 - 只做展示、不参与验证的片段用
// snippet:标注,正文会说明它的完整实现落在哪个文件。 - 跨卷共享的协议帧格式、命令号、实体 ID 位布局全部沿用卷一与卷二的定稿,本卷新增跨服域命令号
0x0D–0x10,不重复定义、不擅自改写。 - 基准数字全部来自本机实跑,并标注「同机相对量级,绝对数值不可移植」;正文不使用「快 N 倍」这类绝对表述。
怎么用这份索引
- 想按顺序读:直接点 §「全书章节索引」里的链接,从 1.1 开始。
- 想跳读:先在 §「常见问题速查」里找到你的问题,再去对应章节。
- 想跟着跑:每一节的代码块都带
// verify:,复制到终端就能执行;§「《晨曦大陆》跨服战场验收清单」是整卷的总验收。 - 想对照既有文章:每章第 1 节都有分工表,写明「这一章对应的站内既有架构文是哪几篇、各自负责什么」。
相关阅读
- 卷一《网络与并发内核》 :网络底座、协议、KCP、会话与网关、幂等与实时同步。
- 卷二《单服架构与玩法系统》 :实体运行时、AOI、战斗、背包、任务、社交、交易与匹配。
- 游戏服务端专题 :站内既有的游戏服务端架构文章总入口。
- 游戏服务端实战工程 :架构方案与取舍类文章,本卷每章分工表的来源。
- 书稿专题 :本站全部成体系书稿的总入口。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。