Skip to content

核心服务角色 ​

Category ​

server / services 子树。节点定位:服务角色划分单独讨论——每个角色真正解决什么、边界污染形态、边界稳比角色多更重要。

Definition ​

系统开始拆分以后,最常见的问题往往不是“服务不够多”,而是名词很多、职责很乱。大家都在说房间服、场景服、活动服、账号服,但一落到实现里,房间服顺手写资产,活动服顺手推进局内状态,网关顺手做半套业务编排,最后服务名字分开了,状态边界还是混着的。

所以这里要做的不是罗列常见名词,而是把这些角色背后的责任和状态归属讲清楚。

Problem ​

「服务不够多」不是问题,「名词很多、职责很乱」才是:房间服顺手写资产、活动服顺手推进局内状态、网关顺手做半套编排——名字分开了,状态边界还混着,等于没拆。

为什么角色划分必须单独讨论 ​

上一节解决的是“为什么拆”和“边界先围绕什么画”;这一节解决的是“拆出来以后,哪些角色最容易稳定下来,哪些角色最容易做脏”。

在真实项目里,大多数系统最终都会围绕几类典型角色组织:

  • 面向连接和会话的角色
  • 面向运行时实例的角色
  • 面向长期资产和外围能力的角色
  • 面向调度和治理的角色

如果这些角色没有分清楚,系统通常会走向两个结果:

  • 某个服务什么都接,最后变成新的大单体
  • 名字虽然拆开了,但状态和责任仍然交叉缠绕

常见服务角色真正各自解决什么问题 ​

1. 网关 / 接入服务 ​

这类服务最核心的价值是维护连接和会话入口。它通常负责:

  • 连接建立、断开、心跳、限流
  • 鉴权后会话绑定
  • 基础协议转换和入口路由
  • 踢线、封禁、基础接入治理

它通常不应该负责:

  • 重业务逻辑
  • 高代价数据库事务
  • 房间、场景或世界状态推进

网关之所以常被做坏,是因为它看起来“离玩家最近”,于是所有临时逻辑都往里塞。结果连接层和业务层互相污染,故障和性能问题都更难定位。

2. 账号 / 角色服务 ​

这类服务更接近长期身份与角色基线治理。它通常负责:

  • 账号信息与角色档案
  • 登录入口和角色选择
  • 基础角色状态读取
  • 局外资产入口或资产主索引

它不适合承担高频局内状态,也不应该变成“什么都能顺手查一下”的万能入口。账号服务如果不断被塞入玩法运行时状态,后面很容易变成最难拆的核心耦合点。

3. 匹配 / 调度服务 ​

匹配服务不只是把玩家凑成一桌。它往往承担:

  • 匹配分桶与规则计算
  • 队伍组织与开局前校验
  • 房间创建请求
  • 节点选择与实例分配
  • 开局前的状态协调

从工程视角看,匹配层其实是很多会话型游戏进入调度体系的第一道入口。

4. 房间 / 副本 / 战斗实例服务 ​

这一类服务的核心特征是实例态强、生命周期相对短、边界和一局或一个副本直接绑定。它们通常负责:

  • 高频运行时状态推进
  • 玩家输入处理与广播
  • 局内权威状态维护
  • 重连上下文和托管上下文
  • 结算前的最终运行时结果

这类服务最怕被塞入长期资产写入、全局规则解释和外围查询逻辑,因为它们的目标应该是让局内主链路尽可能单纯、稳定、低延迟。

5. 场景 / 世界服务 ​

房间服务强调短生命周期实例,场景或世界服务强调长期存在的共享空间。它们通常区别在于:

  • 状态是否长期驻留
  • 是否有多人共存和公共空间
  • 是否存在区域切换和世界迁移
  • 是否承担持续在线的世界规则维护

MMO、大地图、生存沙盒项目里,这类服务往往是系统主干。它们的难点不只是同步,还包括区域管理、热点治理和控制权迁移。

6. 活动 / 任务 / 商店等外围业务服务 ​

这类服务更适合围绕长期规则、配置解释和进度治理组织,常见职责包括:

  • 活动规则解释
  • 任务或活动进度维护
  • 奖励发放请求
  • 商店状态、购买约束和兑换记录

它们最大的问题通常不是“功能多”,而是边界容易失控。一个活动服务如果同时承担配置、进度、发奖、报表和跨服编排,后面每次改动都会变成系统级连锁反应。

7. 排行 / 邮件 / 社交 / 聊天等公共能力服务 ​

这些能力通常跨玩法、跨场景复用,因此边界是否清楚非常关键。

  • 排行更像读取、聚合和展示能力,不应该反向侵入战斗主链路
  • 邮件和补偿更像长期资产外围投递链路
  • 聊天与社交有自己的连接、广播和关系模型,不适合和局内同步混在一起

它们之所以容易被低估,是因为平时不在主战斗循环里,但一旦边界不清楚,就会在全系统里产生隐性耦合。

8. 支付 / 订单 / 风控服务 ​

这类服务通常不在玩法主循环上,但它们的边界往往比玩法服务还稳定。常见职责包括:

  • 订单状态机
  • 回调确认与发货触发
  • 异常订单处理
  • 审计、风控和追责链路

这类服务最怕“顺便做一下”。因为一旦资产和订单链路出错,修复成本远高于普通玩法问题。

9. 协调层 / 控制平面相关服务 ​

很多项目在早期没有正式把它们算作服务角色,后期却一定会补上。它们通常负责:

  • 节点注册、分组和健康治理
  • 区服路由和实例分配
  • 迁移、摘流和切流
  • 扩缩容编排
  • 全局配置下发和版本门禁

它们本身不推进业务状态,却决定整个系统是不是能被稳定调度和恢复。

这些角色最常见的边界污染 ​

长期资产和实例态混在一起 ​

比如房间服直接写长期资产,账号服直接推进副本状态,活动服直接持有局内高频状态。前期看起来省事,后期会同时拉高耦合、恢复成本和故障影响面。

规则解释和状态维护混在一起 ​

尤其容易出现在活动、任务、商城这类系统里。配置解释、进度维护、奖励发放、统计报表如果长在同一个服务里,每次小改动都可能影响整条链路。

把网关做成业务总线 ​

网关一旦开始承担过多业务判断,它就不再只是接入层,而会变成最难拆、最难测、最难排障的隐性总线。

角色不是越多越好,而是边界越稳越好 ​

列出这么多角色,不意味着每个项目一开始就该全部拆出来。真正应该问的是:

  • 这些职责是否已经足够稳定
  • 拆出来是否能减少跨服务抖动
  • 是否值得独立扩缩容和治理
  • 是否有独立故障域和独立运维价值

早期一个服务兼任多个角色并不罕见,问题不在于是否合并,而在于逻辑边界有没有先被说清楚。边界清楚,后续才能平滑外提;边界不清楚,拆不拆都乱。

一个更实用的观察框架 ​

建立直觉时,可以先把这些角色看成四层:

  • 连接与会话层:网关、接入、会话绑定
  • 运行时状态层:匹配、房间、副本、场景、世界
  • 长期资产与公共能力层:账号、活动、支付、邮件、排行、社交、风控
  • 系统治理层:协调层、控制平面、路由、编排、监控

这不是固定部署图,但它能帮助团队避免“所有东西都叫业务服”的混乱。

常见误区 ​

最常见的错误,是把服务名字当成边界,以为起了“房间服”“活动服”“账号服”这些名字,职责就自动清楚了。第二类错误,是让同一个服务同时承担连接、实例态和长期资产三种职责。第三类错误,是忽视协调层和控制平面的独立角色,结果业务逻辑能跑,系统却无法稳定调度、迁移和恢复。

实战案例:一次「网关越做越胖,一次改动全网抖」的业务总线化排查 ​

案例为教学示例(非摘自真实项目),数字经过取整简化。它把本页「1. 网关 / 接入服务」「把网关做成业务总线」「角色不是越多越好,而是边界越稳越好」用到深水区:改的是限流,抖的是全服——这是服务名字分开了、状态边界还混着的排查,也是「怎样让边界稳而不是角色多」的完整展开。

背景与现象:某 MMO 的网关服务,从最初的连接接入层一路长到 8 万行代码、内嵌 30 多个业务逻辑点。一次只改限流策略的小发布,引发全服登录异常 20 分钟——影响面从单模块扩到了所有接入玩家。

第一步:现象与口径——先看故障影响面有多大 ​

影响面口径:网关每次发布影响全部接入玩家,单次故障影响面按全服算;同期业务服务发布只影响对应玩法。

改动口径:30 多个业务逻辑点(订单校验、活动状态查询、部分结算触发)都长在网关里,任何一处改动都要重新回归整条接入链路。

定位口径:网关内连接层与业务层互相污染,同类故障平均定位耗时 4 小时——排障时说不清是接入问题还是业务问题。

第二步:分层归因——按本页边界污染清单排查 ​

text
故障影响面扩散归因  占比
  网关承担重业务逻辑与半套业务编排    57%
  房间服顺手写长期资产                25%
  活动服持有局内高频状态              18%

逐项比对:网关里塞了业务编排(本页说网关「离玩家最近,于是所有临时逻辑都往里塞」);房间服顺手写长期资产;活动服持有局内高频状态。三类污染都在,网关那条影响面最大。

第三步:根因——把服务名字当成了边界 ​

起了「网关」这个名字,团队以为职责自动清楚了,实际上连接、实例态和业务逻辑在同一进程里混着。网关一旦承担过多业务判断,就不再只是接入层,而是最难拆、最难测、最难排障的隐性总线。

第四步:处置与回填——按角色重新划边界 ​

  1. 网关瘦身:只保留连接建立断开、心跳、限流、鉴权后会话绑定、基础协议转换和入口路由,业务判断全部外提到业务服务。
  2. 长期资产与实例态分离:房间服不再写长期资产,资产变更统一走账号/资产服务;活动服不再持有局内高频状态。
  3. 边界写进角色定义评审:每个服务明确「负责什么、不负责什么」两栏,评审时逐条对照。

复核账:网关代码 8 万行 → 2.1 万行;故障影响面从全服收敛到单模块;同类故障平均定位耗时 4 小时 → 40 分钟;限流策略改动的发布回归范围缩小到网关自身。

回填清单:

回填项动作回填处
网关职责边界网关只留连接、会话、鉴权、路由,业务判断外提到业务服务1. 网关 / 接入服务
长期资产与实例态分离房间服不写长期资产,账号服不推进副本状态,资产变更走资产服务长期资产和实例态混在一起
规则解释与状态维护分离活动服的配置解释、进度维护、发奖、报表拆开,不挤在一个服务里规则解释和状态维护混在一起
角色边界评审每个服务写「负责/不负责」两栏,边界稳优先于角色多角色不是越多越好,而是边界越稳越好

案例的三个教训 ​

  1. 服务名字不等于边界。起了「网关」不等于职责清楚,连接、实例态、业务逻辑混在一个进程里,故障影响面就按最大者算。
  2. 离玩家最近的服务最容易长成隐性总线。网关一旦开始承担过多业务判断,就变成最难拆、最难测、最难排障的那一环。
  3. 边界稳比角色多重要。拆不拆是后话,先把每个服务的「负责/不负责」说清楚,才谈得上平滑外提。

Used By ​

服务角色定义评审;边界污染排查。

  • BigWorld(commit 088d3b84,路径相对 programming/bigworld/):base/cell 双形态角色分工——玩家代理 class Proxy : public Base 挂 baseapp(server/baseapp/proxy.hpp:74),真身 class Cell 挂 cellapp(server/cellapp/cell.hpp:45),八类服务进程各有独立 main(server/baseapp/main.cpp、server/cellapp/main.cpp 等)
  • KBEngine(commit 0bc93d5):角色划分是显式枚举——enum COMPONENT_TYPE 把十余类组件类型与 ID 一并定死(kbe/src/lib/common/common.h:73-91),实体跨进程调用封装为 EntityCall(kbe/src/lib/entitydef/entity_call.h:15),baseapp→cellapp 建实体流走 createCellEntity(kbe/src/server/baseapp/entity.cpp:27-28)

关系链:角色独立讨论 → 各角色解什么 → 边界污染 → 边界稳 > 角色多 → 观察框架。上游:services/01(四问定边界)。下游:server/sync(对局角色的展开)、glossary/07(控制平面)。

Reference ​

本页为工程经验归纳;页内实战案例为教学示例(数字取整简化)。

游戏知识体系