老手拍砖 新手看 转载注明
http://www.cppblog.com/ziyebuboka/ 本文介绍一下一个应用的游戏服务器的架构和演变
游戏服务器的作用在于满足在线玩家的需求,实现账号的验证,登陆,玩家在游戏世界的一系列逻辑操作和验证。在此基础上,一个好的架构,可以提升效率,在实现逻辑需求的情况下达到百万级的同时在线数也不是不可能。
我们先从最搓的最简单的结构看起
CLIENT ---------- SERVER --------- DBSYSTEM
就是一个很简单的 C/S系统 同一个server同时处理登陆注册创建角色和游戏逻辑操作的功能,。在server上直接挂接DB操作。DB可以是一个具体的数据库也可以是一个FILESYSTEM
这里可以看的出来,过于简单了,将登陆注册创建和具体逻辑这几个毫无关系的东西放置于一起,严重损耗了具体逻辑操作的效率,特别是在新开服阶段,完全会因为登陆验证的操作而导致逻辑爆卡。
所以这里需要升级,将完全不同类型在玩家一次游戏操作工程中只会在登陆阶段执行一次的操作单独分开,单独进程解决,。故而可成为下面阶段
- LOGINSERVER -
- -
CLIENT - - DBSYSTEM
- -
- GAMESERVER -
分为两个服务器,这个我在一文章里的开头就有提到过了。
我们来看下好处进阶,在LOGINSERVER里只执行账号验证 查询角色列表 创建角色的操作 而后玩家登陆进GAMESERVER 具体逻辑操作在GAMESERVER里完成
玩家的一次登陆操作
发送账号 验证 返回角色列表 创建角色
CLIENT---------------LOGINSERVER -----------DBSYSTEM-----------------------CLIENT ------------------
选择角色与LOGIN断链与GAME连接 登陆
LOGINSERVER -------DBSYSTEM ----------CLIENT ------------------------------------------------------GAMESERVER
如此,可有效的提升效率,玩家的验证 列表读取 创建 和GAME就毫无关系了,但是他的缺点任然存在 我们再继续看可优化的地方
首先从数据库上来提升效率(先说下,从这里开始就应该是肯定的是用数据库了,而非什么本地FILE了,),将账号库和游戏数据库分开,分离为两个独立的库,
具体理由有两个:
1:从游戏运营上来说 你不可能一直是只有一个服吧? 分成多个服后 人数越来越多,就不能所有服都共用一个数据库了吧?那你这数据库也牛逼了
所以我们这里这么干,将 账号库独立,全游戏共用,这样是方便管理,方便管理账号的全局性的信息 经济性的 比如点卡什么的,每个服一个游戏数据库,只记录操作你这个服的玩家信息,世界信息。
2:理由类同将服务器拆分为LOGIN和GAME。
现在 结构就是这样的
- LOGINSERVER-
- - ACCOUNTDBSYSTEM
CLIENT - -
- - GAMEDBSYSTEM
- GAMESERVER -
但是到了这里后 肯定还是不够的,
我们先说个基本的,在服务器里 ,你一定要记得,数据库操作,IO操作 ,文本操作这些 一定要单独进程不要和主进程搞一起,你总不希望你做了个什么查询还是什么操作 他主线程挂起吧?但是,试想下,如果能单独进程肯定还是单独进程更爽一点吧?你还能在里面做做缓存啥的,还不占服务器的资源
所以这里还是麻烦的 从效率上来说 至少后台这块 还有很大提升空间。因此,我们加入 DBAGENT模块 ,单独进程,将数据库操作单独分离,并且可自我添加某些应用的缓存
对应ACCOUNTDBSYSTEM 增加 accountagent ,对应 GAMEDBSYSTEM 增加 gameagent
结构如下
-LOGINSERVER-
- - accountagent - ACCOUNTDBSYSTEM
CLIENT -
- - gameagent - GAMEDBSYSTEM
-GAMESERVER -
LOGINSERVER同时和accountagent和gameagent连接 gameserver也同时和这两个连接 服务器通过agent来对对应的数据库做操作 因为accountdbsystem可能是全服共有的 ,所以accountagent也可以是全服共有的 他连接所有的服务器。loginserver通过accountagent来验证 通过gameagent来查询列表 创建角色 gameserver通过gameagent来查询完整角色信息登陆进game,并通知accountagent此账号已进入游戏,避免重复登陆。并且定期保存。设置你可以将比如你游戏的排行榜啊,拍卖行啊的信息放置于你自己设计的gameagent的缓存中,而避免重复查询
玩家每一个对数据库的操作 server只需发送消息到agent agent来做具体操作,而后再返回到server 再到client就可。将数据操作完全的异步操作,效率有较大提升。并且安全性上也得到了些许保证。
不是我胡说或者轻视,国内一大半游戏,都用的上面这个结构。。。。。。。。。。。。。。。。。。。。。这个可以算是一个比较完善的产品化架构了。
说到这里,大家有没有发现一个共性。采用这类架构,游戏必然会是先选服务器再验证账号 登陆进游戏,这是因为服务端采用的是LOGIN和GAME一对一得处理,也就是你是登陆的什么服务器必然就是从什么服务器的LOGIN进入验证,故而他需要在客户端开启的时候就要知道需要连接的是哪个LOGIN 账号验证成功后再是哪个GAME
其实这里很好处理,就在客户端上做些处理就可以达到先登陆验证在选服务器。所以在配置上 LOGIN不再是一对一(后面会有优化的再说到多个LOGIN),全局也共用一个LOGIN。玩家开启客户端,连接LOGIN。发送账号验证。因为这里已经是把ACCOUNTDBSYSTEM做成全局的了,所以是不用担心他是哪个服的,然后返回成功,玩家客户端显示服务器列表(这个列表还有连接信息配置再客户端就可以了)选择某一个服后,则发送查询某服角色列表的请求到LOGIN,而后再返回再登陆游戏就可。小小调整和改变就可实现先验证后选服务器了。
所以,到了这步,服务器架构就变成这个样子了
-LOGINSERVER-
- - accountagent -ACCOUNTDBSYSTEM
CLIENT - |--------
- |-----------
-
- GAMESERVER - gameagent -GAMEDBSYSTEM
- |
- GAMESERVER -gameagent -GAMEDBSYSTEM
全局共用一个LOGIN和一个ACCOUNTAGENT还有ACCOUNTDBSYSTEM
每个独立服各自独立的gameagent 和gamesdbystem
但是LOGIN的瓶颈立马出现了,当初是一个服独立一个LOGINSERVER 现在是全服只有一个了,毫无以为,扛不住。
其实上面这个架构的不一定非得存在的,就是随便写写,让大家更清楚一点。
所以LOGINSERVER就得配置多个了。这个地方大家选择吧 尽量灵活点,可以全服单位的配置多个也可以每个服对应的配置多个LOGINSERVER。这样 在开服时候,这种大面积井喷式的玩家玩家上线,可有效解决负载。具体CLIENT开启后会是和哪个LOGIN连接呢
这里提供两种方式。一个是配置上的 一个是程序上的
1:
程序上的好说 ,你把所有LOGINSERVER的连接信息都配置到客户端,让客户端开启后随机选择一个去连接。要是你开服后,他所有玩家都随机到一个LOGINSERVER了,那真的算你点背。背到家了
2:配置上 :
通过基于DNS的负载均衡系统,DNS中为一个域名配置多个IP地址。通过负载,让系统来选择是对应到哪个IP
所以就是
-LOGINSERVER -|
- LOGINSERVER -|
-LOGINSERVER -|
- -accountagent -ACCOUNTDBSYSTEM
CLIENT - |--------
- |-----------
-
-GAMESERVER -gameagent -GAMEDBSYSTEM
- |
-GAMESERVER - gameagent -GAMEDBSYSTEM
或者是:
- LOGINSERVER -
- LOGINSERVER -
- LOGINSERVER -
..................................上面可以是N个
- -gameagent -GAMEDBSYSTEM
-GAMESERVER -
Client
- LOGINSERVER -
- LOGINSERVER -
- LOGINSERVER -
..................................上面可以是N个
- gameagent-GAMEDBSYSTEM
- GAMESERVER -
accountagent -- --- ACCOUNTDBSYSTEM 是全局的
一个服对应好多个LOGINSERVER
因为LOGINSERVER使用的动态配置,故而可在登陆下线没有多大压力的情况下,关掉几个LOGINSERVER,节省运维资源
不想写了,元旦又混了三天,明天继续吧。明天把前面的再扩展下,再说下分线的和分布的。牛逼的就不说了
http://www.cppblog.com/ziyebuboka/