Go游戏服务端框架从零搭建(一)— 架构设计

  五邑隐侠,本名关健昌,10年游戏生涯,现隐居海边。

  本教程以Go语言分区游戏服务端框架搭建为例。

  Go语言是Google开发的一种静态强类型、编译型、并发型、具有垃圾回收功能的编程语言。语法上近似C语言,支持接口、可通过struct包含另一个struct方式实现继承等面向对象的概念。性能上媲美C/C++,相比C/C++更健壮,更易开发并发程序。我以前也写C++服务端,接触Go后,更倾向用Go做游戏服务端开发。

  分区游戏,指游戏将分为很多个区,不同区之间玩家不能互动或只有少量互动。玩家需要选择分区进入指定分区开始游戏,一个玩家可以同时在不同分区有角色。目前市面上大多中重度网络游戏都采用这种模式,分区游戏适合不需要大DAU互动的游戏,如卡牌、MMORPG、SLG等。从技术层面,分区属于集群扩容的一种手段;运营上,有利于分区精细运营,滚服运营已经是比较成熟的游戏运营手段。分区的基础上,可以按相邻分区编号设置跨服服务,例如10个分区一组设置跨服服务,用于跨分区的玩法。相对分区游戏,也存在不分区的社交游戏,这类游戏核心玩法是匹配对抗竞技,例如COC。简单的匹配竞技游戏可以把分区游戏的分区改为节点,把跨服服务拆分成匹配服务和多个竞技服务,匹配服务只做简单的报名和匹配,匹配成功后把玩家分配到指定的竞技服务,并在里面分配房间开始游戏。

  搭建分区游戏服务端框架,首先建立一个服务注册发现机制。我们以注册服作为机制的核心,提供服务注册,以及服务信息广播。作为游戏主体,分区的游戏服务组是注册的对象。游戏服务组的主服务“游戏服”启动成功后,连接注册服,并注册该服务组。这样注册服知道所有分区的基本信息和状态。分区注册后,有哪些服务需要发现分区、关注分区的状态变化?对于玩家,登录后要知道有哪些分区以及状态情况。所以账号服需要发现分区。玩家通过登录返回知道分区情况,选择分区进入游戏。而玩家是通过网关连接分区的,所以网关需要发现分区。分区注册后,需要切换状态来支持开服测试、开服、维护。一般会搭建一个管理服,运营人员可以通过管理服发指令给分区更改状态。所以管理服也需要发现分区。这样得到第一个框架模型如下:

Go游戏服务端框架从零搭建(一)— 架构设计

  按照这个模型,先启动注册服等待其他服务注册。然后分别启动管理服、账号服、网关,这些服务注册到注册服。新开一个分区就启动该分区游戏服务组,分区状态为开服测试。该分区连接并把状态信息发给注册服。注册服通知管理服、登录服、网关该分区状态变化。网关连接该分区的游戏服。这时候测试账号可以登录进入该分区开始测试。测试通过后管理服可以发指令更改该分区状态为正常正式开服,分区更新状态并发送给注册服进行广播。同理当分区需要维护时,管理服发指令给该分区更改状态为维护。网关收到注册服广播后,断开与该分区服务的连接,等待一段时间后该分区的服务可以关闭进入维护。这样一个注册发现的流程算是跑通了。

服务间除了注册发现关系外,它们也互相连接调用。下面来分析一下各服务间关系。账号服不与其他服务保持连接。对客户端提供http登录,通过使用同一key对称加解密token,实现帐号服和游戏服间跨服务校验。每个客户端与一个网关保持长连接。对于通信量和频率不高的卡牌游戏,为提高网关复用,可以让每个网关都连接所有可进入的分区游戏服务组,客户端连接任一网关都能进入所有可进入的分区。游戏服务组的业务请求主要由客户端通过网关转发过来,小部分为管理服发送过来的gm指令。管理服连接所有游戏服务组,对外提供http请求,将gm命令转发到对应的游戏服务组。这样得到第二个框架模型如下:

Go游戏服务端框架从零搭建(一)— 架构设计

  接下来看看分区的服务怎样划分。先看一个简单的情况。分区有一个主服务,负责注册到注册服、处理玩家的基本请求,包括分区登录、玩家基本信息操作、养成等业务。这些业务都需要频繁修改玩家数据,应避免直接操作数据库,因此使用redis做缓存,主服务直接操作redis上的数据。redis数据要有一个落地的机制避免redis崩溃或数据过期后数据丢失。这里选用mysql做固化数据库,玩家的游戏数据会从redis固化到mysql。对于redis上数据已过期的玩家再次登录,还需要把数据从mysql加载到redis。所以这里增加一个数据服,负责数据的预热和落地。一个基本的流程,玩家进入分区,主服务处理请求,从redis获取玩家数据,redis上不存在该玩家数据,主服务通过redis发布消息给数据服预热该玩家数据,数据服查询mysql,如果mysql没有该玩家数据,数据服往mysql新加一条玩家数据注册个新玩家,数据服把玩家mysql的数据添加到redis,数据服发布消息通知主服务该玩家数据已准备好,主服务继续从redis获取该玩家数据,返回给客户端。后续的业务请求,主服务读取redis的玩家数据进行业务处理、回写redis,发布消息给数据服该玩家redis数据有更新,返回响应给客户端。数据服定时将有更新的玩家redis数据保存到mysql。这样分区的基本流程也能跑通。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpyww.html