《游戏服务端编程实践》1.2.3 SLG / 策略类游戏架构模式详解
一、SLG 的本质与技术特征
1.1 什么是 SLG
SLG(Simulation Game / Strategy Game),即“策略模拟类游戏”, 是以 资源规划、领地扩张、部队调度、长期运营 为核心玩法的游戏类型。 其典型代表包括:
- 《文明》系列(单机策略)
- 《率土之滨》《三国志战略版》(MMO-SLG)
- 《部落冲突》《海岛奇兵》(休闲策略)
- 《Evony》《Lords Mobile》(全球化跨服 SLG)
1.2 SLG 的技术定义
SLG 与 MMO 一样具备多人在线特征,但其 核心架构差异 在于:
| 对比项 | MMO | SLG |
|---|---|---|
| 玩法核心 | 实时交互、即时战斗 | 异步调度、战略规划 |
| 时间尺度 | 秒级(实时) | 分钟/小时级(异步) |
| 网络模型 | 长连接(实时同步) | 短连接 + 长轮询 / WebSocket |
| 状态粒度 | 高频状态(移动、技能) | 低频状态(建筑、行军) |
| 并发类型 | 高频帧事件 | 异步任务 |
| 存储重点 | 临时内存状态 | 数据持久化一致性 |
| 算法侧重 | 延迟补偿与预测 | 任务调度与离线计算 |
| 防作弊重点 | 输入验证 | 状态签名与冷却校验 |
1.3 SLG 的工程本质
SLG 服务端的本质,是一个 “分布式任务调度系统 + 状态机框架”。
每一位玩家的世界(城市、军队、科技)都对应一组持久化状态, 服务端持续驱动这些状态随时间演化(资源增长、建造完成、行军抵达)。
因此,与实时帧同步的 MMO 不同,SLG 的关键挑战在于:
- 如何在海量异步任务中保持 状态一致性;
- 如何在千万级玩家下实现 低成本持久化与负载分布;
- 如何确保 事件时间驱动(Time-driven) 的正确性。
1.4 SLG 架构核心思想
SLG 的架构可以简化为以下逻辑模型:
graph TD
Client --> Gateway
Gateway --> Logic
Logic --> Scheduler
Scheduler --> DB[(Database)]
Scheduler --> Cache[(Redis)]
Logic --> MapServer
MapServer --> Logic
| 模块 | 功能说明 |
|---|---|
| Client | 呈现与指令输入 |
| Gateway | 长/短连接管理 |
| Logic | 游戏业务逻辑 |
| Scheduler | 异步事件调度(行军、建筑) |
| MapServer | 世界地图与领地 |
| DB / Cache | 持久化与快速读取 |
二、SLG 架构的演进历程
2.1 第一阶段:单服、单线程(早期页游)
早期页游(如《三国志网页版》《傲视天地》)采用单机架构:
- 所有逻辑运行在单台服务器;
- 任务调度由数据库定时器完成;
- HTTP 短连接轮询获取状态。
缺陷:
- CPU 单点瓶颈;
- IO 阻塞严重;
- 定时器执行精度低;
- 无法水平扩展。
2.2 第二阶段:异步任务驱动 + 多进程架构
随着 Node.js、Go 等高并发语言的普及,SLG 架构进入了事件驱动时代:
- 使用消息队列(MQ)调度任务;
- 每个逻辑节点独立处理一类任务;
- 引入 Redis、Kafka、Crontab。
代表架构:
graph TD
A[Client] --> B[Gateway]
B --> C1[Logic Server]
B --> C2[Map Server]
C1 --> D1[Redis]
C2 --> D2[MySQL]
C1 --> E[Kafka Topic: Events]
优点:
- 可水平扩展;
- 异步任务模型提高吞吐;
- 支持多服与多进程部署。
2.3 第三阶段:分布式 + 世界地图分区
现代 MMO-SLG(如《率土之滨》《三国志战略版》)采用:
- 世界地图按格子或地块划分;
- 每个区域由独立逻辑节点维护;
- 玩家城市与部队分布式存储;
- 使用消息总线进行区域间通信。
三、SLG 服务端分层结构
3.1 总体架构图
graph TD
Client --> Gateway
Gateway --> Login
Gateway --> Logic
Logic --> Map
Logic --> Scheduler
Logic --> Chat
Logic --> DB[(MySQL)]
Logic --> Cache[(Redis)]
Scheduler --> MQ[(Kafka / RabbitMQ)]
3.2 各层职责
| 层级 | 功能 |
|---|---|
| 客户端 | 发起建造、行军、科技升级等操作 |
| 网关层 | 连接管理、认证、限流、路由 |
| 逻辑层 | 游戏规则、资源消耗、战斗计算 |
| 地图层 | 世界状态、地块归属、联盟占领 |
| 调度层 | 定时任务管理(建造/行军) |
| 存储层 | 玩家、城市、建筑、联盟数据 |
| 消息层 | 异步事件、日志、排行榜、统计 |
3.3 Go 语言结构体示例
type City struct {
ID int64
OwnerID int64
Level int
Resources Resource
Buildings []Building
Troops []Troop
}
type Resource struct {
Wood int
Stone int
Food int
Iron int
}
四、异步任务与调度系统
SLG 中最核心的机制是“异步调度”。
4.1 典型任务类型
| 类型 | 示例 | 持续时间 |
|---|---|---|
| 建造任务 | 升级建筑 | 分钟级 |
| 科技任务 | 升级科技树 | 小时级 |
| 行军任务 | 攻城、驻防、采集 | 分钟~小时级 |
| 资源产出 | 每秒增长 | 持续任务 |
| 联盟事件 | 宣战、占领、建造奇观 | 多阶段 |
4.2 调度核心思想
- 所有任务具备开始时间与结束时间;
- 服务器定时触发回调;
- 调度精度通常为秒级;
- 分布式任务避免重复执行。
4.3 Go 实现:异步任务调度器
type Task struct {
ID int64
Type string
StartAt time.Time
EndAt time.Time
Payload []byte
}
type Scheduler struct {
Tasks map[int64]*Task
}
func (s *Scheduler) Tick(now time.Time) {
for _, t := range s.Tasks {
if now.After(t.EndAt) {
go s.execute(t)
}
}
}
func (s *Scheduler) execute(t *Task) {
switch t.Type {
case "BUILD":
handleBuildComplete(t.Payload)
case "MARCH":
handleMarchArrive(t.Payload)
}
}
此模型可进一步结合 Redis ZSet(按时间排序)实现跨节点任务分发。
4.4 分布式调度机制
使用 Redis SortedSet:
- key:
task_schedule - score:
timestamp - value:任务 JSON
调度器节点定期扫描最早的任务执行。
tasks, _ := redis.ZRangeByScore("task_schedule", 0, now)
4.5 分布式锁与幂等控制
- 使用 Redis SETNX 防止重复执行;
- 使用 任务状态机 控制状态流转。
| 状态 | 说明 |
|---|---|
| PENDING | 等待执行 |
| RUNNING | 执行中 |
| SUCCESS | 完成 |
| FAILED | 错误(可重试) |
五、地图系统(Map System)
5.1 地图分区
SLG 世界由若干 区块(Tile) 构成。每个区块记录:
- 坐标;
- 所属势力;
- 地形;
- 资源类型。
type Tile struct {
X, Y int
OwnerID int64
Terrain string
ResourceType string
}
5.2 区块分布与负载均衡
采用 “空间分区 + Hash 一致性” 分配地图负载:
| 模式 | 说明 |
|---|---|
| 规则划分 | 按固定坐标范围分配服务器 |
| 动态迁移 | 根据在线人数调整 |
| Hash 分区 | 坐标 hash 决定分区节点 |
5.3 地图同步与推送策略
SLG 通常采用 区域广播 + 客户端可视范围同步:
sequenceDiagram
Client->>Server: 请求地图(x,y,范围)
Server-->>Client: 返回可见区块
Server-->>Client: 当周边变化时推送更新
5.4 世界状态一致性
- 使用 Redis 缓存热点区域;
- 异步写回数据库;
- 跨区通信使用 Kafka 事件流。
六、战斗系统(Battle System)
6.1 异步战斗模型
SLG 的战斗往往是 离线模拟:
- 玩家发起攻击;
- 服务端计算双方部队属性;
- 执行一轮战斗模拟;
- 异步生成战报;
- 推送结果。
6.2 战斗流程
sequenceDiagram
Client->>Server: Attack(TargetID)
Server->>Server: ValidateResource()
Server->>BattleSim: ComputeResult()
BattleSim-->>Server: Report(Result)
Server-->>Client: NotifyBattleEnd()
6.3 战斗模拟实现(简化版)
func SimulateBattle(attacker, defender Troop) BattleReport {
atkPower := attacker.Soldiers * attacker.Attack
defPower := defender.Soldiers * defender.Defense
result := BattleReport{}
if atkPower > defPower {
result.Winner = attacker.ID
} else {
result.Winner = defender.ID
}
return result
}
6.4 战报系统
战报(BattleReport)为异步消息,可存入 Kafka / Redis Stream。 客户端登录时按分页加载。
七、联盟与社交系统
7.1 联盟结构
type Alliance struct {
ID int64
Name string
LeaderID int64
Members []int64
Territories []Tile
}
联盟功能涉及复杂的权限控制与世界交互。
7.2 频道式聊天系统
采用 Redis Pub/Sub:
- 每个联盟一个频道;
- 全服广播使用 Topic;
- 历史记录通过 Kafka 落地。
7.3 联盟任务与奇观系统
联盟任务是跨玩家合作的典型场景:
- 阶段性进度;
- 服务器全局状态共享;
- 事件广播。
八、通信与同步机制
8.1 协议层选择
| 类型 | 用途 | 传输方式 |
|---|---|---|
| 登录 / 数据同步 | HTTP / gRPC | Request/Response |
| 地图事件推送 | WebSocket | 异步推送 |
| 战斗/行军 | 消息队列 | 异步任务 |
| 聊天 | Pub/Sub | 实时广播 |
8.2 WebSocket 推送(Go)
func (c *Conn) PushUpdate(event string, data interface{}) {
msg, _ := json.Marshal(map[string]interface{}{
"event": event,
"data": data,
})
c.ws.WriteMessage(websocket.TextMessage, msg)
}
8.3 协议压缩与安全
- 使用 Snappy / Zlib 压缩;
- 加密层:AES + HMAC;
- 防止篡改:签名验证(timestamp + token)。
九、分布式与可扩展性设计
9.1 模块划分
| 模块 | 水平扩展方式 |
|---|---|
| 网关层 | 负载均衡(Nginx / Envoy) |
| 逻辑层 | 按用户 ID Hash 分区 |
| 地图层 | 按坐标分区 |
| 调度层 | 分布式定时任务 |
| 数据层 | 分库分表(MySQL Sharding) |
9.2 数据分片示例
玩家ID % 16 = 数据库分区号
9.3 状态一致性策略
- 强一致(Critical):支付、资源;
- 最终一致(Non-critical):排行榜、统计;
- 使用事务消息(Outbox Pattern)确保幂等性。
9.4 弹性伸缩(K8s)
通过 Horizontal Pod Autoscaler 动态伸缩:
- CPU 负载 > 70% → 扩容;
- Idle → 缩容;
- Redis Cluster 自动分片。
十、性能与安全
10.1 性能优化方向
| 层级 | 优化点 |
|---|---|
| 网络层 | WebSocket 连接池 |
| 调度层 | 分布式任务桶 |
| 数据层 | 异步写入队列 |
| 缓存层 | 热点键分布 |
| 消息层 | 批量消费 / 异步提交 |
10.2 防作弊与防刷机制
- 行军冷却校验;
- 签名验证;
- 防时间篡改;
- 建筑队列上限;
- 服务端权威验证。
十一、典型案例分析
11.1 《率土之滨》
- 世界 1024x1024 区块;
- 服务器分区 + 区域联盟;
- Redis 缓存热区;
- 定时任务驱动;
- 战斗异步模拟;
- Kafka 日志追踪。
11.2 《三国志战略版》
- 世界服分层(登录 / 区服 / 世界);
- GeoHash 空间划分;
- 行军与战斗通过任务队列;
- Redis 用作任务时间轮;
- 战报异步生成;
- 联盟领地强一致更新。
11.3 《Clash of Clans》
- 部落系统采用一致性 Hash;
- 数据完全持久化;
- 战斗离线模拟;
- 全球化分布式部署。
十二、未来趋势:AI + Cloud + Simulation
| 方向 | 描述 |
|---|---|
| AI 代理玩家(AI Agent) | 模拟玩家行为、自动决策 |
| 云原生 SLG | MapServer 动态分配 |
| 可验证游戏(Verifiable Game) | 区块链状态签名验证 |
| 分布式仿真引擎 | 状态更新通过物理时钟驱动 |
| 跨世界交互 | 多服联盟、全球匹配 |
十三、总结:SLG 的架构哲学
SLG 是一类 以时间为核心变量 的分布式系统。 它不像 MMO 那样追求实时性,而是在“持久性与正确性”之间平衡。
MMO 解决“现在的世界”; SLG 解决“未来的世界”。
它的工程本质是:
- 一个全局时间驱动的状态机;
- 一个分布式任务系统;
- 一个数据一致性的长期仿真系统。