场景型网游服务器架构设计

本文所讨论的只是现有网游中一部分会采用这种架构思想,但本身,网游种类很多,所以需要专门对当前网游的需求进行一系列改变,所以本文不代表所有网游服务器架构。

 

对于网游的服务器架构设计,我们主要考虑下列几个点:

1,游戏类型:现有的游戏类型有很多,有房间式、世界类型、场景型(跟房间类型有部分相同)

2,连接方式:大部分游戏采用TCP长连接方式,但有些游戏也采用UDP传输或TCP/UDP共用

3,在线人数:为了保证游戏的流畅性,我们必须确保服务器集群的容灾和扩容性,以便于防止同时在线人数的增加。

4,性能方面:主要考虑内存、CPU、宽带等物理问题。

 

本文主要说明一类场景型网游服务器架构的设计框架。

首先我们理解一个网游服务器在游戏中所扮演的角色,我们可以把它理解为一个上帝角色,它拥有当前场景下所有玩家、NPC、事物对象的各类属性(状态、动作)的一个读写权,它可以通过自身的逻辑处理,将多个客户端连接到一起,呈现一个“统一”的世界。

下面先介绍一款游戏(刀剑Online,参考了网上其他大神的Blog)的服务器架构:

1,连接负载服务器(Connection Load Server - CLS)

  CLS主要负责服务器端与客户端的网络连接,主要作用就是将真正的服务器端口与客户端隔离开,CLS进行网络连接的处理,信息交互的处理,错误数据的处理......,有了CLS层后,我们可以有效的降低了逻辑层的负担,同时保证逻辑层对于客户端完全是一个黑盒服务器,确保其安全性,还有便是TCP长连问题,我们不需要再对TCP的连接进行处理,如果更换场景时,仅需要服务器端进行一个场景服务器的切换而已,TCP端口并不需要断开重连。一般我们只在CLS层进行网络数据的交互,关于游戏逻辑层的处理,是完全交给下层服务器处理,主要是为了保证框架的理解性,使得整个框架更加清晰。

  在编写CLS层的代码时,我们需要注意一些细节:

  ⑴,对于游戏服务器的逻辑处理,我们为了保证游戏的流畅性,就必须保证网络通讯做到及时处理,而TCP协议中,默认会开启Nagle算法,此算法的设计理念是在早期,若不断进行一个字节数据包的传输,TCP传输的有效利用率就会大大降低,大部分的CPU资源会浪费在TCP传输包的处理上,对于一些负载较重的网络,很容易造成拥堵,而Nagle算法就是在发送端欲发送多次少量数据包时,会先将第一个数据包发出去,其他小的数据包会先进行缓存,只到第一个数据包的ACK返回时,才会把缓存的包发出去,这样可以有效降低TCP传输中的资源浪费,但对于游戏中,这种做法是很难接受的,所以我们就需要关闭这个算法,在连接时使用TCP_NODELAY参数,禁用Nagle算法。

  ⑵,连接负载服务器组在与客户端进行交互之前,还必须先进行网络连接,如果仅仅只是一个1W人同时在线的小型游戏,那基本不需要多考虑,直接一台服务器进行连接交互就可以,但如果人数过大,一台服务器根本无法负担起这个工作,就需要一个服务器组,其前段再有一个负载均衡器对客户端的连接进行分配就可以

  ⑶,连接负载服务器对客户端发过来的数据如何进行解密,现有两种做法,一种是部分解密,一种是完全解密,具体参照上述说CLS层最好不要做过多其他层的东西,那同样逻辑层最好接受到的信息,也是不需要解密的明文类型,所以个人建议是在CLS层对数据包进行完全解密,再传输给逻辑层进行处理。

 

2,总控服务器(Master Server - MS)

  总控服务器有管理当前所有游戏相关内容的全向,比如某个客户端的登录、注销、角色操作、不同场景间的互动均由总控服务器处理,MS需要与其他的场景服务器时刻保持连接,我们可以把MS想象成一个服务器的中枢,它先从CLS层取得数据包,然后根据是否需要场景服务器处理判断后,如果不需要,自身处理完将结果反馈给CLS,如果需要,则分配给专门的某个场景服务器进行处理,并通知CLS层,让后续该用户的指令均直接转给该场景服务器处理。以其工作场景举个例子:

  ⑴,用户A与B分别处于不同场景服务器的管理上,A与B沟通时,则需要A的场景服务器将信息包发送给MS,包中有用户B的基础信息,MS会在临时管理信息库中进行检索,找到B的信息后,将该信息包再次发送给B所属的场景服务器。

  ⑵,用户A处于场景服务器1中的传送点,要传送到场景服务器2管理的场景,则会发送指令给MS,由MS给场景服务器2发送接收指令,这时便有MS对用户A进行服务器信息的更换,将用户A的信息处理放置在场景服务器2中。

 

3,场景服务器(Zone Server - ZS)

  场景服务器主要负责当前场景下的所有玩家的指令交互和逻辑处理,一般一个场景服务器所能同时支撑的在线人数在10000人左右,如果超过就会严重影响玩家的使用,所以对于一个玩家非常多的游戏,都会采用一种逆向管理发,以玩家ip进行服务器的分配,而不再是场景(当然,对于现在的场景型网游,一般很少出现一个场景下万人在线)。

  对于场景服务器,一般必须的要求有:1,高效(解决方法就是尽可能提升效率和代码的优化,并使用高效的脚本语言)

2,灾难回复机制,当ZS发生非法操作导致影响某段时间用户的数据,就必须要保证没隔一段时间就对数据进行一次存储,这样的代价就是大大家中了对数据库方面的负担(但没有办法,必须的),而有些游戏的做法就是将某些关键数据放在程序的共享内存中,这样就算发生数据非法访问等,也可以在重启时,直接从共享内存中对数据进行回复,同时恢复时必须对数据进行校验,防止将错误的数据存入数据库。

 

上述大致描述了一个场景型网游服务器的架构设计,那还有一些细节,比如每个玩家的完整信息存放在哪里之类的,玩家对象和场景的关系等等。下面一一分析一下。

4,玩家对象

  服务端如果需要对玩家进行逻辑处理,那就必然需要对每个玩家构建一个对象,以确保处理的对象不会发生错乱,那这个对象我们放在哪里会比较好一些,CLS?MS?ZS。

  首先讨论讨论一下CLS,我们前面说过,CLS的作用仅仅只是一个连接负载的作用,仅仅对客户端的连接进行网络交互和发给逻辑层处理,不做任何逻辑判断和内存处理。所以先PASS,那肯定是需要放在逻辑层的。

  其次如果把玩家对象放在MS上,那所有的玩家都会在MS的内存中保留一份数据信息,好处就是对象统一性,可以在MS中直接对玩家对象的一些信息进行处理,比如玩家之间沟通,但这无疑加大了MS的内存压力,同时如果MS接受到一些非法操作信息,有可能就会延迟整个服务器的玩家,甚至掉线。最后举个最麻烦的例子:假如玩家A在场景1下与怪物PK,由于对血量数据的记录是放在MS中,那也就是说ZS必须先对数据进行处理,然后发送给MS进行保存,MS进行统计完后给ZS发送ACK,最后再由ZS反馈给客户端,这个过程无疑有些麻烦了。

  那最后再考虑一下将玩家对象放置在ZS中,这种情况将对象放在ZS中,好处就是,在ZS中,我们无论进行什么操作,ZS都可以直接获取对象信息,在场景内的交互是非常便利的,不需要多余的数据传输,只是跨场景操作才需要通过MS中转一下数据。但也有一些缺点,比如所有的对象信息,就需要同时在ZS、MS、数据库中进行同步,假如我们需要进行多次跨服操作,同样就需要将数据从ZS中提取,传输到MS中进行逻辑操作,操作过程中ZS是不能修改当前对象的相关信息。这样无疑也是很麻烦的,所以无论放在ZS或这MS上,都是有一定的弊病,需要根据游戏的具体情景进行分析放置。

 

5,玩家对象和世界对象的模式关系

  ⑴,玩家自我操作模式:

  比如玩家使用某个作用对象为自己的物品-加血,流程大致就是服务器中获取对应的玩家对象,对自身加锁后,进行处理血量数据的添加,处理完后解锁,将处理的信息再次反馈给客户端显示血量添加。这种自我操作模式不需要考虑其他对象,仅仅对当前进行操作的对象进行加锁-处理-解锁即可,但如果是互动模式,就不能对别的对象进行加锁操作,否则两者有可能陷入死锁。那在互动模式下,服务器的操作流程是怎样呢?看一个图:

上图可以看到,如果对象A对对象B发起进攻,服务器接受到该指令后,需要与B交互,则将该消息打包放入一个消息队列中,并指定接受者为对象B,服务器会不断检索消息队列,发现有消息时,就会取出开始执行相应操作,流程与自我操作模式相似,为B上锁,减血后,解锁。一般游戏的服务器设计中,玩家与玩家之间的交互都是通过消息传递交互的。

  这种设计模式的优缺点也是比较明显的:优点就是在开发人员实现具体的逻辑时,我们不用担心加锁解锁的问题,我们只需要对消息进行逻辑处理并且对客户端进行反馈就可以,同时每个对象都不能直接对其他对象进行操作,放置死锁等现象,但缺点就是频繁的消息传递,增加交流的成本,两个对象之间无法直接获取对方的属性,必须通过消息传递,导致逻辑处理会延后,当在线人数过高的情况下,有可能会造成一些错误、超时等等。

  ⑵,世界型上帝模式:

  以一个例子来说明:玩家A向玩家B发起攻击

  流程图中可以看出,服务器分别找到A,B两个对象,将两者锁住后,直接由服务器进行攻击的逻辑操作,这里服务器就是一个可以访问所有对象属性的管理者,这样做的危险型就是容易发生死锁,由于是对多个对象进行加锁,那多线程下,两个对象相互攻击,那就有可能产生死锁的情况,所以在进行加锁前,必须对id先进行排序,保证了加锁的对象不会产生重复。这种模式的优点就是逻辑的编写是比较简单的,直接对多个不同的对象进行逻辑操作就可以,但有可能导致过多加锁的冲突和等待,就需要设计人员对整体的框架有着良好的规划和加锁策略。

 

上述就是本文关于场景型网游服务器设计架构的一个简单的分析理解,本文只是简单的走了一遍服务器架构的思想,但具体编码的很多细节还需要在具体项目中去探索。

 

posted @ 2017-07-21 17:33  不想写代码的DBA  阅读(581)  评论(0编辑  收藏  举报