五邑隐侠,本名关健昌,10年游戏生涯,现隐居海边。nginx
本教程以Go语言分区游戏服务端框架搭建为例。web
Go语言是Google开发的一种静态强类型、编译型、并发型、具备垃圾回收功能的编程语言。语法上近似C语言,支持接口、可经过struct包含另外一个struct方式实现继承等面向对象的概念。性能上媲美C/C++,相比C/C++更健壮,更易开发并发程序。我之前也写C++服务端,接触Go后,更倾向用Go作游戏服务端开发。redis
所谓分区游戏,指游戏将分为不少个区,不一样区之间玩家不能互动或只有少许互动。玩家进入游戏须要选择分区,进入指定分区进行游戏,一个玩家能够同时在不一样分区有角色。目前市面上大多中重度网络游戏都采用这种模式,分区游戏适合不须要大DAU互动的游戏,如卡牌、MMORPG、SLG等。从技术层面,分区属于集群扩容的一种手段;运营上,有利于分区精细运营,滚服运营已是比较成熟的游戏运营手段。相对分区游戏,也存在不分区的社交游戏,这类游戏核心玩法是匹配对抗,例如COC。若是把分区游戏的分区,映射为该类游戏的节点服,广播服映射为匹配服,对不分区游戏的架构也就很好理解。数据库
本教程主要讲分区游戏服务端框架搭建。整体设计以下:编程
分区游戏,玩家先登陆游戏,而后进入指定分区。因此首先要有一个登陆服务器,提供全局的登陆服务。登陆服务器的核心数据是玩家帐号,核心业务是对玩家进行登陆校验,包括使用自有帐号系统、第三方帐号登陆。帐号数据须要落地长期存储,因此在该服务器配套一个MySQL数据库,用于保存玩家帐号信息。有一到多个登陆服务进程,进行游戏登陆校验。登陆服务是一个短链接服务,使用http协议,对外经过nginx提供统一访问地址,对多个登陆服务进程作负载均衡。一般,登陆接口还会返回分区信息、玩家各分区角色简要信息、客户端最新版本号、配置版本、资源版本、公告等,这些信息能够经过gm服务(后面会介绍)动态更新,登陆服在响应请求时获取并返回给客户端。因此在登陆服务器会配套一个redis服务,用于这些数据的缓存。
缓存
玩家登陆游戏成功后,将进入选定游戏分区。分区是一组服务进程。大部分游戏分区都采用长链接通讯,若是同时兼顾如今热门的h5游戏、微信小游戏,考虑选用websocket作通讯(之前使用socket)。考虑到游戏中会有广播的需求,广播数据和分区游戏数据都但愿从同一个链接返回给客户端,有必要提供一个统一的分区入口网关服,网关服进程对客户端提供统一的分区地址和端口,对内作数据转发。分区的逻辑业务能够集中放在一个游戏服进程里。之前一些游戏,游戏服在线数据会保存在进程内存里,因为游戏数据变化太频繁,MySQL 频繁读写性能不高,因此会隔必定时间才保存到MySQL。但分区内游戏服是一个单点,一旦崩掉,游戏服的内存数据就会丢失,回档到上一次保存的时间。后来一些游戏为了减小这种风险,把在线数据保存到共享内存,再定时保存到MySQL。共享内存依赖系统和语言,目前发现Go没有直接支持。再后来有了memcached和redis,部分游戏选择用这种缓存系统作缓存,游戏服崩掉,数据还在缓存里不会丢失,能够快速启动游戏服恢复服务。我选用redis做为缓存,缓存活跃玩家数据。隔必定时间,把变化数据保存到MySQL。redis数据主要使用key-value方式保存数据,每次业务处理都须要读取、解析,再使用。对业务开发不是很友好。游戏服进程内存仍是会保存在线玩家数据,玩家进入分区时从redis读取到游戏服内存,redis不命中则发布消息给数据服进行数据预热,预热成功后从redis读取。后面的请求能够直接经过内存数据作业务判断、处理,更改数据以事务方式保存到redis,成功后响应给客户端。这样内存数据跟redis数据一致,并且能够把玩家数据拆成更细的单元,减小跟redis间的通讯。玩家下线后清除游戏服内存数据。因此分区内配套一个redis、一个MySQL。为了创建定时保存数据这个机制,且不会因游戏服崩溃而受影响,配备一个功能很简单的数据服,经过redis的发布订阅机制、消息队列,负责数据的定时落地固化、玩家注册、数据预热。服务器
前面提到广播服,广播服顾名思义主要负责广播,例如跑马灯广播、世界聊天、世界boss。广播服经过各个分区的网关服将数据广播给玩家,所以广播服将链接各个分区网关。广播任务经过消息队列进行缓存,这样每一个分区的广播操做在写到队列后就能够响应客户端。消息队列采用redis实现。广播服是一个全局的服务,为了不单点风险,能够作成主从,经过redis的订阅发布机制,启动时订阅redis,若是必定时间没有收到发布消息,认为主服务不存在,切换为主服务,取消消息订阅,链接各分区网关,定时向redis发布消息报活。微信
除了业务相关的服务,须要对整个服务体系提供管理。例如开服、停服、更新配置/资源版本、发邮件、发公告、发放道具、踢人等。提供一个全局的gm服,各分区服务启动后,游戏服进程链接到gm服并保持心跳,以通知gm服开/停服。gm服将这些变动信息更新到登陆服的redis,这样玩家登陆游戏就知道各个服的状态。gm服还能够经过向redis发消息通知登陆服进行封号等操做。因为各个游戏服都链接到gm服,这样就能够对各个分区发gm命令。gm服能够经过向广播服的消息队列写消息发全员广播。gm服的功能由运营人员进行操做,因此须要提供http服务,方便在网页上访问。gm服有道具发放的功能,因此第三方支付回调能够经过gm服的http接口请求发货。websocket
为了给运营提供决策,还须要提供统计后台,对游戏数据日志进行收集、统计。因为登陆服、各分区的游戏服、gm服都会上报数据,数据来源广,数据量大,须要作消息队列。所以登陆服、游戏服、gm服都经过redis的消息队列进行上报。统计服从redis读取消息,保存数据日志到MySQL。所以须要配套一个redis、一个MySQL。统计服的功能由运营人员使用,须要提供http服务,方便在网页上访问。统计服的http接口还支持客户端进行数据上报。网络
为了合并运营人员的页面,gm服、统计服经过nginx提供统一的http地址。
这样就获得了如前面设计图的整个服务框架。
本篇介绍到这里,接下来会详细介绍各个服务的实现。在此以前,下一篇先介绍一些通用的基础机制设计和实现。