对于游戏服务器的一些思考和研究

          客户端已经写了五六年了,但是并没有写过服务器。现在有相关的需求,希望能够以比较省时省力的方式完成服务器的开发。经验比较浅,所以以下言论只是个人观点和吐槽。

 
          我对服务器技术的理解是这样的。做到京东、阿里这么大的规模的时候,对数据一致性、容灾、安全性、稳定性、并发性等等都有非常高的要求。这个很依赖于经验,没有足够的经验,学的再多也是纸上谈兵。 web服务器跟游戏服务器有所区别。 web服务器逻辑相对简单,对并发有很大的要求。 游戏服务器逻辑可能会非常复杂,并且要时刻面对策划和运营的需求和变化,另一方面,虽然我们很关注游戏服务器的最高承载人数,但是其实对并发没有那么高的需求,比如一台服务器能够做到5000人同时在线就算做的很不错的了。


          我的需求是非常简单的,不是要做一个MMO的服务器。虽然会考虑一些分布式、全区全服之类的东西,但是对性能没有太高的要求。反而是由于人手不足,所以会对开发效率有一定的需求。

          对于服务器,我们需要解决这么几个问题:1、服务器逻辑如何维护,如何实现一个功能   2、服务器和客户端的通信  3、数据库

          一个传统的服务器就是一个进程,负责客户端登录,维护数据。 我们可以再划分出网关服务器(负责负载均衡、屏蔽内部网络)、登录服务器(负责不同平台的登录)、游戏逻辑服务器(负责实际的游戏逻辑)、数据库服务器(负责持久化数据)。  对于分布式服务器有两种划分方式,一种是分进程,即,把聊天、商城、战斗等单独开一个进程用作独立的服务器逻辑,这样可以有效利用cpu核心。  另一种是按场景划分也就是我想实现的全区全服的服务器的架构,不同的场景对应不同的场景服务器,角色可以在场景服务器中间自由的跳转,这些场景服务器公用同一个逻辑服务器和数据库服务器,如果有必要的话,逻辑服务器和数据库服务器也可以做成多进程的。

          我考虑过这么几个方案:

          1、c++xlua,核心组件用c++来实现,逻辑用lua来实现。 这个是我认为最正统的服务器方案,参考云风的skynet。不过这样相当于要自己重写一个服务器,对我来说,用还不会用呢,更何况自己来写。 而且现在c#写的多了,越发感觉c++的开发效率确实不高,虽然高手无论用什么写都会写的很优秀,但是高手毕竟是少的,更多的时候面临的情况是招不到合适的人,或者不靠谱的人写了一大堆坑等着自己来填(跳)。

          2、java服务器。  现在看来java的效率并不低,jit之后不会比c++有量级的差距,比如差个三五倍吧。如果考虑到java有很多优秀的类库,如netty,性能说不定比蹩脚的c++实现还要高。但是java的开发效率并不敢恭维。最开始我们老大认为,在腾讯都是c++服务器,现在小公司,可能c++的人不太好招,java的开发效率要比c++高,而且稳定,于是就选择用java做服务器。 然而结果是客户端做一个功能要两三天,而服务器做同样的功能要一个月。 java并没有体现出优异的开发效率。  而且我们想再招一个java服务器的时候,并不会比招一个c++服务器简单多少。

          3、pomelo。这个是网易基于Node.js来做的分布式服务器。 结构设计的非常漂亮。 也有一些手游拿pomelo做服务器了,性能和稳定性不用太担心。 如果js经验丰富的话,这个是比较不错的选择。但是个人对javascript比较反感,太过灵活的语法显得非常散乱,语法细节坑很多。 回调是Node.js的灵魂,但是非常不适合维护大型逻辑,具体多大的逻辑是大型逻辑因人而异。对我而言,回调最痛苦的地方还不仅仅在代码形式上(有Promise和Generator),而在于发生错误的时候非常难以调试。  同步逻辑只要设好断点就可以获取错误发生的堆栈,但是异步逻辑只能获得这个回调被调用了这个信息,具体谁调的非常难获取。

          4、python。Firefly,python这门语言我非常喜欢,自己也常拿它来写工具脚本。 但是运行效率是瓶颈,作为web服务器还没有什么特别的影响,但是游戏服务器是计算密集型的,Node.js(jit v8)都可能会有效率问题,更何况是python。

          5、Scut。 C#语言的服务器,我们之前是拿它来做手游服务器的。个人感觉c#的服务器不适合部署在linux上,即便是mono也可能会有一些问题。 如果仅看服务器实现的话,个人感觉非常复杂和厚重,但是框架的实现并不是很漂亮。 能拿来实现功能,但是并不是我心目中的那个她。

           6、erlang。一个actor模型打遍天下无敌手。不过我实在无法接受函数式编程的思维模式。相比erlang,可能skynet会更适合我。

           7、KBEngine。 这个是我最近使用的。从零开始学习服务器相关的内容,并且在一个月的时间内实现了一个棋牌游戏(服务器+客户端)。这个开源的服务器是我感觉最专业,代码实现最漂亮的。 参考BigWorld引擎,c++加python的实现。理论上可以实现全区全服或者是魔兽世界那样的mmo。 我之前也想一步到位,学习一个终极的服务器框架,然后可以解决自己的所有问题。 不过现在看来他有几个缺点(严格来说是与我自己的习惯和实际情况有出入),这个也是我要重点分析的,同时也是我选择游戏服务器框架的依据。

                  a、框架结构非常专业,但是同时非常厚重。 编译时间很长,服务器启动时间也很长(10~20秒),部署也非常麻烦(在linux上面要安装openssl,编译python,设置环境变量)

                  b、分布式并不仅仅体现在多个逻辑服务器上面,而体现在多个逻辑服务器(场景服务器)数据可互通。 这个也是KBEngine非常强大的地方。但是我对这方面的需求反而很低,因为这样的需求是专为MMO服务的,但是我要实现一个棋牌游戏或者手游并不需要考虑太多的数据互通。 只要把公共数据库维护好就可以做一个简单的全区全服的手游了(比如coc)。 没有这方面的需求,但是又需要承担其消耗有点得不偿失。

                  c、python作为脚本语言,我如果仅仅是实现简单的逻辑还没什么问题。但是一旦我所有的服务器逻辑都是python来实现了,那么性能就会成为问题,甚至可能还不如Node.js性能高。  脚本语言比c++、java这样的静态编译的语言开发效率要高,但是实际操作起来却发现很多不顺手的地方,很多静态语言编译期就能检查出来的低级错误,现在必须运行时才发现某个变量名写错了。 在我看来服务器其实对热更新并没有那么高的需求,而且要做成安全可靠的热更新是非常困难的,客户端影响比较小还可以考虑,服务器一旦出错就成百上千倍的放大。能把配置做成热加载的,能不关服务器的情况下开启和关闭某个系统就足够了。 脚本语言除了开发效率高就是热更新方便,然而现在看来热更新需求不大,开发效率也不如使用c#+vs高效。

                   d、RPC的通信方式很棒,可以让客户端和服务器以函数调用的方式来调用远程函数,而不需要考虑通信细节。 然而我非常不习惯这种方式,当需要传的数据复杂了,维护起来反而麻烦。而且传输效率上来讲肯定不如protobuf高。 如果是protobuf来维护的话,只要proto定好了,客户端和服务器共同使用,有类型修改的时候只要关注proto就可以了。 然而KBEngine中的rpc定义参数修改了需要改三处地方,并且还不是静态检查,只有运行时才能发现哪个参数定义的不一致。 另外,如果客户端和服务器都是使用python的话,应该还是比较方便的,但是客户端是c#而服务器是python,rpc反而造成了维护的不方便。

                    e、以实体为单位管理数据,不需要维护数据库,只要定义好实体,那么就会自动将数据保存在数据库中。这点非常棒,因为我没有什么服务器的经验,数据库的优化是我最不放心的地方。 使用KBEngine我完全不需要操心数据库的东西,只要实体定义好就可以了。  不过这里也藏着一些坑,万一它优化的不好怎么办? 频繁的写数据会不会造成性能问题? 它是如何加载相关性数据的? 会不会因为某些实体关系定义的不合理,造成内存爆涨?

                     f、引擎本身有一些小Bug,比如被自己的账号踢了导致这个账号再也登不上去了。 经常出现消息延迟较大,但是不知道原因是什么。  引擎的代码量还是很大的,要想整理清楚所有的问题还是有一些令人头疼的地方。

               


            经过这些尝试和思考,我最终决定使用golang来做服务器开发语言。有这么几点:

1、静态编译型语言。这个是我最看重的,不选择skynet(c+lua)和KBEngine(c++ python)有很大一个原因是动态脚本语言维护逻辑复杂了维护起来非常困难。 静态语言基本编译通过后就没有太大问题了,剩下的就是思考不周导致的bug。

2、堪比python的开发效率。  不选java很大的一个原因是这个。  我不需要最优方案,也不需要最稳妥的方案,只需要一个合适的方案。

3、并发模型,可以轻易利用起多核。 不选Node.js的原因是callback还没有真正完善的解决方案

4、有现成的开源服务器。即便不说有成功案例,至少是有可行的案例

5、优异的跨平台能力。  我想部署KBEngine到linux,结果python编译了半天都没成功。(顺便吐槽下linux,不同发行版本,软件源中的软件名不一样,操作命令和习惯也不一样,简直是作)

6、部署方便,只要把执行文件拷贝一下就可以了,没有太多的依赖或者动态库。同样参考上一条。

7、支持protobuf、mongoDB。KBEngine中我一直想做这个修改,不过改动太大,完全Hold不住。这个不算特别的优点,因为很多其他的方案也都支持,只不过恰好不谋而合而已。

        

你可能感兴趣的:(对于游戏服务器的一些思考和研究)