经典游戏服务器端架构概述(3)- 全服分线模型篇

发表于2015-07-20
评论0 3.4k浏览

1、   模型描述

由于多进程服务器模型的发展,游戏开发者们首先发现,由于游戏业务的特点,那些需要持久化的数据,一般都是玩家的存档,以及一些游戏本身需要用的,在运行期只读的数据。这对于存储进程的分布,提供了非常有利的条件。于是玩家数据可以存放于同一个集群中,可以不再和游戏服务器绑定在一起,因为登录的时候便可根据玩家的ID去存储集群中定位想要存取的存储进程。

 

[12-全区分线模型]

 

2、   存储的挑战

a)        需求:扩容和容灾

在全区分线模型下,游戏玩家可以随便选择任何一个服务器登录,自己的帐号数据都可以提取出来玩。这种显然比每个服务器重新“练”一个号要省事的多。而且这样也可以和朋友们约定去一个负载较低的服务器一起玩,而不用苦苦等待某一个特定的服务器变得空闲。然而,这些好处所需要付出的代价,是在存储层的分布式设计。这种设计有一个最需要解决的问题,就是游戏服务器系统的扩容和容灾


从模型上说,扩容是加入新的服务器,容灾是减掉失效的服务器。这两个操作在无状态的服务器进程上操作,都只是更新一下连接配置表,然后重启一下即可。但是,由于游戏存在大量的状态,包括运行时内存中的状态,以及持久化的存储状态,这就让扩容和容灾需要更多的处理才能成功。

最普通的情况下,在扩容和容灾的时候,首先需要通知所有玩家下线,把内存中的状态数据写入持久化数据进程;然后根据需要的配置,把持久化数据重新“搬迁”到新的变化后的服务器上。——如果一个游戏有几千万用户,这样的数据搬迁将会耗时非常长,玩家也被迫等待很长的时间才能重新登录游戏。所以在这种模型下,对于数据存储的设计是关键的地方。


b)       分区分服的关系型数据库

我们常常会使用MySQL这种关系型数据库来存放游戏数据。由于SQL能够表述非常复杂的数据操作,这对于游戏数据的一些后期处理有非常好的支持:如客服需要发奖励,需要撤销某些错误的运营数据,需要封停某些特征的玩家……但是,分布式数据库也是最难做分布的。一般来说我们都需要通过某一主键字段做分库和分表;而另外一些如唯一关键字等数据,就需要一些技巧来处理。

[13-分表分库]

以玩家ID作为分表分库是一个非常自然的选择,但是这种方案,往往需要在逻辑代码中,对玩家数据按照自定义的规则,做存储进程的选择。但是如果发现这个分表分库的算法(原则)不符合需求,就需要把大量的数据做搬迁。如上图是按玩家ID做奇偶规则分布到两个表中,一旦需要增加第三台服务器,数据存储的目的服务器编号就变成了id%3,这样就需要把好多数据需要从原来的第一、二台数据库中拷贝出来,非常麻烦。

有的开发者会预先建立几十个表(如120个表=2x3x4x5),一开始是全部都放在一个服务器上,然后在增加数据库服务器的时候,把对应的整个表搬迁出来。这样能减轻在搬迁数据的时候造成的复杂度,但还是需要搬迁数据的。最后如果与建立的表还是放不下了,依然还是需要很复杂和耗时的重新拷贝数据。


c)        NoSQL

在很多开发者绞尽脑汁折腾MySQL的时候,NoSQL横空出世了。实际上在很早,目录型存储进程就在DNS等特定领域默默工作了。NoSQL系统最大的好处正是关系型数据库最大的弱点——分布。

由于主键只有一个,因此内置的分布功能使用起来非常简便。而且游戏玩家数据,绝大多数的操作都是根据主键来读写的。“自古以来”游戏就有“SL大法”之称,其本质就是对存档数据的简单读、写。在网游的早期版本MUD游戏时代,玩家存档只是简单的放在硬盘的文件上,文件名就是玩家的ID。这些,都说明了游戏中的玩家数据,其读写都是有明显约束的——玩家ID。这和NoSQL兼职是天作之合。

[14-分表分库]

 

NoSQL的确是非常适合用来存储游戏数据。特别是有些服务器如Redis还带有丰富的字段值类型。但是,NoSQL本身往往不带很复杂的容灾热备机制,这是需要额外注意的。而且NoSQL的访问延迟虽然比关系型数据库快很多,但是毕竟要经过一层网络。这对于那些发展了很多年的ORM库来说,缺乏了一个本地缓存的功能。这就导致了NoSQL还不能简单的取代掉所有服务器上的“状态”。而这些正是分布式缓存所希望达成的目标。


d)       分布式缓存

在业界用的比较多的缓存系统有memcache,开发者有时候也会使用诸如Hibernate这样的ROM库提供cache功能。但是这些缓存系统在使用上往往会有一些限制,最主要的限制是“无法分布式使用”,也就是说缓存系统本身成为性能瓶颈后,就没有办法扩容了。或者在容灾的情景下,缓存系统往往容易变成致命的单点。


Orcale公司有一款叫Coherence的产品,就是一种能很好解决以上问题的“能分布式使用”的产品。他利用局域网的组播功能来做节点间的状态同步,同时采用节点互相备份的方案来分布数据。这款产品还使用Map接口来提供功能。这让整个缓存系统既使用简单又功能强大。更重要的是,它能让用户对于数据的存取特性做配置,从而提供用户可接受的数据风险下的更高性能——本地缓存。


由于游戏的数据,真正变化频繁的,往往不是“关键”的需要安全保障数据,如玩家的位置、玩家在某次战斗中的HP、子弹怪物的位置等等。而那些非常重要的数据,如等级、装备,又变化的不频繁。这就给了开发者针对数据特性做优化以很大的空间。而且,大部分数据的读、写频率都有典型的不平衡状态。普遍游戏数据都是读多写少。少量的日志、上报数据是写多、几乎不读。


对于缓存系统来说,有三个重要的因数决定了在游戏开发中的地位。首先是其使用的便利性,因为游戏的数据结构变化非常频繁,如果要很繁琐的配置数据结构,则不会适合游戏开发;其次是要能提供近似本地内存的性能,由于游戏服务器逻辑基本上都是在频繁的读写某一特定数据块,如玩家位置、经验、HP等等,而且游戏对于处理延迟也有较高的需求(WEB应用在2秒以内都可以忍受,游戏则要求最好能在20ms以内完成)。要能同时满足这两点,是不太容易的。

[15-分布式缓存]

 

e)        集成缓存的NoSQL

根据上面的描述,读者应该也会想到,如果数据库系统,或者叫持久化系统,自带了缓存,是否更好呢?这样确实是会更好的,而且特别是对于NOSQL系统来说,能以一些内部的算法策略,来降低前端逻辑开发的复杂程度。一般来说,我们需要对集成缓存的NOSQL系统有以下几方面的需求:首先是冷热数据自动交换,就是对于常用数据有算法来判别其冷热,然后换入到内存以提高存取性;其次是分布式扩容和容灾功能,由于NOSQL是可以知道数据的主关键字的,所以自然就可以自动的去划分数据所在的分段,从而可以自动化的寻找到目标存储位置来做操作;最后是数据导出功能,由于NOSQL支持的查询索引只能是主键,对于很多后台游戏操作来说是不够的,所以一定要能够到处到传统的SQL服务器上去。


在这方面,有很多产品都做过一定的尝试,比如在Redis或者MangoDB上做插件修改,或者以ORM系统封装MySQL以试图构造这种系统等等。

[16-集成缓存的NOSQL]

 

3、   跳线和开房间

a)        开房间型游戏模型

在全区分线服务器模型中,最早出现在开房间类型的游戏中。因为海量玩家需要临时聚合到一个个小的在线服务单元上互动。比如一起下棋、打牌等。这类游戏玩法和MMORPG有很大的不同,在于其在线广播单元的不确定性和广播数量很小。

这一类游戏最重要的是其“游戏大厅”的承载量,每个“游戏房间”受逻辑所限,需要维持和广播的玩家数据是有限的,但是“游戏大厅”需要维持相当高的在线用户数,所以一般来说,这种游戏还是需要做“分服”的。典型的游戏就是《英雄联盟》《穿越火线》这一类游戏了。而“游戏大厅”里面最有挑战性的任务,就是“自动匹配”玩家进入一个“游戏房间”,这需要对所有在线玩家做搜索和过滤。

[17-开房间型游戏]

 

这类游戏服务器,玩家先登录“大厅服务器”,然后选择组队游戏的功能,服务器会通知参与的所有游戏客户端,新开一条连接到房间服务器上,这样所有参与的用户就能在房间服务器里进行游戏交互了。

由于“大厅服务器”只负责“组队”,所以其承载力会比具体的房间服务器更高一些,但这里仍然会是性能瓶颈。所以一般我们需要尽量减少大厅服务器的功能,比如把登录功能单独列出来、把玩家的购买物品商城功能也单独出来等等。最后,我们也可以直接想办法把“组队”功能也按组队逻辑做一定划分,比如不同的组队玩法、副本类型、组队用户等级等等。

虽然这种模型已经可以对很多游戏做很好的承载了,但是在大厅服务器这里依然无法做到平行扩展,原因是玩家的在线数据比较难分布到不同的服务进程上去,而且还带有大量复杂的数据查询逻辑。


b)       专用聊天服务器

不管是MMORPG还是开房间类游戏,聊天一直都是网络游戏中一个重要的功能。而这个功能在“在线人数”很多,“聊天频道”很多的情况下,会给性能带来非常大的挑战。在很多类型的页游和少部分手机游戏里面,在线聊天甚至是唯一的“带公共状态”的服务。

聊天服务处理点对点的聊天,还有群聊。用户可能会添加好友、建立好友群组等各种功能。这些功能,都是和一般的游戏逻辑有一定差别的功能。这些功能往往并不是非常容易实现。很多游戏都期望建立类似腾讯QQ的游戏聊天功能,但是QQ是一整个公司在做开发,要用仅仅一个游戏团队做成这么完整的功能,是有一定困难的。


因此游戏开发者们常常会专门的针对聊天功能来开发一系列的服务进程,以便能让游戏的聊天功能独立出来,做到负载分流和代码重用的逻辑。著名的端游《梦幻西游》,其聊天系统从客户端来说就是和主游戏进程分开的。

聊天服务器的本质是对客户端数据做广播,从而让玩家可以交互,所以有很多游戏开发者也直接拿聊天服务器来做棋牌游戏的房间服务器,或者反过来用。由于在游戏“分服”里面单独部署了聊天服务器,这类服务器也往往被用来承担做“跨服玩法”的进程。比如跨服团队战、跨服副本等等。不管这些服务器最终叫什么名字,实际上他们承担的主要功能还是广播,而且是运行玩家“二次登录”的广播服务器。以至于后来,有部分游戏直接全部都用聊天服务器来代替原始的“游戏服务器”,这样还能实现一个叫“跳线”的功能,也就是玩家从一个“在线环境”跳到另外一个“在线环境”去。——这些都是对于“广播”功能的灵活运用。

 

[18-专用聊天服务器]

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引