MMO游戏服务器属于大型多人在线游戏服务器,负载,稳定,效率(包括反馈延迟和开发效率)是这种服务器基本要求。
本人从10年入行至今一直从事MMO游戏的研发和架构设计工作,对此类服务器有一些理解和见解。下面分享给想了解游戏服务器开发的朋友们。这些是本人这些年来对MMO服务器架构设计的总结的分享。本人会从头开发一套完整的MMO服务器架构程序。并在架构的基础上实现基本的游戏Demo功能。虽然只是架构,但是完全可以支持线上项目的研发。本人是实战中成长起来的,不会花哨的语言修饰。都是真枪实弹的code。
开发语言选择:
本人参与C++服务器架构开发5年,后转Java,发现Java更加适合游戏服务器的研发。优点如下:
1、相对简单,远比c++要容易些,这个应该不用争辩吧。并且Java的人员招聘也比C++要容易些。
2、服务器稳定,C++服务器动不动出现指针等问题就可能导致服务器宕机,但Java有的异常处理机制可以处理几乎所以因为简单异常导致的问题,出现引用问题,也只是抛出一个异常打印即可。
3、开发编译效率。Java的库比较完善(C++库也很完善),但去网上查询多少开源的java库和多少开源的c++库,对比就知道了。相同的功能,用Java去写逻辑比C++写逻辑代码要少,这是我的感受。c++写类需要H文件和CPP文件,并且需要先定义后实现,这就要多写一个函数定义。编译,C++项目的链接机制很耗时,一个完善的大型游戏服务器项目重新编译一次,动不动就是10分钟半个小时以上,有人会不会说不用联编啊,我上个项目在使用联编的条件下需要10分钟以上,不用联编时间就不用提了,每个半个小时肯定编译不完。但Java就快的多了,Java是生成的字节码,并且没有链接的过程。比如修改一个函数,Java添加完成,可以直接启动测试,但是C++就可能会因为一行代码的修改,导致无数Cpp文件的编译。这个过程十分耗时。这是我比较推荐使用Java开发的主要原因。因为项目开发的大部分时间还是逻辑功能的开发。如果因为编译过程消耗大量时间,后期的开发维护成本大大减低。
4、效率对比,有人可能说C++比Java运行效率高,这个我不争辩。网上争辩的太多,现在的机器性能已经足够高,不够就堆积硬件,硬件成本远低于软件成本。也不是说Java确实效率不行,实际上Java和C++效率对比已经可以忽略。比如相同程序,C++跑1000万次耗时1秒,Java耗时0.9秒。虽然慢,但是1000万次的数量级,完全没有必要非得争取那0.1秒。但也是分领域。比如游戏内部寻路算法NavMesh,这种纯运算的逻辑还是用C++,确实效率高。通过Java的Jni方式与本地C++Dll实现交互,Java调用C++方法。
5、跨平台问题。就说Window和Linux,C++编写的代码在不同的平台要有两份实现。就仅仅网络部分window的Iocp,linux的Epoll就是两种实现。其他的函数库,两个平台也有不同,都要进行处理。对于Java,就一个虚拟机,在window还是在linux都是运行在虚拟机之下,只要有Java虚拟机,管你是什么系统。
模块介绍:
虽然只是服务器架构,但是麻雀虽小,五脏俱全。先整体介绍一下MMO服务器需要的基础组成部分,让大家有一个整体的认识。
基础组件:
1、网络组件:包括内网通信模块和外网通信模块。还有协议部分。
2、数据库组件:负责玩家数据和全局数据的持久化。
3、日志组件:包括异常日志(代码异常打印日志)和行为日志(为运营平台提供的行为日志)。
4、配置读取组件:程序启动配置(程序启动相关配置如ip,port,连接关系等这个很简单,使用ini配置即可)和游戏相关配置(游戏逻辑相关配置使用量巨大,采用json格式数据)。
游戏逻辑模块:
以上组件都是为了这部分的做支撑。这个部分也是代码量最大,使用量最大的部分。这部分还可以细分出很多模块。具体模块后续详细说明。游戏逻辑模块主要分成两部分线程组:系统服务线程组和场景逻辑线程组。不同的系统服务器挂载不同的服务线程上,不同的场景挂载不同的场景线程上。
系统服务包括哪些:比如登陆系统服务,好友系统服务,帮派系统服务,等。可以将一个或者多服务器挂载一个线程,也可以分别挂载不同线程。根据预测的逻辑运算量进行分配,同步配置文件可以实现配置挂载。
场景逻辑:玩家的所有操作基本都属于场景逻辑线程组的。玩家的行走,战斗,道具获得,使用。系统服务线程组提供的系统服务基本都是通过RPC调用的方式为场景逻辑组线程提供服务。比如添加好友,场景逻辑线程上的玩家收到添加好友消息,然后通过Rpc的方式调用系统服务器线程组的好友服务实现添加好友功能。但登陆服务做了特殊处理,登陆消息会直接分发到登陆服务,登陆服务进行验证,验证通过后会在场景服务线程组创建对应的角色通信对象实现与客户端的通信处理。
进程划分:
之前做C++的时候,一般都把进程都可以划分为登陆进程,网关进程,游戏逻辑进程,数据库进程,日志进程,平台进程。但转Java后,发现启动多进程反而启动麻烦。由于服务器架构整体都是多线程架构,就没有做细致的进程划分,我们的服务器可以全部都开在一个进程上,也可以分开启动。我们最近上的项目就是所有功能都在一个进程启动,开服第一天开了10几组服务器,由于导量的不均匀,导致首服人数特别火爆,最初设置的最高在线人数初始都是3000人,最后将首服调整为5500人。因为硬件都是试用云服务器,足够的大内存,cpu,完全没有必要分开进程启动,多进程反而会消耗更大的内存和cpu,单进程多线程更优。运维启动也更方便。
PS:本文是从整体到部分的实现步骤,所以难免有部分细节介绍可能存在一些疏忽或者问题。希望大家可以及时反馈,本人之后也会再发现问题修改本文的部分内容。