每个全局功能(需要和其他玩家交互的功能,例如聊天,公会,副本和场景等)都作为一个独立服务来做,方便扩展。这个服务可以是逻辑服务器内嵌的(如果没有与其他服务器交互的需求),也可以是一个单独的服务器,甚至一个服务器集群。
在分区游戏中,很多时候某些全局功能都作为一个功能模块内嵌到逻辑上去了,这样在某些需要服务器间玩家交互的功能时,就会很难做。例如: 如果聊天/好友服务内嵌到逻辑服务器上时,玩家如果需要与其他服务器上的好友(在跨服功能中加为好友的)通信时就会很麻烦。
大多可能有很大压力的全局功能都采用服务器集群的做法,集群中的成员:
- 一个或多个(分层的或平行的)管理服务器,职责:
- 根据某种策略(id 哈希/映射,服务器压力统计等)路由外部请求到具体的工作服务器;
- 工作服务器的新增(外部请求或根据工作强度向其他服务请求启动新的工作服务器);
- 工作服务器的停机
- 多个工作服务器,职责:
- 根据请求 id,处理对应的模块实体;
- 向管理服务器汇报服务器压力
实现:
gate
- 多个 gate 管理服务器,外网接入:
- 由 DNS 根据线路等指向或者固定 ip,client 接入时,会根据玩家的线路和 gate 的压力情况选择适合的 gate ip:port 返回给玩家;
- gate 接入,外网 ip:port 注册
- 多个 gate ,外网接入:
- 玩家接入,认证等等;
- 向 gate 管理服务器发送在线压力情况;
- 和在线统计服务器和逻辑服务器合作,负责玩家的登入及之后的消息中转
登入
-
一个或多个在线统计服务器:
- 如果不存在玩家记录,根据策略(id 哈希,服务器压力等)选择一个逻辑服务器供玩家登录 [player: zzz, id: xxx, ref: yyy];
- 如果存在玩家记录,直接返回其所在逻辑服务器 [player: zzz, id: xxx, ref: yyy+1](引用加1,防止逻辑服务器的错位删除)
- 监控逻辑服务器的状态,逻辑服务器宕机后,标记其状态为宕机,避免玩家登入时再次接入已经宕机的逻辑服务器。
- 做成无状态的服务,所有数据都存 Redis(这些数据都是在线玩家和所在逻辑服务器的映射,只需存在内存中),避免过多的逻辑,以及宕机后的自动恢复。 (服务与存储分开的关键是,数据能够原子的更新, Redis 的 Lua Script 都可以做到这点。当然,也可以写一个定制的内存服务程序来解决这点。)
-
多个逻辑服务器:
- 玩家个体逻辑的大部分功能都由该服务器实现 (如果玩家逻辑功能比较复杂,可以用动态语言+虚拟机方式实现,这样当某个玩家或某个功能出现异常时,缩小影响范围);
- 在玩家登出后的有限时间内清空玩家数据,并向在线服务器(或 Redis)发送清空玩家对该服务器的引用[player: zzz, ref: yyy]
client 在 gate 完成登录认证,由 gate 向在线统计服务器发送请求选择逻辑服务器 [id: xxx, ref: yyy] , gate 向逻辑服务器发送玩家的登入请求 [player: zzz, ref: yyy] ,玩家进入游戏。