为什么要有这篇前言
序讲的是“为什么写这套书”,本篇讲的是“这套书是怎么写出来的”。
架构书最容易出现的两个问题是:案例太抽象,读完不知道跟自己有什么关系;结论太具体,换一个团队、换一个品类就不成立。为了避免这两点,本书做了三个约定:
- 案例固定在同一个工作室,三款产品覆盖四种典型品类,同一组决策可以在不同产品上对照;
- 每个结论都给出适用条件,包括团队规模、在线量级、延迟预算和运维能力;
- 关键结论尽量落成可运行或可检查的产物,代码、测试、清单至少有一种。
下面把技术基线、案例构造、代码组织和证据口径逐项交代清楚。读者可以据此判断:哪一段可以直接借鉴,哪一段必须先替换成自己的参数。
技术基线
卷一的可运行代码以 Go 1.26.0 为基线,主要理由是:
- 标准库足够覆盖本书的 L1/L2 场景,不需要引入 Web 框架或 ORM;
- goroutine 与 channel 让并发与超时的表达更接近架构图;
- 单文件即可编译运行,便于把代码直接嵌进文章。
本书不绑定游戏引擎,也不绑定云厂商。房间、地图、tick、匹配这些概念在 Unity、Unreal、自研引擎或纯服务端项目里都存在,差别主要在客户端同步方式,而本书讨论的是服务端边界。
涉及真实依赖时,使用 Docker 启动 PostgreSQL 或 Redis。卷一以 L1 为主,只有少量 L2/L3 验证;卷二的容量、缓存与高可用章节会增加 L3 的比重。本书不会声称在未安装的环境里跑过任何东西,Kubernetes 相关的内容只写设计与边界,不写“本机已验证”。
| 组件 | 版本口径 | 用途 |
|---|---|---|
| Go | 1.26.0 | 全部可运行代码 |
| PostgreSQL | 17-alpine(Docker) | L3 持久化验证 |
| Redis | 7.x(Docker,可选) | 会话、排行榜等场景 |
| Hugo | 0.163.3+extended | 本书站点构建,与读者无关 |
版本会随环境变化。如果你在更高版本上运行,绝大多数 L1 代码应当照常工作;出现编译差异时,以你本机的错误信息为准,不要为了迁就书中的写法而降低版本。
案例是怎么构造的
北辰工作室和三款产品是虚构的。构造它们时遵循了三条规则。
规则一:每个产品只承载一种主要矛盾
- 《裂隙战场》承载“实时与公平”;
- 《群岛纪元》承载“持久与大世界”;
- 《泡泡工坊》承载“速度与成本”。
如果一款产品同时承载所有矛盾,案例会变成万能答案,反而失去对照价值。把矛盾拆开之后,同一个问题在三款产品上会得到不同答案,读者才能看到取舍的边界。
规则二:参数取常见量级,不追求极端
书中的同时在线、单局时长、消息频率、机器数量都取行业中常见量级,并在第一次出现时标注“示例值”。它们足够支撑数量级判断,但不构成容量承诺。真正做容量规划时,必须用自己产品的峰值、留存曲线和战斗时长重新计算。
规则三:事故来自真实问题的拼合
书中描述的事故——幽灵房间、跨洋伤害延迟、重启回档、离线收益异常——由多个项目里的常见问题拼合而成,去掉了可识别的公司、项目和时间信息。这样做的目的不是制造戏剧性,而是让失败模式有具体形状:读者能对照自己的系统,判断“我们有没有同样的隐患”。
代码怎么组织
卷一的所有代码围绕一个本地验证工程 gsarch-lab 组织。文章中的代码块带有三类标记:
// file: internal/session/registry.go
// tier: L1
// verify: go test ./internal/session/
package session
file:该代码在验证工程中的路径;tier:可运行级别,L1/L2/L3;verify:作者实际用于验证的命令。
同一段代码在文章与工程中保持逐字节一致。这样做有一个副作用:文章里的代码会包含包声明、导入和测试辅助函数,读起来不如伪代码紧凑。这是刻意选择的代价——能跑的代码比漂亮的伪代码更值得信任。
卷一的包大致按问题划分:
| 目录 | 对应主题 |
|---|---|
internal/topology、internal/arch | 拓扑选择、模块依赖 |
internal/room、internal/alloc | 房间状态机、分配器 |
internal/state、internal/tick、internal/offline | 快照、tick、离线补算 |
internal/conn、internal/gateway、internal/session | 连接、网关、会话 |
internal/authority、internal/anticheat、internal/economy | 预测裁决、反作弊、经济随机 |
internal/moba、internal/lagcomp、internal/replay | 竞技品类 |
internal/worldmap、internal/merge、internal/settle | SLG 品类 |
internal/hybrid、internal/cardgame、internal/minibackend | 休闲、卡牌、小游戏 |
internal/deploy、internal/stateful、internal/faultdomain | 部署单元与故障域 |
internal/views、internal/contractspec、internal/decisionlog | 架构表达 |
internal/baseline、internal/matrix、internal/handoff | 卷一收口 |
这些包不会组成一个可直接上线的服务端。它们是决策的夹具:用最小的代码把某个边界、状态机或故障模式固定下来,让读者能改参数、跑测试、看失败。真正的产品代码需要考虑协议、持久化、运维和性能,这些在《MMO 服务器开发》与卷二里展开。
可运行性分级
本书用四级标注代码的验证强度。卷一主要使用前两级。
| 级别 | 判定 | 验收方式 | 能证明什么 |
|---|---|---|---|
| L1 | 纯逻辑或单包,不依赖外部进程 | gofmt -l 无输出、go vet、go test | 状态机、路由、预算、策略逻辑正确 |
| L2 | 进程内端到端,内存适配器或本地端口 | 一个脚本完成主流程并断言结果 | 模块之间的契约能跑通 |
| L3 | 真实依赖,Docker Compose 启动 | 固定场景脚本 + 指标/日志 | 持久化、并发、故障恢复在真实依赖下成立 |
| L4 | 多节点、网络分区、故障注入 | 需要独立实验环境 | 分布式假设在故障下成立 |
L4 不在卷一的承诺范围内。书中讨论多节点与故障域时,会明确区分“设计推演”和“本机验证”。前者依赖模型和假设,后者才有命令与输出。读者在评审时也应该追问同一个问题:这个结论是哪一级证据支撑的?
数字的口径
书中数字分三类,写法不同:
- 示例值:用于说明数量级或取舍关系,例如“单房间 60Hz、每帧 20KB 下行”。它们帮助读者建立直觉,不是 benchmark。
- 设计目标:团队承诺的预算,例如“战斗操作 P99 小于 80ms”。目标可以写进 SLO,但不等于现状。
- 本机实测:附有命令、环境和输出,例如“在本机 8 核上运行
go test -bench的结果”。这类数字只对当时的软硬件成立。
如果一段文字只写“很快”“高并发”“低延迟”,却没有口径,那它不值得作为决策依据——包括本书里的文字。读者有理由对任何没有出处的性能结论保持怀疑。
按角色阅读
不同读者的路径不同,目录篇给了三条主路径。这里补充按角色的建议。
服务端工程师:顺序读第 1–6 章,建立品类、状态、时间、连接、权威的共同语言;再按自己负责的品类读第 7–10 章;第 11–13 章用于评审和收口。
技术负责人/架构师:先读 1.2、1.3、2.2、2.3,再读第 11–13 章与附录 B/C。重点不是记住结论,而是检查自己团队的决策是否写清了假设、代价和退出条件。
从普通后端转游戏:重点读第 1、4、5、6 章。游戏服务端与普通后端最大的差异集中在有状态、强实时、长会话和权威模型,这四章是迁移的地基。
产品/运营:读 1.3、7–10 章与附录 B。不需要看懂代码,但需要理解“全球同服”“无缝世界”“实时竞技”这些承诺在服务端分别意味着什么代价。
如何复现书中的验证
卷一的代码可以在本地按下面的方式验证。文章中的 // verify: 标记给出了每个包对应的命令。
# 进入验证工程
cd gsarch-lab
# 格式、静态检查与全部测试
gofmt -l .
go vet ./...
go test ./...
# 只跑某一章对应的包
go test ./internal/session/ ./internal/gateway/
如果你的环境没有安装 Go 1.26.0,建议使用官方二进制或容器,而不是修改 go.mod 里的版本号。版本差异导致的失败,本身就是一条有价值的信号:它提醒你,书中的结论有环境前提。
关于错误与修订
架构书的风险在于:结论看起来永远正确,直到换一个规模。本书会尽量把适用条件和失效条件写在正文里,但仍然会有判断偏差、版本过时和案例不严谨的地方。
如果你发现某段代码跑不通、某个数字没有口径、某个结论在你的品类下不成立,欢迎带着复现步骤指出。比“这里写得不对”更有用的反馈是:“在什么规模、什么团队、什么品类下,这个结论开始失效。”这类反馈会直接进入下一版的边界说明。
本书不做什么
最后明确边界,避免误解:
- 不教 Go、网络编程、数据库或 Kubernetes 的基础;
- 不提供可直接上线的一站式服务端框架;
- 不评价具体引擎、云厂商或开源中间件的优劣;
- 不承诺某种架构适用于所有品类;
- 不把设计推演说成本机验证。
在这些边界之内,本书会尽量把每个决策讲透:备选方案是什么,判据是什么,代价是什么,什么时候该改。
阅读入口:《游戏服务端架构·品类、状态与拓扑》目录与学习路径 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。