

此时游戏服务端已经脱离陈旧的 MUDOS体系,各个公司在参考 MUDOS结构的情况下,开始自己用 C在重新开发自己的游戏服务端。并且脚本也抛弃了 LPC,采用扩展性更好的 Python或者 Lua来代替。由于主逻辑使用单线程模型,随着游戏内容的增加,传统单服务器的结构进一步成为瓶颈。于是有人开始拆分游戏世界,变为下面的模型:
游戏服务器压力拆分后得意缓解,但是两台游戏服务器同时访问数据库,大量重复访问,大量数据交换,使得数据库成为下一个瓶颈。于是形成了数据库前端代理(DB Proxy),游戏服务器不直接访问数据库而是访问代理,再有代理访问数据库,同时提供内存级别的cache。早年 MySQL4之前没有提供存储过程,这个前端代理一般和 MySQL跑在同一台上,它转化游戏服务器发过来的高级数据操作指令,拆分成具体的数据库操作,一定程度上代替了存储过程:
但是这样的结构并没有持续太长时间,因为玩家切换场景经常要切换连接,中间的状态容易错乱。而且游戏服务器多了以后,相互之间数据交互又会变得比较麻烦,于是人们拆分了网络功能,独立出一个网关服务 Gate(有的地方叫 Session,有的地方叫 LinkSvr之类的,名字不同而已):
把网络功能单独提取出来,让用户统一去连接一个网关服务器,再有网关服务器转发数据到后端游戏服务器。而游戏服务器之间数据交换也统一连接到网管进行交换。这样类型的服务器基本能稳定的为玩家提供游戏服务,一台网关服务1-2万人,后面的游戏服务器每台服务5k-1w,依游戏类型和复杂度不同而已,图中隐藏了很多不重要的服务器,如登录和管理。这是目前应用最广的一个模型,到今天任然很多新项目会才用这样的结构来搭建。
这样的模型好用么?确实有成功游戏使用类似这样的架构,并且发挥了它的性能优势,比如一些大型 MMORPG。但是有两个挑战:每增加一级服务器,状态机复杂度可能会翻倍,导致研发和找bug的成本上升;并且对开发组挑战比较大,一旦项目时间吃紧,开发人员经验不足,很容易弄挂。
每台 Node服务器用来管理一块地图区域,由 NodeMaster(NM)来为他们提供总体管理。更高层次的 World则提供大陆级别的管理服务。这里省略若干细节服务器,比如传统数据库前端,登录服务器,日志和监控等,统统用 ADMIN概括。在这样的结构下,玩家从一块区域走向另外一块区域需要简单处理一下:
玩家1完全由节点A控制,玩家3完全由节点B控制。而处在两个节点边缘的2号玩家,则同时由A和B提供服务。玩家2从A移动到B的过程中,会同时向A请求左边的情况,并向B请求右边的情况。但是此时玩家2还是属于A管理。直到玩家2彻底离开AB边界很远,才彻底交由B管理。按照这样的逻辑将世界地图分割为一块一块的区域,交由不同的 Node去管理。
网关服务器再次退回到精简的网络转发功能,而用户逻辑则由按照 UID划分的 OBJ服务器来承担,GATE是按照网络接入时的负载来分布,而 OBJ则是按照资源的编号(UID)来分布,这样和一个用户通信直接根据 UID计算出 OBJ服务器编号发送数据即可。而新独立出来的 OBJ则提供了更多高层次的服务:
图11 动态负载均衡
图12 基于网格的动态负载均衡
玩家通过 Match Making 服务器使用:创建、加入、自动匹配、邀请 等方式组成一局游戏。服务器会选择一个人做 Host,其他人 P2P连接到做主的玩家上来。STUN是帮助玩家之间建立 P2P的牵引服务器,而由于 P2P联通情况大概只有 75%,实在联不通的玩家会通过 Forward进行转发。
和战网一样的全区架构,用户数据不能象分区的 RPG那样一次性load到内存,然后在内存里面直接修改。全区架构下,为了应对一个用户同时玩几个游戏,用户数据需要区分基本数据和不同的游戏数据,而游戏数据又需要区分积分数据、和文档数据。胜平负之类的积分可以直接提交增量修改,而更为普遍的文档类数据则需要提供读写令牌,写令牌只有一块,读令牌有很多块。同帐号同一个游戏同时在两台电脑上玩时,最先开始的那个游戏获得写令牌,可以操作任意的用户数据。而后开始的那个游戏除了可以提交胜平负积分的增量改变外,对用户数据采用只读的方式,保证游戏能运行下去,但是会提示用户,游戏数据锁定。楼主 2015-08-25 12:29 回复