服务器框架回顾

时间:2022-08-28 12:06:28

  【c++端游】

  第一个接触的游戏项目,MMORPG,虽说MMORPG有蛮高的技术门槛,但那会大多在写逻辑,很少深入底层,所以收获有限。

  win平台的,整体看分了三层:HomeServer、GameServer、四个DB进程(AccountDB、CharDB、LogDB、MailDB)。HomeServer负责登录排队、同中控、平台交互等;GameServer是游戏主体,内部除了数据库、网络IO......游戏逻辑相关的采用了单线程架构,有统一的Service循环框架,各种功能都是注册进Service由主循环发起,比如:AI、Buff、移动、玩家数据写库...

  在线玩家均放于内存池中,因单线程缘故,所以对强交互的支持很高(不必考虑并发操作一致性,rpc调用,rpc delay……)。类传奇的战斗方式,也能应付密集计算。

  可惜整体上的实现了解不多,深入研习过的只有三个部分:AI、网络模块、活动设计。

 

  我们的AI是个基于虚函数的递归调用系统(本质用的解析器模式),附带初始化时指定切换规则。简单说来分为三个层级:

    1)Do:执行基础动作,如走路、攻击、睡觉

    2)Base:对Do层做简单包装,加入条件判断、控制等,如随机走、围绕某点、跟随

    3)Logic:组合任意AI(Logic之间也能互相组合),有切换逻辑

  同行为树的区别:

    1)逻辑判断、行为写在了一起

    2)行为树提取了通用节点,易于组织逻辑,比如

      a)Selector Node

      b)Sequence Node

      c)Parallel Node

  与外部系统交互上:

  • 行为树
    • 弄个全局变量/dic,写condition检测
    • 新增对应条件节点,Update时自己检查
  • 项目AI
    • 通过事件类型,直接告诉AI切换行为( OnEvent )
    • AI内部只关心自己的常规流程,比如巡逻、攻击、跟随…
    • 特殊条件的逻辑,全交给外界事件处理……觉得这样解耦挺不错
      • 发事件的地方,相当于决策层
      • 行为树里的决策层,就是整个树结构,行为都封装在行为节点,或一棵小树里
    • 相对而言行为树的Condition Node就得拉入外部数据

  

  这个AI系统,对比behaviac的行为树,量级算是很轻了,核心代码不超300行,容易把控细节,且实现大多玩法的AI不成问题。

 

  网络模块,windows下固然是IOCP,这个可以另开贴子详细描述,可挖的东西非常多。

  活动设计,一位大神的作品,用c++做通信内核、数据存放,具体逻辑全放Lua脚本,扩展性非常高,且使用方便。举个印象很深的例子:

  客户端需要的数据是非常杂乱的,很难统一格式,大神在脚本层做了一套指令系统,svr端只需调同一接口发出指令即可,形如“Command#param1#param2#param3...”,客户端脚本中,只需注册同名函数,即能自动调用。发送显示信息方便非常。

 

  AI和IOCP有整理重构过,源码地址:

  https://github.com/3workman/InterpretAI

  https://github.com/3workman/IOCP

 

  【lua手游】

  这个项目的架构比较时髦,Logic、Gateway、Battle、Cross、SDK、Center、DB、World……齐全了。

  多线程架构,c++做内核,Lua写逻辑,其中Logic、Battle、Gateway、DB均可水平扩展。Cross负责后台模块之间的通信,比如Battle同Logic(每个Battle、Logic完成初始化后,去Cross注册下)。

  先说优点:

    1)使用方便,包装的Rpc通信,不必注册消息,且用的buffer传参,代码中连定义消息结构体都省了;

    2)起服流程设计很好,区分了Init、OnReady、Sequence等不同的接口调用阶段,方便数据布局、热更新;

    3)借助Lua强大的mettable,可以做到在业务层消灭所有数据库操作,全底层控制,玩家数据自动同步客户端;

    4)支持逻辑事务性,server端批量操作,直接调接口,只要一个失败,整个msg调用自动回退……爽的一比,不用预先搞一坨判断;

  缺点也明显:

    1)底层有大量的数据拷贝,性能不高,作为手游服务器,貌似仅支持5k在线

    2)不支持强交互,同erlang、go自带的轻量线程不同,这里的是系统级线程,玩家之间的数据修改加锁的,且无法保证时序上数据的一致性,比如B先改了A的数据,C再去访问,很可能C拿到的还是旧数据……批量玩家的数据交互,甚至需要开发者自己预估竞态,然后用对应技巧规避;

    3)该服务器原用于页游的,被设计成:一个服务器进程可跑多个服的数据,所以一个线程可能在跑几个服的数据,而一个服的数据也会分在多个线程中。这个特性让你在写代码时要额外注意,比如A、B两玩家若分配在不同线程,那他们彼此是不可见的,用错API就一直返回空了;再比如活动数据,要求全服一致,就不能随便乱放了;

    4)静态生存期的数据种类太多了,有:玩家数据、玩家临时数据、ShareData、玩家共享数据、lua文件数据、全局_G数据……要理解它们各自存在的目的、适用场景~~可得一番功夫

 

  虽说如此,但这个架构我觉得是很优秀的,尤其设计思想,几个优点带来的福音,写代码high爆了,开发效率非常高,一个熟手就能应付全部svr端任务。

 

  【go手游】

  最近刚接触,go是个很好用的语言,并发虽然没erlang那么牛逼,但一般的游戏绝对够用。且写出的代码可读性高(也有不好的,没奇技淫巧玩,硬编码的写法多了不少),静态语言省了一大部分动态语言的debug时间。

  说回架构,这个项目用的多进程架构:accountSvr、battleSvr、chatSvr、crossSvr、gamesvr、logSvr、mongoDB。

  主逻辑服务器gamesvr用的http短连接(上面两个都是用的长连接,Battle战斗服务器用的UDP),battleSvr、chatSvr用的tcp长连接同client交互。

  每个模块都是单独的一个进程,架构非常清晰,功能内聚,很有些每个模块提供一种服务的味道,可以继续延伸,还在研习之中。

  这个相比之前的服务器,最大优点是简单、清晰,学习掌握成本很低,且够用……嗯,这也是go的设计哲学呐(*^__^*)