MMO 游戏服务器引擎设计

时间:2022-09-14 20:47:43

原文地址:http://blog.csdn.net/itcombox/article/details/51445319

摘要:

MMO游戏服务器引擎设计工程总纲(一)

MMO游戏服务器引擎网络通信(二)

MMO游戏服务器引擎数据层集群(三)


MMO游戏服务器引擎设计工程总纲(一)

一、 网络游戏开发的基本流程

◆ 项目文档

◆ 开发的进行和文档准备流程

◆ 技术人员文档

二、 MMO游戏架构

 MMO游戏特点

 MMO架构的特有内容

三、 策划文档

◆ 考虑示例游戏的题材

◆ 详细设计文档

 MMO庞大的游戏设定

 5种设计文档

系统的基本结构图

进程关系图

资源评估文档

协议定义文档

数据库设计图

◆ 设计上的重要判断

四、 系统基本结构图

◆ 系统基本结构图的基础

◆ 服务器必须具有可扩展性 ---- 商业模式的确认

◆ 各瓶颈 ---- 扩展方式的选择

 MMO客户端特有的渲染性能瓶颈

◆ 解决服务器/数据库的瓶颈

空间分割法

实例法

平行世界方式

◆ 一台服务器负责整个游戏世界(什么都不做)

 

◆ 服务器的空间分割法 ---- 解决服务器的瓶颈

 

◆ 实例法 ---- 解决服务器的瓶颈

◆ 平行世界方式 ---- 解决数据库瓶颈

1、 同时采用平行世界和空间分割法

 

2、 同时采用空间分割、平行世界、实例法

◆ 同时采用多种方法 ---- 大量玩家在线时的数据

◆ 各种方式的引入难度

◆ 各个世界中数据库服务器的绝对性能提高

 K-Online的设计估算---- 首先从同时在线开始

◆ 据游戏逻辑的处理成本估算

◆ 据游戏数据库的处理负荷估算 ---- 角色数据的保存频率和数据库负荷的关系

◆ 可扩展性的最低讨论结果及进一步的用户体验追求

◆ 服务器的基本结构

五、 进程关系图

◆ 服务器连接的结构 ---- 只用空间分割法/使用平行世界方式和空间分割法

proxygmsv的关系是据gmsv处理逻辑的性能瓶颈和proxy连接数量瓶颈决定的m:n关系

(1) 只是用空间分割法;

蓝色是使用现有的服务器、黑色需要独立制作、准备
 MMO 游戏服务器引擎设计

(2)同时使用平行世界和空间分割法

MMO 游戏服务器引擎设计

 5-1-2-1 同时使用平行世界和空间分割法

使用平行世界方式进行扩展的关键是将dbsv分为dbsv1dbsv2dbsv3这样的多个数据库服务器,从而线性的提高存储游戏数据时的写入性能。

 authsv是共通的

● 分为5个平行世界,1个平行世界允许同时连接6000名玩家,总共允许3W玩家同时访问游戏

 1个平行世界分为8个区(8核,8个进程)

 1个平行世界准备360个实例(16, 16个进程)

● 玩家继续增加的情况下,追加平行世界

 5-1-2-1中,各个服务器的分布情况:

① 尽量使得authsv进程并行化

② 各个世界中,worldsv1个进程,gmsv中地区用到8个进程, 实例用到16个进程,不能动态增减。
 proxygmsv的个数相同

 dbsvMySQL、备份用的MySql每个世界1

 msgsv是所有世界共用的,尽量并行化,实际的进程数据要根据之后的基准测试来决定

 logsv是所有世界共用的,只要1个进程,生成多少日志要在开发中决定

进程所需的服务器资源

进程

CPU(内核)

备注

RAM

存储器

TCP会话数

Gmsv

W * (8 + 16)

K-Online中的世界数据都是二维的,故数据量没那么大,内存每个内核1G就够,CPU成为性能瓶颈可能性高

上述 * 1G

不需要

3+

Loginsv

W * 1

通信缓存部分的内存,实际上loginsv很少成为瓶颈

上述 * 500M

不需要

2+

Dbsv

W * 1

通信缓存部分的内存,dbsv中的Mysql大多会成为瓶颈

上述 * 500M

不需要

(8 + 16)+

Proxy

W * (8 + 16)

通信缓存部分是十分必要的,关键是TCP/IPQPS性能可达到多少,但1proxy只为1gmsv,就不会成为瓶颈

上述 * 500M

不需要

500+

Msgsv

W * 2

对玩家的在线状况进行管理,防止二次登录,内存和CPU都可能以外的成为瓶颈,beta测试前要进行基准测试

上述 * 2G

不需要

3+

Worldsv

W * 1

因必须一定程度上把握各个gmsv的玩家状态,经常增加排序和搜索处理,故CPU和内存都容易成为瓶颈

上述 * 2G

不需要

(8+16)+

Commondbsv

1

平行世界方式下,进行与世界无关的持久化处理;存储设备更多地使用后端的MysqlMysql可能成为瓶颈

上述 * 500M

不需要

W

Authsv

W * 1

只具有结算公司网关的功能,通信缓存部分的内存即可,authsv与结算公司间的线路延迟时,会成为瓶颈

上述 * 500M

不需要

2+

Logsv

1

不考虑日志存储量瓶颈,若gmsv等前端服务器突然发送大量日志,网络QPS会成为瓶颈

1G

10T

(10 + W * 30)+

Mysql

W * 2

 

内核数 * 8G

W * 100G

1+

资源估算分为两大类型:CPU为中心的服务器、存储为中心的服务器

 CPU为中心的服务器:

CPU较快,内核较多,内存一般,存储量少,容错性低,一次性的

■ 存储为中心的服务器:

CPU一般,内核一般,内存高,存储量大,容错性高,使用长期

◆ 使用平行世界方式进行扩展的关键

六、 资源估算文档

◆ 以进程列表为基础估算服务器资源

◆ 分别以CPU、存储为中心的服务器

◆ 服务器资源估算 ---- 成本估算

七、 协议文档

◆ 协议的基本性质

C/SMMO中,TCP的基础上构建专用的协议,协议的基本性质:

■ 哪些作为Server,哪些作为Client

■ 长连接还是短链接,取决于是否需强连网进行频繁的网络消息发送

■ 与服务器端间的会话是否是有状态的,是否要进行管理各个会话(例如:定期统计在线玩家人数,可做在ClientServer的连接之间)

■ 是否管理认证时的状态

 ClientServer之间的,ServerServer之间的m :n关系,取决于硬件系统和软件系统设计及处理的性能瓶颈的关系,例如:通常,一个Proxy远远满足于一个GameServer的处理性能需求

■ 是否需要服务器的主动推送(Push)

■ 连接中断时,是否需要立即结束服务

进程种类:

■ 客户端 cli

■ 逻辑服务器 gmsv

■ 登录服务器 loginsv

■ 消息服务器 msgsv

■ 数据库服务器 dbsv

■ 逆向代理服务器 proxy

■ 世界服务器 worldsv

■ 全体公用服务器 commondbsv

■ 收费认证服务器 authsv

■ 日志服务器 logsv

 DBMS

■ 结算公司服务器 paysv

7-1 进程间的关系

 

cli

gmsv

loginsv

msgsv

dbsv

worldsv

com-dbsv

authsv

logsv

DBMS

paysv

cli

 

             

gmsv

       

 

   

loginsv

       

   

msgsv

       

 

   

dbsv

               

 

worldsv

               

   

com-dbsv

               

   

authsv

               

 

logsv

                     

DBMS

                     

paysv

                     

协议性质划分原则:连到谁,就叫谁

 gmsv协议

 loginsv协议

 msgsv协议

 dbsv协议(gmsvloginsvmsgsv都连接dbsv,就叫dbsv协议)

 worldsv协议(gmsvloginsvmsgsv都连接worldsv,就叫worldsv协议)

 com-dbsv协议(gmsvloginsvmsgsv都连接com-dbsv,就叫com-dbsv协议)

 authsv协议

 logsv协议(gmsvloginsvmsgsvdbsvworldsvcom-dbsvauthsv)

7-2 协议基本性质关系

 

Cli

gmsv

loginsv

msgsv

dbsv

worldsv

com-dbsv

authsv

logsv

DBMS

paysv

Cli

 

state

n:1

push

每次连接n:1

stateful

n:1

push

harmful

           

Gmsv

       

n:1

n:1

n:1

 

n:1

harmful

   

loginsv

       

n:1

n:1

n:1

n:1

n:1

harmful

   

msgsv

       

n:1

n:1

n:1

 

n:1

harmful

   

Dbsv

             

n:1

harmful

1:1

 

worldsv

               

n:1

harmful

   

com-dbsv

             

n:1

harmful

1:1

 

authsv

               

n:1

harmful

 

n:1

logsv

                     

DBMS

                     

paysv

                     

state/stateful:需要服务器端管理各个会话的状态

push:需推送信息

harmful:连接中断时,不需要立即结束服务

7-2各服务连接中断时,是否需要立即结束服务

① cli连接gmsv,连接中断时,MMO中是需要立即停止游戏的;但msgsv是聊天服务器,若出问题,游戏还是可以继续进行的,不需立即关闭客户端

② 各服务器间的连接,若前端服务器与后端服务器的连接中断或超时的情况下,前端服务器则停止运行。特别是dbsv异常的情况下,无法保存数据,若还是运行游戏,则产生与存储数据的不一致,这情况得避免,没有等待几秒重连的空闲

③ DBMS,authsv都是低频访问的服务器,则dbsvauthsv都得停止,而引起其余服务器都得停止

协议设计的基本原则:

■ 与后端服务器通信时,尽可能无状态;是可做到对于所有后端服务器无状态的

 MMO系统,战斗、聊天服务器通常采用常连接,亦有使用到短链的场景

◆ 协议的API规范(概要)

协议的实现原则:

■ 后端Server实现基本的、通用的功能,前端Server实现专用功能,降低系统的修改成本,提高开发效率。但若在各自的进程中实现各项功能,即使发生内存访问冲突时,也能防止包含相关功能的部分同时崩溃,Google Chrome采用的多进程就是出于这种考虑

■ 前端Server依赖于后端Server结构,位于后端的Server先启动,前端Server后启动

■ 协议是无状态简单操作的集合,C/S MMO中,复杂处理集中在gmsv,可将有状态的协议限制在clientgmsv之间,除了gmsv协议,若有其他协议需要有状态,一般都是不合理的设计

■ 尽量在一个地方接受外部的异常情况,数据的持久化在一个地方进行,易于维护

■ 优秀的API的调用时序:最上最优

● 不调用API,即不需要;能做到不调用其他接口最好

● 只调用没有返回值的API的单向时序图(7-3)

● 只调用一次然后获取返回值的呈三角状的时序图(7-4)

● 呈锯齿状的时序图(7-5)

gmsv采用比线程更轻量级的回调和任务系统实现异步编程,当C/S MMO中出现“锯齿状时序图”时就需要对其必要性重新加以讨论;在处理互斥机制的部分时,采用“三角状时序图”或“线状时序图”来实现

7-3 单向时序图

 

 

7-3 三角状时序图

 

7-4 锯齿状时序图

 

 

■ 是否有必要Push

◆ 协议的API规范(详细)

◆ 网络数据包格式

八、 数据库设计

◆ 数据库设计图

◆ 编码前的重要的表的设计

 K-Online所需的表

◆ 数据库性能测试

九、 C/S + 中间件

◆ 网络游戏的中间件

 MMO的基础支持单元

十、 开发中的基本原则

◆ 编程之始,编程之续

◆ 数据结构优先原则

◆ 实现数据结构之前的讨论

◆ 维持可玩的状态的原则

◆ 后端服务器的延后原则

◆ 持续测定的原则

GThinkServerEngine

Server_Gate

 complie : 编译和生成protobuf协议相关及.C文件

 config_server : 服务器配置

 console_mgr : 输入管理

 logger : 日志模块

 utility_game : 服务器ID相关函数

 globals : 全局接口、common库头文件,服务器状态

 service_mgr : 服务管理

 service_client : 面向客户端的服务

 service_login : 登陆验证的服务(应考虑独立出来)

 service_game : 面向游戏逻辑服的服务

 handle_service_client : 处理客户端的网络消息

 handle_service_login : 处理登陆的网络消息

 handle_service_game : 处理逻辑服的网络消息

◆ handle_server_performance : 处理qps等性能提升

Server_Game

 complie : 编译和生成protobuf协议相关及.C文件

 config_server : 服务器配置

 console_mgr : 输入管理

 logger : 日志模块

 utility_game : 服务器ID相关函数

 globals : common库头文件和全局的接口

 server_pool : 服务器Socket连接池

 suffix_trie : 敏感词过滤、后缀树

 json_help : json格式转换

 user_data : 玩家所有基类数据节点

 user_extend : 玩家数据节点扩展

 csv_storage : .csv配置文件的打开关闭、读写操作

 mail_template : 邮件模版

 client_layer : 验证客户端网络包的合法性及会话状态是否建立

 client_message_object : 解析客户端消息Object的相关操作:解包[获取msgID、获取msgData + len、获取client session info]、打包,encode + 加密 [rspData]

 client_session : 客户端会话的定义和操作,包含客户端的上下线信息及定时扫描

 client_session_mgr : 客户端会话管理,使用循环队列管理会话信息

 message_listen : 消息监听

 notify_system : 游戏内的服务器主动推送系统

 oss : 运营日志

 rpc_call_db : rpc调用数据库

 service_game : 面向server_gate服务器的连接等管理

 service_game_handler : 处理客户端的网络消息

 service_login : 登录流程的验证服务

 service_mgr : 逻辑服务器本身的网络和服务的管理,例如,服务的创建、网络的状态

 service_tool : 逻辑服务器要管理提供的服务的工具,针对其网络层和服务状态

 user_finger : 逻辑服务器中的金手指功能

 base_object/

游戏节点数据缓存机制:

game_object ---> CMemObject : 内存对象类

game_object ---> CGameObject : 游戏节点类

game_object ---> CGameObjectT : 游戏节点模版类

game_objectsT ---> CGameObjectsT : 游戏节点模版s1,重载

game_objects2T ---> CGameObjects2T : 游戏节点模版s2,重载

rich_user ---> CRichUser : 游戏玩家类,包含玩家所有基类节点的增删查改等操作;玩家所有基类数据节点放在user_data

rich_user ---> IUser : 玩家的功能接口

注意:基类SetGet的接口,仅限于到下一层的信息,接口层次统一,其他具体获取可放具体模块逻辑中。

IGameObject:声明CGameObjectCRichUser

IGameObject---> IGameObject : virtualvoid Release( ) = 0;

IGameObject---> IGameObjectBuilder :

■ virtualCGameObject* BuildObject(pb_common::xxxInfo& info ) = 0;

GameObjectBuilder ---> CGameObjectBuilder:声明玩家所有基类节点CBasexxx

提供生成和获取GameObjectBuilder接口;

 static IGameObjectBuilder*Builder(){return m_builer;}

 static voidBuilder(IGameObjectBuilder* builder){m_builder =builder;}

■ 数据成员:

IGameObjectBuilder* m_builder;

游戏基类数据节点:

user_data ---> CUserData : 存放玩家所有基类节点数据

rich_user ---> CRichUser : 包含玩家所有基类节点的操作(对应client_rich_user)

base_users ---> CBaseUsers : 声明了CUserDataCRichUser;提供的接口:

 void Load() : 玩家数据加载

 void Save() : 玩家数据保存

 bool SafeUpdate() : 安全更新玩家数据

 bool SynUserData() : 同步玩家数据

 void EnumUser() : 遍历玩家数据

■ 数据成员 :

pb_common::DataCtrl m_ctrl;

map<USERID, RichUserSPtr> m_users;

base_user_mgrT --->CBaseUserMgrT : 按标志Flag加载玩家数据节点及更新玩家数据

base_role --->CBaseRole

base_army_tech --->CBaseArmyTech

base_army_tech --->CBaseArmyTechs

base_bag_item --->CBaseBagItem

base_bag_items --->CBaseBagItems

base_battle --->CBaseBattle

base_enemy --->CBaseEnemy

base_enemys --->CBaseEnemys

base_friend --->CBaseFriend

base_friends --->CBaseFriends

base_manor --->CBaseManor

base_plant --->CBasePlant

base_plants --->CBasePlants

base_quest --->CBaseQuest

base_quests --->CBaseQuests

base_suit --->CBaseSuit

base_suits --->CBaseSuits

等都是挂载在User节点下的,而User的做法是将数据放在CUserData类中,将数据的操作放在CRichUser类中

最终,玩家所有节点数据派生为以GameObject为父类的子类,并且以模版类GameObjectsTGameObjects2T的形式存储在内存中,提供GameServer全局的数据访问和修改的接口IGameObject

节点数据生命周期中的轨迹图:

 codec : 网络层数据设计:数据包格式、解包和打包方式、加解密方式等

网络包消息格式定义:

--------4--------8--------12-------16------20-------24--------28

        |   |        |        |                |         | |  

|- MsgHead -| userid |-   TokenBlob          -| EncodeBlob|

|-                  MsgHeadClientRequest                   -|

MsgHeadClientRequest -- MsgHead - hdr_len4Byte

                      |         |

                      |         - hdr_msg 2Byte

                     -- session 4Byte

                      |

                     -- userid 4Byte

                      |

                     -- TokenBlob - org_len4Byte

                      |            |

                      |            - mode 1Byte

                     -- EncodeBlob - checksum4Byte

                                   |

                                   - reqid 8Byte 

--------4---------8--------12-------16

       |    |    |       |  |      |

|- MsgHead -|    |EncodeBlob |

|- MsgHeadClientResponse    -|

 

hdr_len 4Byte

hdr_msg 2Byte

result 2Byte

ogr_len 4Byte

mode   1Byte

 client_object/

client_game_object_builder--->CClientGameObjectBuilder

client_user_mgr --->CClientUserMgr

client_users --->CClientUsers

client_army_tech --->CClientArmyTech

client_army_techs --->CClientArmyTechs

client_bag_item --->CClientBagItem

client_bag_items --->CClientBagItems

client_battle --->CClientBattle

client_enemy --->CClientEnemy

client_enemys --->CClientEnemys

client_friend --->CClientFriend

client_friends --->CClientFriends

client_manor --->CClientManor

client_plant --->CClientPlant

client_plants --->CClientPlants

client_quest --->CClientQuest

client_quests --->CClientQuests

client_rich_user --->CClientRichUser

client_role --->CClientRole

client_suit --->CClientSuit

client_suits --->CClientSuits

Server_Redis_Cluster

Server_Redis_To_DB===>???(有没有更好的方法)

Server_Db_Cluster

Server_Common_DB ===>???(必要性)

Server_Login

Server_Auth

Server_Fight

Server_World

Server_Log

未完待续!待完善!