跨服通信方案
概述
分片之后,跨节点协作成为常态:跨服好友、跨服对战、跨服排行榜。跨服通信的核心是RPC(同步调用/异步回调)与消息路由(把请求送到正确的节点)。本文对比 RPC 框架(gRPC/Dubbo/Thrift)、设计跨服消息路由与服务发现,并给出跨服 Battle 方案。
一、RPC 框架选型
1.1 框架对比
| 框架 | 协议 | 特点 | 适用 |
|---|---|---|---|
| gRPC | HTTP/2 + Protobuf | 跨语言、流式、生态好 | 通用/跨语言 RPC |
| Dubbo | 自研 TCP | Java 生态、服务治理强 | Java 微服务 |
| Thrift | 自研 | 多语言代码生成 | 遗留系统 |
游戏服务器场景:
内部逻辑节点通信 → gRPC(Protobuf 已有)或自研二进制 RPC
跨服(独立服之间)→ gRPC
微服务拆分 → Dubbo(Java 生态治理)
选型考虑:
协议效率(游戏要求低延迟)
序列化(复用 Protobuf 章节)
治理能力(注册/负载/超时/重试)// gRPC 服务定义(Proto)
service GameService {
rpc SendToPlayer(PlayerMsg) returns (CommonReply);
rpc CreateRoom(RoomReq) returns (RoomReply);
}1.2 RPC 设计要点
RPC 关键设计:
超时控制(跨节点网络不稳定)
重试与幂等(网络重试可能重复执行)
熔断(下游故障保护)
异步化(游戏主流程不阻塞等 RPC)
超时策略:
不同操作不同超时(查询 1s / 创建房间 3s)
超时兜底(本地降级/缓存)二、跨服消息路由
2.1 路由模型
路由层级:
网关 → 逻辑节点(玩家分片路由)
逻辑节点 → 跨服(目标服/目标服务)
消息寻址:
playerId → 玩家所在服/节点
roomId → 房间所在节点
service 名 → 服务实例(服务发现)
路由表:
全局会话(Redis):playerId → 节点(见网关章节)
服务实例表:服务名 → 实例列表(服务发现)// 跨服调用示例(定位目标)
String target = globalSession.lookup(targetPlayerId);
if (!target.equals(selfNode())) {
gameRpcClient.call(target, "SendToPlayer", msg);
} else {
localHandle(msg); // 本地直接处理
}2.2 跨服调用模式
同步调用(ask):
适合短查询(查玩家状态)
有超时与失败降级
异步调用(tell):
适合通知(好友上线通知)
不等待结果
消息队列解耦:
跨服事件(聊天广播)→ MQ 投递
适合非实时/可延迟(见消息队列章节)// 跨服 Battle 请求(异步回调模式)
NodeClient remote = router.route(targetNode);
remote.invoke("JoinCrossRoom", req)
.whenComplete((reply, err) -> {
if (err != null) {
handleFail(req); // 降级处理
} else {
handleJoinResult(reply);
}
});三、服务发现
3.1 注册与发现
服务发现:
节点启动 → 注册(服务名/地址/负载)
调用方 → 查询可用实例 → 负载均衡
方案:
Nacos(Java 生态、配置中心一体)
Kubernetes Service(容器编排自带)
Consul/Eureka(传统)
游戏场景:
逻辑节点数量动态(扩缩容)→ 自动注册/摘除
网关查逻辑节点地址 → 服务发现// Nacos 注册示例
NamingService naming = NamingFactory.createNamingService(serverAddr);
naming.registerInstance("game-logic", ip, port);
List<Instance> list = naming.selectInstances("game-logic", true);3.2 负载均衡
负载均衡策略:
轮询/加权(普通服务)
一致性哈希(有状态分片,见分片章节)
最小连接(连接型服务)
关键:
游戏逻辑有状态 → 路由必须一致(不能随机)
负载均衡只用于无状态服务(网关/查询)四、跨服 Battle 方案
4.1 方案对比
方案一:房间迁移(玩家前往房间所在服)
创建跨服房间 → 玩家连接跨服
适合对战型(状态集中)
方案二:中继服务器(Battle Server)
独立对战集群 → 玩家进入战场服
适合大型实时对战
方案三:分片协作(两个节点共建)
状态分布两个节点 → 同步复杂
一般不用(一致性成本高)4.2 房间迁移式跨服对战
跨服 Battle 流程:
1. 玩家 A(服 1)发起跨服匹配
2. 匹配服务(全局)匹配到玩家 B(服 2)
3. 在服 3(或指定服)创建房间
4. A、B 客户端重连到房间所在服
5. 对战结束 → 玩家回到原服
要点:
玩家状态同步(跨服期间只带必要数据)
对战结果回传原服(结算)
重连与断线恢复(跨服通道)跨服结算:
房间所在服结算 → 结果回传各玩家原服
原服发放奖励(幂等)
排行榜按全局/本服分别统计4.3 跨服可靠性
跨服链路保障:
心跳检测(节点间)
超时重试 + 幂等
房间断线重连(跨服恢复)
对局中断处理(判负/重赛)五、实现要点
设计清单:
RPC 选型(gRPC 通用 / Dubbo Java 生态)
路由分层(网关本地 + 跨服全局会话)
服务发现(Nacos/K8s)自动注册摘除
超时/重试/熔断/幂等
跨服 Battle(房间迁移式)工程注意:
RPC 序列化复用 Protobuf
跨服调用全链路 TraceId(见链路追踪章节)
节点间心跳与故障检测
跨服网络延迟(分地域就近部署)常见坑:
跨服调用阻塞主线程 → 异步化
重试导致重复执行 → 幂等设计
服务发现延迟 → 调用失败重试
跨服数据一致性 → 结果回传 + 对账与其他系统衔接:
分片 → 房间分片章节
全局会话 → 网关章节
MQ 解耦 → 消息队列章节
监控 → 链路追踪章节