浅谈MMORPG服务器架构

前言

本篇文章虽然是谈谈MMO服务器架构,但可能只是我个人的碎碎念把,这是算我进入公司几个月以来的一个回顾与总结吧。先说下项目把,我们项目是一个十多年历史的老MMO端游,存在这架构老旧,代码臃肿等一系列问题,不过把因为历史原因而没有设计好的地方剔除来看,这个项目还许多值得学习的地方。

做为一个新手游戏程序员能够接触到较为复杂的MMO服务器,不过我们项目上线多年,很多东西是已经开发好,相对从0开始开发项目,会缺少一些从设计到实现的经验。

游戏服务器特点

因为游戏服务器并没有比较通用方案,不同游戏类型之间使用方案可能差距非常大。

我个人把游戏服务器分为三类

1.大DUA休闲游戏
2.房间类型游戏服务器
3.MMO游戏服务器

房间类型游戏服务器会特殊点,因为它主要看房间内的的游戏类型。

大DUA休闲游戏

大DUA休闲游戏是游戏逻辑较为简单的一种游戏类型,特点为逻辑较为简单,访问量大。

据我个人了解,这样的休闲游戏会做一个全球同服,一般采取互联网那种架构比较多一点,可能nginx做网关,上一个redis集群做缓存,后面mysql分库分表,游戏内部逻辑给客户端一丢,服务器做的逻辑相对于其他游戏类型会比较少。

房间类型游戏

房间类型游戏相对于休闲游戏来说,逻辑更多,并且大概率涉及到游戏同步问题,不过休闲游戏也可能是房间类型的游戏,两者是相交的关系,这里就不严格区分开来了。

房间类型游戏有比如像英雄联盟那样的MOBA,QQ飞车那样的赛车或者是吃鸡那样的FPS,游戏类型丰富,房间类型游戏的游戏类型取决为房间内的内容。难点也取决于内容,比如英雄联盟和你画我猜都是开房间类型的游戏,但是难点肉眼可见的不同。

但是房间类型游戏相对于MMO游戏有个好的地方就是房间与房间之间是天然隔离开来的,而MMO游戏服务器为了实现无缝地图一直是比较困难的一件事情。

MMO游戏服务器

MMO游戏服务器比前两者又有毕竟大的不同,我个人认为最大的区别是一个逻辑服务器上玩家人数的不同,休闲游戏大概率不存在逻辑服务器这样的东西,所以休闲服务器就不讨论了。而房间类游戏服务器一般来说一个房间十个玩家就差不多了,每个房间与房间之间天然隔离,可以很容易的加机器扩容解决问题。

而MMO游戏服务器上一个场景可能会有上百甚至上千人,不同场景倒是可以切割开来,但是单场景切割是件不容易的事情(不过kbengine已经实现了),涉及到的问题比较多。所以MMO一般以一个进程或一个线程负责一个场景的方式来切割不用场景,处理简单,也不会涉及到并发问题。

但无论是单线程还是单进程,网络都会成为痛点,举个极端的例子,某一个场景内有100个玩家同屏(同属于一个AOI发现范围内,并假设每个包达到MTU大小),那么所需的网络带宽为 100 X 100 X 1500byte ,大概为140Mbps,然后单场景又可能有多个这样的情况,不过这是比较极端的。

MMORPG架构

现在我来分享下,目前我所在项目的一个端游MMO服务端架构,不过这个架构虽然比较老,但是还是很有学习的价值。
在这里插入图片描述
首先来解释一下图中各个含义吧。首先这个架构是一个多进程单线程的架构,图中除客户端外,每一个方框代表一个进程,每一个进程中只有一个线程。

GateWay列表服务器

GateWay列表服务是负责为客户分配GateWay服务器地址的服务器。通常客户端第一次与服务器进行通信,首先就是去GateWay列表服务器上获取的GateWay服务器IP地址。获取到之后就断开连接。
GateWay列表服务器在我目前项目主要是作用是动态分配负载低的GateWay给客户端,起一个负载均衡的作用。

GateWay服务器

GateWay服务器是类似网关一样的服务器,GateWay服务器不对数据内容进行任何处理,只进行转发以及加密解密操作。数据将被发送到GMS服务器。

GMS服务器

GMS服务器管理玩家信息,但不负责游戏内的逻辑操作,游戏内逻辑操作全由场景服务器进行处理,所以GMS的功能大致分为两部分,一是负责玩家进入场景之前的所以逻辑(如登入),二是保存玩家的上下文信息(如账号角色信息,在哪一个场景服务器之类),以便于玩家在场景切换。

GMS会在玩家进入场景时候起重要作用,因为不同场景服务器会负责不同的场景,玩家进入场景时候就由GMS服务器选择转发消息到那一台场景服务器上去。不过这里有个问题,一个GMS服务器会对应多个其他服务器,并且全局只有一个GMS服务器,在第一次看的时候考虑过这里会不会成为一个单点问题,但是后面想想多虑了,因为如果GMS服务器达到瓶颈的情况下,那么场景服务器可能在很早就崩掉了,因为逻辑服务器是属于计算密集型的,单场景单进程可能也就能承载几千人而已。算一算离单机极限还远着呢。除非把单场景做成多线程的那种形式,也就是做成无缝大地图形式,才需要把GMS做成分布式来避免单点。

场景服务器

场景服务器负责游戏内的全部逻辑操作,如移动,攻击,下副本等等。可以说是游戏服务器中最重要的一部分。在这个架构中场景服务器是以组的形式存在的,每个场景服务器负责各自的场景,场景服务器于场景服务区直接是没有任何数据传输的(虽然说是没有,但是极端环境下还可能存在场景服务器与场景服务器直接通讯)。

但是有一个例外,那就是全局场景服务器,全局场景服务器顾名思义,负责解决一些多场景可能发生争夺的问题,比如说全局帮会服务器,有关帮会相关的操作逻辑会在这个服务器上进行处理。因为帮会的一些操作在任何一个场景服务器都有可能发生,但是又需要避免多线程争夺的问题,就直接独立分一个全局服务服务器处理帮会等功能。

共享内存服务器

共享内存服务器可以算是DB的缓存,如果把这个替换成redis,那大家就一定懂了,不过注意的一点是,场景服务器并非每次操作都要去共享内存服务器拉数据,这种操作对游戏中一个逻辑帧只有40ms的时间来说太长了,主要数据还是在内存里直接操作。所以基本是有比较重要的写操作时候才丢给共享服务器去写,然后共享服务器在定期存到DB去。

DB

DB也就是数据库,这里要特殊说明下,上面的图有一点画错了,DB不仅和逻辑服务器通讯还负责定期写入共享内存服务器的数据,不过只有特别重要的数据逻辑服务器才直接走DB(如氪金商城消费等),普通的数据还是走共享内存,然后定期存储。

在我项目中DB使用了定存的方式,所以DB存在感会低一点,不像互联网那样每次必存DB(虽然现在互联王都直接丢mq了),查询也是向共享内存先查,查不到在到DB里面查,基本上游戏服务器使用的DB常见的有mysql,mongo,甚至Berkeley DB,基本就是哪个顺手用哪个。不过感觉把共享内存+DB这个组合直接换成redis组应该是可以。

优点

这种多进程架构相比多线程式的更容易拓展一点,因为多进程多机部署更简单,中间走socket就好了。

共享内存+db的组合保证一定程度上容灾,不过要是两个都挂了那还是问题挺大。

缺点

无法解决单场景分割问题。

共享内存和DB同时挂掉就要靠日志回档。

架构改进与想法

Redis

因为项目组以前有出现过运营事故,机房电源给全断了,然后服务器就全挂了。这说明共享内存+DB就两台服务器不一定靠谱。我自己的想法是换成redis集群+DB+mq。这样就算挂了几台也问题不大,redis的主从能很快切换,就算全挂了也可以去mq里面直接拿数据,就不用拿日志分析了。

拓展GMS

虽然说GMS瓶颈还是很难达到,不过反正是想法就随便说说,大概是将GMS扩展为GMS组,在有用户接入时,用redis记录用户走的是那哪一个GMS和Gateway,这是一个hashmap一样的结果。

不过这样做跨服也会好做一点,据我了解天龙跨服就是类是这样做法,它们把n个Tserver(类似GMS)进行管理,实现一个树形的服务器结构。玩家很容易的就可以跨服玩法,跨服的数据也容易的回传到原来服务器上。

猜你喜欢

转载自blog.csdn.net/ninesnow_c/article/details/119533665
今日推荐