一、前言
没有最好的架构,只有最适合自身业务的架构。
首先我们应该确定的是大的架构方向:分布式 / 单应用+负载均衡,这两种架构设计直接影响后续的网络层、缓存层、数据层、业务层的设计。笔者这两种架构的应用都接触过,两种架构各有优劣:
- 分布式架构在业务层设计上更轻巧,更容易迭代,并且将各个业务模块独立开来可以大量减少锁竞争、线程阻塞的情况,可以做到无状态数据通信,天然支持跨服业务,且耦合性低内聚性高……缺点是分布式架构会有进程间调用上的性能损失(但是在现在硬件条件下损失微乎其微),且相对于单应用架构技术性更为复杂,缓存、锁、数据同步机制设计上也更为复杂,对开发人员、运维等要求更高。
- 再说单应用的架构,目前业界内采用这种设计的可能更为常见一些,优点是内存共享性能好,且开发、运维更容易上手,如果想要达到能承载较大负载的场景下在负载均衡的设计上需要下一些功夫,缺点是更新迭代相对麻烦,模块间耦合性难以拆分,锁竞争激烈环境下性能影响较大。
一个大型的网落游戏服务器应该包含几个模块:网络通讯,业务逻辑,数据存储,守护监控(不是必须),其中业务逻辑可能根据具体需要,又划分为好几个子模块。
这里说的模块可以指一个进程,或者一个线程方式存在,本质上就是一些类的封装。
二、进程与线程的服务器设计模式
对于服务器的并发性,要么采用单进程多线程,要么采用多进程单线程的方式,说说两种方式的优缺点:
1、单进程多线程的服务器设计模式
只有一个进程,但一个进程包好多个线程:
网络通讯层,业务逻辑,数据存储,分别在独立的线程中,无守护进程。
优点:
1.数据共享和交换方便,使用全局变量或者单例就可以,数据存储方便。
2.单进程,服务器框架结构相对简单,编码容易。
缺点:
1.所有功能只能在单个物理服务器上,不能做成分布式。
2.不方便监控各个线程状态,容易死锁
3.一个线程出错,例如内存非法访问,栈空间被破坏,那么服务器进程就退出,所有玩家掉线,影响大。
二、多进程单线程的服务器设计模式
多个进程,每个进程只有一个线程:
网路通讯,业务逻辑,数据存储,守护进程,分别在不同的进程。
优点:
1.各个进程可以分布在不同的物理服务器上,可以做成分布式的服务器框架,例如可以将数据存储单独放到一个物理服务器上,供几个区的服务器使用。将网络通讯进程独立出来,甚至可以做成导向服务器,实现跨服战。
2.可以通过守护进程监控其它进程状态,例如有进程死掉,马上重启该进程,或者某个进程cpu使用率接近100%(基本可以判断是某个逻辑死循环了), 强制kill掉该进程,然后重启。
3.单个服务器进程异常退出,只要不是网络通讯进程(一般这个都会比较稳定,没什么逻辑),那么就可以及时被守护进程重启,不会造成玩家掉线,只会造成在1-2秒内,某个逻辑功能无法使用,甚至玩家都感觉不到。
4.服务器通过共享内存进行数据交换,那么如果其中一个服务器死掉,数据还在,可以保护用户数据(当然多线程也可以使用共享内存)。
5.并发性相对多线程要高点。
缺点:
1.不方便使用互斥锁,因为进程切换的时间片远远于线程切换,对于一个高并发服务器是无法允许这么高时间片的切换代价的。因此必须设计好服务器的框架,尽量避开使用锁机制,但要保证数据不出错。
2.多进程编程,在各个进程间会有很多通讯,跨服务器进程的异步消息较多,会让服务器的编码难度加大。
三、游戏框架
下面先按照一个游戏的功能,将服务器的功能分块框架画出来:
以上是一个游戏服务器最基础的功能框架图,接下来要做的就是设计服务器的框架了
1.早期的MMORPG服务器结构
Client<->GameServer<->DB 所有业务,数据集中处理:
优点:简单,快速开发
缺点:
1.所有业务放在一起,系统负担大大增加.一个bug可能导致整个服务器崩溃,造成所有玩家掉线甚至丢失等严重后果。
2.开服一刹那,所有玩家全部堆积在同一个新手村.->>>>卡,客户端卡(同屏人数过多渲染/广播风暴) 服务器卡(处理大量同场景消息