一、参考游戏服务器架构通识
早期网游服务器
早期游戏服务器的改进版本
按照功能划分多个服务器进程
按照场景划分多个服务器进程
对游戏服务器历史有了基本了解后,成熟形态的游戏服务器很容易理解。简单来说,就是把逻辑服务器单个进程的压力分摊到多个服务器。难点在逻辑的设计上,要像做手术一样把本来是一体的功能切开,并抽象出若干个API来保持联系(服务器之间是TCP连接)。
在分解时,要找联系相对最薄弱的环节入手,比如场景和场景之间分开、单独抽出聊天服务、组队服务、好友服务。无论如何分解,最终结果只能是有限个服务。而且分解的越细,开发难度就越大。因为跨服务器逻辑是把简单的同步逻辑变成了异步Callback逻辑,而且容易出现时序问题等不易测试的问题。
单个场景服务几乎是无法分解的。分解单个场景难度巨大以至于出现了BigWorld引擎来专门的解决场景分割问题,后面会谈到。这种成熟形态的游戏服务器已经能满足现实中99%的频繁交互类网游需求,是大型MMO端游、页游的主流形式。当然有实力的公司在这个基础上会做很多改动,实现动态开辟副本、相位技术等等,但是万变不离其宗,其本质和上图没有什么区别。
二、横向对比
参考
游戏服务器架构和web服务器架构的区别?端游、手游服务端常用的架构是什么样的?
在架构上面,一般访问量不是很大的网站是只有一台服务器的,访问量高的才会进行分布式设计或者集群设计。而大部分游戏服务器都是需要分布式设计的。在现有的网络游戏服务器端架构中,多是以功能和场景来划分服务器结构的。具体的划分是根据项目的需求进行的,并没有一个十分通用的架构。
以上是比较常见的结构,客户端登录的时候,连接GateServer,然后由GateServer去连接LoginServer进行登录。登录后通过CenterServer转发到GameServer(GameServer即是服务器大区)。而其中的DCServer,主要的功能是缓存玩家角色数据,保证角色数据能快速的读取和保存。LogServer便是保存日志的了。
当一个网站访问人数很庞大的情况下,单独去提升一台物理机配置能够带来的性能提升会因为边际效应逐渐减小。这时候就需要考虑使用集群了。集群有三种,高可用集群, 负载均衡集群,科学计算集群。其中最常见的便是负载均衡。很多情况下,集群之间是不需要互相交互的,数据都在单个服务器上进行处理,也就没了同步的问题(相比游戏服务器要简单了多)。相对于游戏的难点就在于游戏我们可以通过分区分服甚至分频道等方式来减小服务器负载压力。而网站是无法这样让用户分区之类的操作。甚至是需要,全国各地乃至全球各地访问到这个网站都是同样的用户数据(针对这种情况我们会使用cdn,部署网络各地的节点服务器可以使得不同地方的人员访问网站的速度是一致流畅的)。所以并不是网站业务简单就轻率的认为网站开发没有技术含量。
游戏服务器,因为可以分区分频道等,所以很多情况下一台服务器的负载量要求不会太高。像手游的服务器,甚至要求可以低至同时在线200人。而且有些时候我们仅需要提高某一些功能的负载量,又或者大型3D游戏存在地图,这些情况下,我们往往使用分布式架构来解决。如分离聊天、好友之类的功能,如给每个区域分配一个单独的房间/地图/场景服务器。
三、Golang 游戏框架汇总
https://github.com/davyxu/cellnet
https://github.com/name5566/leaf
https://github.com/liangdas/mqant 部分框架对比,参考mquant作者的WIKI:mqant的设计动机
https://github.com/viphxin/xingo
https://github.com/heroiclabs/nakama
https://github.com/lonng/nano[Golang]四川麻将玩法, 血战到底(三人模式/四人模式)服务器代码开源, 功能一应俱全, 可以作为学习 nano 的示例
https://github.com/chrislonng/starx
四、达达的Go语言网络层脚手架https://github.com/funny/link
参考
GoCN第一期《老司机带你看Go风景》——游戏达人达达知乎 如何使用 Go 语言写游戏服务器?
最初开发这个包的目的是提炼一套可以在公司内多个项目间共用的网络层,因为在项目中我发现不同的网络应用一直重复一些相同或相类似的东西,比如最常用到的就是会话管理,不管是做游戏的前端连接层还是做服务器和服务器之间的RPC层或者是游戏的网关,虽然协议不一样但是它们都会需要会话的管理。会话管理看似简单,但是任何简单的问题一旦涉及到并发都会变得复杂起来,所以看似简单的会话管理每次实现起来都得再配套做单元测试甚至线上实际运行几个版本才能放心。所以我决定提取这些公共的部分,避免那些容易引入BUG的重复劳动。
.
但是在提取这些公共部分的时候并没有期初想象的那么容易,因为不同的应用场景有不同的需求,比如有的场景需要异步,有的场景需要同步,有的协议需要握手过程,有的则需要keepalive。从代码的提交历史里面可以看出这个包前后经过了很多次大的调整,因为要做一个能满足所有需求的通用网络层真的很难。
.
重构过程就像在简化公式,经过不断的提炼目前link变得十分的简单,同时它的定位也很清楚。link不是一个完整网络层也不是一个框架,它只是一个脚手架,它可以帮助你快速的实现出你所需要的网络层或者通讯框架,帮你约束网络层的实现方式,不至于用不合理的方式实现网络层,除此之外它不会管更多的事情。
.
link是协议无关的,使用link只需要理解少数几个概念就可以上手了。
五、Go游戏服务器开发的一些思考 系列文章