精华内容
下载资源
问答
  • 游戏服务器开发都要学什么

    万次阅读 多人点赞 2019-08-22 17:26:27
    一,游戏服务器开发工作介绍 近来遇到有很多人想从其它开发领域转到游戏服务器开发行业上来,他们或许觉得游戏服务器开发工资高,或许觉得做游戏服务器需要掌握的技术更高级,可以锻炼自己,或许觉得想换个环境等等...

    一,游戏服务器开发工作介绍

    近来遇到有很多人想从其它开发领域转到游戏服务器开发行业上来,他们或许觉得游戏服务器开发工资高,或许觉得做游戏服务器需要掌握的技术更高级,可以锻炼自己,或许觉得想换个环境等等。不管出于什么原因吧,做为一名几年的游戏服务器开发者,当然是持欢迎态度的,那么我就先介绍一下游戏服务器开发的工作吧,游戏服务器开发具体要做哪些工作呢?

    1,团队沟通

    基本上不管做什么开发,都是一个团队来完成的,游戏也是如此,游戏团队一般由老板,总经理,CTO(技术主管),主策划(领导一些人,包括数值策划,系统策划,特效策划),主美(领导一些人,包括原画,UI设计,特效动作设计),客户端主程(领导一些人,客户端程序员,客户端程序员...),服务器主程(领导一些人,包括服务器程序员,服务器程序员),外加运维。而游戏的大部分逻辑实现与逻辑数据验证都会放在服务器端,所以服务端程序需要明确了解策划的需求,要了解就需要沟通,沟通方式的正确与否,直接关系到功能的实现是否正确,由于游戏逻辑的复杂性,单纯的文档描述可能不会非常完整,不像其它行业需求文档就几百页,详细的图文并茂,制定好之后也很少变化。所以做为一名游戏程序员,一定要有良好的沟通方式和技巧。

    2,架构设计

    这个架构设计就像盖房子打基础,基础好,房子就稳固,基础不好,房子高了就容易倒。架构设计需要结合软件工程学来搞,它需要对服务器的整个流程有足够的了解,对需求的变化有足够的认识。架构的设计一般有几个特性。

    首先是易用性,架构一旦完成,在开发的时候就要方便使用,比如网络通信架构,设计好之后,其他开发者就不需要关心客户端的数据是怎么被传输到服务器端的,这个时候对于服务器开发者来说,只需要实现一些简单的接口,就可以直接对客户端发送来的请求进行处理操作。再比如说服务器端数据的存储与更新,开发者只需要写少量SQL语句或基本不用写,都由架构的底层代码完成,开发者只需要调用封装好的API,就可以把数据存入数据库而不用关心数据的最终流向,只需要关心实现逻辑就可以了。

    第二,可扩展性,可扩展性包括两个方面,一是代码的可扩展性,比如说游戏中的任务处理吧,一个游戏中任务可能有几十种,而且还可能不定时的增加,为了判断不同的任务类型该执行什么操作,最简单也是最差的写法是if else,想象一下,一个方法里面,有几十个if else,这简单是bug的理想诞生地呀。一种可行的做法是使用责任链模式(具体的请参考设计模式的实现),这样每种任务都有一个单独的类去处理它,而不会影响其它的类,符合开闭原则,相互关联少,越少越不容易出bug。二是部署的可扩展性,比如,如果在线人数突然增加或预期可能要增加,一台物理机器可能处理不过来这么多的请求,那怎么办?那就需要支持在不影响其它服务器运行的情况下,可以动态的添加机器。而当压力降低之后,又可以移除某些机器,合理利用资源。

    第三,高吞吐量,这个是指能尽量最大化的利用计算机固定的资源,去处理更多的请求,更快速的响应客户端。这就需要在服务器架构设计的时候考虑异步处理,减少IO等待时间(比如请求redis,存储数据库,和其它服务器通信)以及数据缓存。说到异步,一定会涉及到多线程,并发等相关的技术,所以架构设计的时候需要对这部分知识有足够的了解。

    第四,要考虑是否所有的功能模块都放在同一个进程中。也就是需不需要分布式开发,哪些功能需要单独拿出来。对于手机游戏来说,一般要求同时在线量比较小,功能比较单一,所有功能都在一个进程中,人数大量同时在线时,可以多部署几组进程。而对于大型网页游戏或客户端游戏来说,特别是有些大区或不分区的情况,单个功能访问量大,服务器就要考虑分布式部署开发了。

    架构设计一般需要有经验的开发者(项目主程)去搭建,新手可以做为了解,在接触到项目之后,可以按这个思路去理解项目的架构是怎么样构成的,如果让自己来做,能否模仿出来,有时间可以自己尝试去独立设计架构,锻炼自己的能力,为将来自己带项目做主程做好充值准备,机会都是留给有准备之人的。

     

    3,逻辑开发

    架构搭建完成之后,紧接着就是游戏服务器的逻辑开发,这时才开始真正去实现游戏需要的内容,比如注册,登陆,任务,活动,背包,组队战斗等。由于游戏逻辑可能需要的判断条件多,组合变化多,所以在游戏逻辑开发过程中,你会慢慢发现面向对象的重要性。逻辑开发是一个任重而道远的过程,同一个问题,可能有很多种实现方式,不同的实现方式对效率和吞吐量有很大的影响,所以就需要对需求功能的理解要深入,不同功能之间的关联要明确。对常用的设计模式要知道如何使用。比如像上面说的替换数量比较多的if else的方式。逻辑开发需要谨慎细心,而且一定要自己测试才可以,不然bug在不知不觉中就产生了。

    4,系统周边开发

    一个游戏成功的运营,需要很多服务去支持它,比如sdk接入,充值接入,日志统计,游戏运行管理系统(一般叫后台管理系统,是内部人员为了管理游戏的而开发的系统)。比如修改某个用户的等级,封号等。管理系统一般会用web开发,与游戏服务器通信。

     

     

    二,游戏类型与技术选择

    游戏服务器开发使用的技术取决于游戏的类型,不同的游戏类型,需要的游戏环境不一样,所使用的技术也不一样。但是在本质上都是一样的,都是面对数据,处理数据,不同的是面对的数量大小而已。

    1,PC类端游

    这类游戏在线人数庞大,游戏中要处理的数据也非常庞大。所以对服务器性能要求非常高,一般都是采用C++做为开发语言,C++可以直接操作内存数据,与操作系统直接交互,减少数据之间的复制,它运行效率高,处理速度快,是这类游戏开发的首选开发语言。服务器端采用分布式架构,把不同的模块分散在多台物理机上处理。需要学习的大致有C++编程,Linux网络编程、TCP/IP通讯协议、多线程编程再加数据库。它一般开发周期比较长,一个游戏的上线基本上需要三到五年。

    2,网页游戏

    这类游戏相对于端游来说,开发周期短,因为是网页游戏,游戏的界面展示依赖于网络传输,所在在画面和特效上会次于客户端游戏很多。游戏的特点主要集中在游戏的玩法上。但是对于服务器端来说,和端游类是差不多是一样的,有些公司之前是做端游的,他们就直接把端游的服务器架构拿来就可以使用,以完成快速开发。

    3,手机游戏

    手机类游戏目前是最火最热门的游戏,因为他的用户量大,用户占有时间长。但是手机游戏大多数是一般小游戏,功能简单,玩法单一,一般都是休闲娱乐的。现在也有一些稍微大型的MORPG游戏。所以手机游戏开发周期更短,上线更快。

    目前,游戏市场竞争激烈,当前服务器主流的开发语言是C++和Java,但是C++学习难度大,开发速度慢。为了满足游戏服务器快速开发,快速上线,所以一般来说我们都是使用Java语言来开发服务器。近年来,随着游戏市场的发展,游戏服务器开发技术因Java而生成了一套体系。可以供开发者选择。

     

    三,使用Java开发服务器需要学习什么

    Java语言,由于学习成本低,开发速度快,稳定性高,开源框架多,目前已成为网页游戏和手机游戏服务器开发的主要语言。咱们从系统的开发流程简单梳理一下服务器开发需要用到的技术。

    1,网络通信

    这个是首要实现的,如果没有网络通信,就没有服务器存在的必要了。网络通信就需要建立网络连接。目前网络通信有两种方式,一种是短连接,比如http,一种是长连接,比如socket,当然http也是基于socket的,socket是通信的基础。所以要对tcp/ip通信的知识有所了解,明白通信的原理。基于这两种网络通信,游戏服务器也分为两种,弱联网和强联网。弱联网的游戏一般是指一些小型的游戏,比如开心消消乐,连连看,以及一些卡牌养成类游戏,这类游戏一般几秒钟或几分钟再会与服务器同步一次数据,一般会使用短连接。而像一些arpg游戏,实时战斗类游戏,以及带同屏显示玩家的游戏,这类游戏与服务器交互信息频繁,一秒钟可能几十次,会采用长连接,避免每次连接重新建立消耗系统资源,提高通信效率。

    为了网络通信的效率,服务器要使用NIO(非阻塞网络通信)通信。它能支持大并发连接。Java NIO是多路复用IO,在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。目前基于此技术有很多开源框架,目前最热门的NIO异步网络通信框架是Netty,它目前已被应用到种大型的开源软件之后,比如RPC调用,阿里云的消 息队列组件RocketMQ,Spring cloud的网关组件也是用Netty实现的。为了便于新手学习,可以参考这个单服游戏服务器框:https://gitee.com/wgslucky/xinyue-alone-game-server  ,此开源框架实现了游戏服务器开发中常见的基本功能,比如网络通信,消息序列化与反序列化,逻辑处理,多线程封装,消息广播,消息加密解密,消息压缩与解压,连接管理,断包与粘包处理等。

    所以在网络通信这一块,如果是弱联网游戏,可以使用web那一套来开发游戏服务器,需要学习的技术一般有http原理,Json格式协议,servlet,Tomcat(也可以是其它web容器),spring等。如果是强联网游戏,要学习的技术有Netty或Mina可以选择一种,多线程以及线程池的应用。这是网络通信所必须掌握的。只要能把客户端发送的信息接收到,并解析成代码使用的明文,就是成功了一半了,剩下的事就是把代码封装好,方便逻辑开发调用!

    通信这块还要考虑消息的并发,长连接情况下,怎么处理断包,粘包问题,每个用户的消息处理的是不是有序的,如果有序会不会阻塞消息,如果无序会不会造成处理混乱,比如后到的消息先处理了,这些问题都要处理好,目前一般是保证同一个用户的消息要有序处理!

    2,数据存储

    网络通信调试好之后,不要急着做逻辑开发,还需要把数据如何存储理清楚!因为服务器端操作的全是数据,如果处理的不好,容易出bug,丢数据,这对游戏玩家来说是致命的,不可接受的!数据存储要考虑,

    一,数据如何存到数据库,是同步存储,还是异步存储!同步存储即将数操作完之后立刻写入数据库,异步操作即数据操作完之后先存储到内存缓存,然后由另外的线程或进程再同步到数据库!游戏中一般都是采用的异步存储方式,因为游戏并发量大,必须低延时,快速响应客户端!如果直接操作数据库太慢,会造成消息阻塞!内存缓存可先择的框架有redis,memcache,具体怎么同步到数据库,需要自己去设计了!

    二,数据接口如何设计,能不能用工作生成这些数据操作的代码,能不能不用写SQL语句,需是封装在底层,或由工具生成。编程是门艺术,在这就体现出来了,当然是仁者见仁,智者见智了!

    三,大并发情况下数据的一致性,像这类可能多线程操作的数据,一般是放在内存中,由锁来控制并发!所以对锁的使用要熟悉,不要出现死锁,或锁粒度过大,造成线程的长时间等待的情况!四,当数据量太大,一个数据库存储不了,数据该怎么分库分表!一种是水平划分,一种是垂直划分!具体的划分方式其它资料已有详细介绍,请自行查找阅读!目前有一个开源的分库框架mycat,是用JAVA写的,大家可以研究一下!

    四,目前常用的数据库有MySQL和MongoDB,MongoDB的优点是在开发过程中添加或删除字段不用操作数据库表,它是文档性数据库。两者各有利弊,可以都熟悉一下。

    3,逻辑开发

    逻辑开发就是实现游戏策划想象的各种游戏功能,比如,登录,物品使用,战斗结算等!逻辑开发代码量巨大,相互之间有很紧密的耦合性,所以每个功能模块一定要划分好!最好是接触下单元测试,写之前考虑一下是否方便单元测试,这样设计的代码会更加清晰,每个方法责任明确,不容易出bug!正是因为逻辑代码复杂,为了更好的管理代码,前辈们给我们总结了一些经验,就是著名的设计模式,所以学习一下设计模式对代码的管理有很大的好处!

    逻辑开发一般遇到的问题有:

    3.1,数据同步

    一说到数据同步或资源共享的时候,一般都会考虑到锁的使用。因为一份资源同时只能被一个线程访问才是安全的。Java的JDK中提供了一些锁,比如:synchronized,以及java.util.concurrent.lock包中的Lock对象,java.util.concurrent包中还提供了其它的一些原子操作的类,我们知道i++操作不是线程安全的,但是可以使用AtomicInteger中的getAndIncrement();方法代替,还有线程安全的ConcurrentHashMap哈稀Map。以及阻塞队列LinkedBlockingQueue等。都是逻辑开发中常用的处理数据同步的类。

    3.2,设计模式的使用

    使用设计模式,可以让代码更加清晰,可扩展性更强,维护性更佳,比如,任务系统,任务会有很多种类型,要获得任务数据时,在一开始写这个系统的时候,我是这样写的if(type == 1)做什么,else if(type == 2)做什么,else if(type == 3)......else if(type == 35) else等。如果需要添加新的类型,又要添加else,这些if else都在同一个方法中。最后都不敢动一块,就怕出bug。其实当一个方法中出现三个以上的if else将来还可能增加时,就应当考虑设计是不是有问题了,后来改成责任链模式或状态模式,就解决了这个问题。还有一个例子是,当一个值变化,要影响多个任务完成状态时,可以使用观察者模式或监听模式或订阅模式去实现,这样功能之间完全解耦,出问题的机率会很小很小。

    3.3,数据缓存框架的API使用

    目前主流使用的数据缓存框架有redis和memcache,虽然在逻辑开发前,主程会对这些进行一些封装,但是作为使用者还是需要对这些框架的客户端的使用要有所了解的。这些可以去阅读相关的文档。不是太难。

    4,程序部署与运行

    目前,大多数Java项目都采用maven管理 ,可以使用maven打包开发好的程序,程序一般运行在远程服务器上,比如云服务器。一般运行Java程序的远程服务器都是Linux系统,需要使用Linux命令操作,或写一些shell脚本去自动化部署管理一些程序。

    5,艰苦奋斗的精神

    首先,一定要让自己对这一行有兴趣,明确自己在这一行的技术选择,人生选择。很多人都知道,程序员加班是常有的事,坚持的住就做,坚持不了就再换一家公司做。

    综上所述,想做Java游戏服务器方面的开发要掌握的技术有以下一些:

    1,网络通信框架,Mina或Netty必须熟悉一种。而且自己必须要亲自搭建过,并明白其它原理。

    2,通信协议制定和处理断包粘包,这一般属于网络通信框架要解决的问题。

    3,数据缓存框架,redis或memcache选择一个,能熟练使用其客户端的命令。

    4,Java基础,Java NIO通信原理,Java集合的使用,Java多线程开发,Java锁的使用,在Java界,以后Spring MVC,Spring Boot,Spring Cloud是必不可少的。

    5,了解一些设计模式。最好能把23种设计模式都看一遍,并结合自己的开发经验,看哪些可以用到设计模式,但也不能死套设计模式,要灵活运用。

    6,熟悉使用Mysql数据库

    7,了解数据库连接池的一些框架,比如Mybatis,hibernate

    8,对Http协议熟悉,熟悉一种web容器,比如tomcat,了解其配置。

    9,对常用的一些Linux命令要熟悉使用。

    10,热爱学习,不断的充实自己,上面所说的只是入门技能而已,真正做起来要复杂的多,一定要让自己喜欢游戏这个行业,这样才能有动力做下去,做自己喜欢的工作还是比为了工作要好的!


     

     

                                                                        

     

    展开全文
  • java游戏服务器必备

    千次阅读 2018-12-28 16:41:44
    对于一个新手,想接触游戏服务器,一定会有个疑问——使用Java开发服务器需要学习什么?       Java语言,由于学习成本低,开发速度快,稳定

    推荐阅读:

          对于一个新手,想接触游戏服务器,一定会有个疑问——使用Java开发服务器需要学习什么?

          Java语言,由于学习成本低,开发速度快,稳定性高,开源框架多,目前已成为网页游戏和手机游戏服务器开发的主要语言。咱们从系统的开发流程简单梳理一下服务器开发需要用到的技术。

    1,网络通信

          这个是首要实现的,如果没有网络通信,就没有服务器存在的必要了。网络通信就需要建立网络连接。目前网络通信有两种方式,一种是短连接,比如http,一种是长连接,比如socket,当然http也是基于socket的,socket是通信的基础。所以要对tcp/ip通信的知识有所了解,明白通信的原理。
          基于这两种网络通信,游戏服务器也分为两种,弱联网和强联网。弱联网的游戏一般是指一些小型的游戏,比如开心消消乐,连连看,以及一些卡牌养成类游戏,这类游戏一般几秒钟或几分钟再会与服务器同步一次数据,一般会使用短连接。而像一些arpg游戏,实时战斗类游戏,以及带同屏显示玩家的游戏,这类游戏与服务器交互信息频繁,一秒钟可能几十次,会采用长连接,避免每次连接重新建立消耗系统资源,提高通信效率。

          为了网络通信的效率,服务器要使用NIO(非阻塞网络通信)通信。它能支持大并发连接。Java NIO是多路复用IO,在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。目前基于此技术有很多开源框架,最常用的有两种,Netty和Mina。

          所以在网络通信这一块,如果是弱联网游戏,可以使用web那一套来开发游戏服务器,需要学习的技术一般有http原理,Json格式协议,servlet,Tomcat(也可以是其它web容器),spring等。如果是强联网游戏,要学习的技术有Netty或Mina可以选择一种,多线程以及线程池的应用。这是网络通信所必须掌握的。只要能把客户端发送的信息接收到,并解析成代码使用的明文,就是成功了一半了,剩下的事就是把代码封装好,方便逻辑开发调用!

          通信这块还要考虑消息的并发,长连接情况下,怎么处理断包,粘包问题,每个用户的消息处理的是不是有序的,如果有序会不会阻塞消息,如果无序会不会造成处理混乱,比如后到的消息先处理了,这些问题都要处理好,目前一般是保证同一个用户的消息要有序处理!

    2,数据存储

          网络通信调试好之后,不要急着做逻辑开发,还需要把数据如何存储理清楚!因为服务器端操作的全是数据,如果处理的不好,容易出bug,丢数据,这对游戏玩家来说是致命的,不可接受的!数据存储要考虑:
          一,数据如何存到数据库,是同步存储,还是异步存储!同步存储即将数操作完之后立刻写入数据库,异步操作即数据操作完之后先存储到内存缓存,然后由另外的线程或进程再同步到数据库!游戏中一般都是采用的异步存储方式,因为游戏并发量大,必须低延时,快速响应客户端!如果直接操作数据库太慢,会造成消息阻塞!内存缓存可先择的框架有redis,memcache,具体怎么同步到数据库,需要自己去设计了!
          二,数据接口如何设计,能不能用工作生成这些数据操作的代码,能不能不用写SQL语句,需是封装在底层,或由工具生成。编程是门艺术,在这就体现出来了,当然是仁者见仁,智者见智了!
          三,大并发情况下数据的一致性,像这类可能多线程操作的数据,一般是放在内存中,由锁来控制并发!所以对锁的使用要熟悉,不要出现死锁,或锁粒度过大,造成线程的长时间等待的情况!
          四,当数据量太大,一个数据库存储不了,数据该怎么分库分表!一种是水平划分,一种是垂直划分!具体的划分方式其它资料已有详细介绍,请自行查找阅读!目前有一个开源的分库框架mycat,是用JAVA写的,大家可以研究一下!

    3,逻辑开发

          逻辑开发就是实现游戏策划想象的各种游戏功能,比如,登录,物品使用,战斗结算等!逻辑开发代码量巨大,相互之间有很紧密的耦合性,所以每个功能模块一定要划分好!最好是接触下单元测试,写之前考虑一下是否方便单元测试,这样设计的代码会更加清晰,每个方法责任明确,不容易出bug!正是因为逻辑代码复杂,为了更好的管理代码,前辈们给我们总结了一些经验,就是著名的设计模式,所以学习一下设计模式对代码的管理有很大的好处!

    逻辑开发一般遇到的问题有:

    3.1,数据同步

          一说到数据同步或资源共享的时候,一般都会考虑到锁的使用。因为一份资源同时只能被一个线程访问才是安全的。Java的JDK中提供了一些锁,比如:synchronized,以及java.util.concurrent.lock包中的Lock对象,java.util.concurrent包中还提供了其它的一些原子操作的类,我们知道i++操作不是线程安全的,但是可以使用AtomicInteger中的getAndIncrement();方法代替,还有线程安全的ConcurrentHashMap哈稀Map。以及阻塞队列LinkedBlockingQueue等。都是逻辑开发中常用的处理数据同步的类。

    3.2,设计模式的使用

          使用设计模式,可以让代码更加清晰,可扩展性更强,维护性更佳,比如,任务系统,任务会有很多种类型,要获得任务数据时,在一开始写这个系统的时候,我是这样写的if(type == 1)做什么,else if(type == 2)做什么,else if(type == 3)…else if(type == 35) else等。如果需要添加新的类型,又要添加else,这些if else都在同一个方法中。最后都不敢动一块,就怕出bug。其实当一个方法中出现三个以上的if else将来还可能增加时,就应当考虑设计是不是有问题了,后来改成责任链模式或状态模式,就解决了这个问题。还有一个例子是,当一个值变化,要影响多个任务完成状态时,可以使用观察者模式或监听模式或订阅模式去实现,这样功能之间完全解耦,出问题的机率会很小很小。

    3.3,数据缓存框架的API使用

          目前主流使用的数据缓存框架有redis和memcache,虽然在逻辑开发前,主程会对这些进行一些封装,但是作为使用者还是需要对这些框架的客户端的使用要有所了解的。这些可以去阅读相关的文档。不是太难。

    4,程序部署与运行

          目前,大多数Java项目都采用maven管理 ,可以使用maven打包开发好的程序,程序一般运行在远程服务器上,比如云服务器。一般运行Java程序的远程服务器都是Linux系统,需要使用Linux命令操作,或写一些shell脚本去自动化部署管理一些程序。

    5,艰苦奋斗的精神

          首先,一定要让自己对这一行有兴趣,明确自己在这一行的技术选择,人生选择。很多人都知道,程序员加班是常有的事,坚持的住就做,坚持不了就再换一家公司做。

    综上所述,想做Java游戏服务器方面的开发要掌握的技术有以下一些:

    1,网络通信框架,Mina或Netty必须熟悉一种。而且自己必须要亲自搭建过,并明白其它原理。

    2,通信协议制定和处理断包粘包,这一般属于网络通信框架要解决的问题。

    3,数据缓存框架,redis或memcache选择一个,能熟练使用其客户端的命令。

    4,Java基础,Java NIO通信原理,Java集合的使用,Java多线程开发,Java锁的使用

    5,了解一些设计模式。最好能把23种设计模式都看一遍,并结合自己的开发经验,看哪些可以用到设计模式,但也不能死套设计模式,要灵活运用。

    6,熟悉使用Mysql数据库

    7,了解数据库连接池的一些框架,比如Mybatis,hibernate

    8,对Http协议熟悉,熟悉一种web容器,比如tomcat,了解其配置。

    9,对常用的一些Linux命令要熟悉使用。

    10,热爱学习,不断的充实自己,上面所说的只是入门技能而已,真正做起来要复杂的多,一定要让自己喜欢游戏这个行业,这样才能有动力做下去,做自己喜欢的工作还是比为了工作要好的!
    原文:https://blog.csdn.net/qq_29166327/article/details/79433018

    展开全文
  • 游戏服务器框架概括分析

    千次阅读 2019-05-05 16:00:47
    游戏服务器框架概括分析 这篇blog题目涉及的范围真大!以至于在这里需要先写一篇前言把范围缩小。选择写这样一个系列的文章,主要是想给工作了两年的自己一个交代,或者说是一个阶段性的总结。两年时间里,房价依然...

    游戏服务器框架概括分析

    这篇blog题目涉及的范围真大!以至于在这里需要先写一篇前言把范围缩小。选择写这样一个系列的文章,主要是想给工作了两年的自己一个交代,或者说是一个阶段性的总结。两年时间里,房价依然再涨,工资依然跑不赢CPI,某人依然在仰望星空。期间很多梦碎了,很多还在坚持着,生活过得波澜不惊。而我也从刚毕业是的青涩逐步蜕变为“老油条”。不知道是一种悲哀、还是一种悲哀、还是一种悲哀....... 庆幸的是梦还在继续,一颗倔强的心还在坚持。希望明天的明天被束缚的心能回到梦开始的地方!

     

    ==========================我只是条分割线========================

        作为本系列blog的开篇前言,本文主要明确网络游戏服务器构架的设计目标,并作出一些限定。因为本系列所讨论的服务器端构架只适用于部分网游,并不是一个通用的网游服务器构架。

     

    设计目标:

    1. 支持的游戏类型:大型MMORPG游戏,类似魔兽世界(有大世界,不是开房间式)。
    2. 连接方式:以TCP长连接为主。动作类游戏并不在本文讨论范围内(因为本人并没有参与开发过动作类游戏),如果有时间可以研究一下龙之谷(部分使用UDP传输)、天下贰(全部使用UDP传输),类似的逆向工程网上已经有人做了。
    3. 在线人数:保证最大1w人左右在线还能比较流畅的运行。如果在线人数大于1w对客户端的同学和策划的同学都是很大的挑战。
    4. 服务器可以以多进程的形式布置在不同的物理主机上,也可以布置在同一主机上,考虑效率的同时兼顾可扩展性。
    5. 能在普通配置的服务器上流程运行,物理主机配置:按照DELL 1950、DELL R610上32G内存的标准来部署主机,一般公司是用不起WOW的小霸王的.......
    6. 内存不用过多的考虑,因为现在服务器的内存已经很大了。减少内存使用会放到模块设计、详细设计里。不在构架分析的讨论范围内。
    7. 偏格斗的游戏会对CPU和带宽要求比较高,设计时需要进行讨论。

     

        设计目标就这些多说无益,核心就是设计出能够支持类似魔兽世界的大型MMORPG游戏的网游服务器端。具体的设计以及设计时的取舍、需要解决的问题等,会在后续的文章进行详细的介绍。

     

     

    网络游戏服务器构架设计(二):刀剑Online - 连接负载服务器CLS

     

     

     

        本文并没有涉及什么逆向工程,只是拜读刀剑Online服务器端主程的文章后[1],想结合自己的经验谈一谈。

    PS:由于题目范围太大,本系列的前言做了一些限制。

     

    一、网络游戏服务器

        要想设计好网络游戏服务器的构架,首先需要知道网络游戏服务器在玩家游戏过程中发挥什么作用。就我个人的理解:网游服务器在玩家游戏过程中扮演上帝的角色。玩家在服务器制定的规则下进行游戏,服务器负责同步在线玩家之间的属性、操作、状态等等,最终在多个不同的客户端呈现一个“统一”的游戏世界。

        所谓的服务器构架在本系列blog中,主要是指如何将服务器各部分合理的安排,以实现最初的功能需求。好的结构不是一蹴而就的,是通过需求的推动一步步的完善。而且每个设计者心中的标准不尽相同,所以我认为并没有绝对优秀服务器构架。本系列文章中所谓的优秀构架是指各方面达到一种平衡(包括成本等的非技术因素)。

        下面先介绍刀剑Online的服务器构架(后续还可能有WOW、天龙等):

     

    二、刀剑Online

    image    

    图1 刀剑Online服务器构架

     

        看了像素的技术总监魏华的文章[1],感觉有点意思。文章中所介绍的服务器构架并不复杂,但满足一般MMORPG网游要求应该是绰绰有余了。按照魏华自己的话,这样的服务器构架主要满足能够接受以下几条限制的网络游戏:

    1. 游戏同时在线人数在1w人以下。
    2. 服务器为多进程程序,可部署在一台或者多台机器上。
    3. 服务器内存足够大,一般一个进程1~2G的内存需求还是应该满足的,64位系统能支持更大的内存需求。内存这块主要看游戏的设计需求。
    4. 刀剑属于格斗性质的网游,对CPU和带宽有一定的要求。(这篇文章写于2005年,当时刀剑可能是按照256k、512k或1M ADSL的网速进行设计的。现在已经开始普及10M网,带宽和网速应该可以满足),网络延迟的问题本文后面再做展开。对CPU的要求主要影响可承载人数。
    5. 地图采用独立小场景的管理模式,各个场景之间通过传送点来连接。每个场景服务器程序分管一部分地图。

        服务器包括游戏中和游戏外两大部分,这里主要讨论游戏中的服务器构架,类似客户端自动更新等的游戏外服务器不在本文的讨论范围。

        接下来对刀剑Online的服务器构架的各个部分进行详细的分析,其中包含很多我自己的想法,很多内容都是我猜测的,因此不能“信以为真”。

     

    2.1 连接负载服务器(Connection Load Server,CLS)

        游戏客户端在游戏过程中实际上是和连接负载服务器(简称CLS)进行连接并做数据交互的。如文中[1]所诉,CLS主要的作用是:

    • 把网络连接和真正的游戏逻辑隔离开,降低游戏逻辑服务器处理网络交互的负担,同时提高游戏的安全性。有了CLS,刀剑Online的服务器对于玩家来说就是一个黑盒,如下图:

    image图2

    • 使场景服务器(Zone Server)更为独立——客户端连接CLS而不是直接连接Zone Server的好处是:用户切换场景服务器时,并不会导致原来的TCP连接断开,从而使设计更为简单和独立。
    • 提高发送广播消息的效率,比如需要全服广播时,游戏逻辑服务器只需要对CLS发送一条广播指令,而向每个用户的广播工作由CLS完成。
    • 完成客户端数据交互的加密解密过程。

    连接服务器的主要工作正如上述魏华谈到的,但有几点并没有做出强调,下面本人结合平时的实际工作给出一些补充(不一定正确):

    根据经验:

        CLS作为与client建立连接、进行数据交互的“Gate”,从程序角度来看CLS的代码应该是最简洁高效的。因为CLS主要负责与客户端交互数据是的加密解密、以及数据搬运。而使用流加密算法RC4对整个数据流进行加密解密是很耗CPU的,因此代码的高效在这个模块是十分的重要。

        为了提高程序的运行效率,CLS程序往往会使用-O3的选项进行编译,这无形中又对代码的编写有更高的要求。CLS一般会有自己的打包机制(控制发送频率),因此常会使用TCP_NODELAY选项禁用Nagle算法。

        CLS常会被分配到不同的物理机器上,因为操作系统在处理TCP包时,需要通过软中断来通知进程或者唤醒system call,在服务器十分繁忙的时候CPU可能处理不过来。解决办法是:使用多核的服务器,然后把TCP的软中断平均分配到多个CPU。(一些操作系统默认只使用0号CPU来处理,Fedora Core release 2默认就是只使用0号CPU,较新的版本我没有做研究)

        CLS在做数据流的解密后,往往需要把数据包构造成内部服务器进程间通讯使用的protocol,这种protocol模块要独立,序列化和反序列化的接口要稳定,这样以后需要更换协议模块也不至于伤筋动骨。可以使用像google的protobuf这样的开源协议,减少开发难度。

        CLS负责建立和client的连接,多会使用多个CLS进程才能支撑1w的在线人数,因此在CLS前端一般会有负载均衡的程序,负责把建立连接的请求均匀的提交到各个CLS。

       有一个需要讨论的问题:作为服务器端的“Gate”,只负责数据转发的CLS是否需要对client发过来的数据进行完全的解密?或者只解密包头,知道转发的目的地即可?(RC4并没有增加流的长度,因此可以只做部分解密)

      CLS只做部分解密:

    好处:将耗费CPU资源的解密功能分摊到别的进程;各进程各服务可以在解密后用不同的方案来构造自己的protocol。

      CLS做完全解密:

    好处:可以提前过滤部分无效的消息,只做部分解密也可以做提前过滤,但是这样太过于依赖协议的设计;在CLS处做完全解密,则往后服务器端的之间的消息传递都是明文,利于抓包查错;由于CLS的功能比较简单,很容易通过加机器来进行扩展,因此计算放在CLS上是比较明智的选择。

     

    总结:

        CLS是一个功能相对简单但要求代码简洁高效的程序,在设计实现的时应该注重效率及代码编写规范。经过对比在CLS程序对数据流进行完全解密是利大于弊的,推荐使用这种方案。

     

     

    网络游戏服务器构架设计(三):刀剑Online - 总控服务器、场景服务器

     

     

     

        上一篇《网络游戏服务器构架设计(二)》介绍了刀剑Online的连接负载服务器CLS,博友提出质疑“说得不够详细,比如你怎么,场景服务器怎么才算一个场景服务器,场景服务器切换怎么处理不断线后连接另一个场景的,还有很多细节问题没有说到”,本篇就来介绍游戏服务器最为核心的部分:游戏逻辑服务器,同时也回答了这位博友的问题。

    PS:本篇的文章结构主要分两个部分,前半部分(2.2节)介绍刀剑Online如何实现游戏逻辑服务器,后半部分(2.3节)为本人结合实际工作对这套服务器构架做出的一些展开解释及补充,主要对设计思想进行分析。精彩在后面哦!

     

    -------------------------------------------我只是条分割线--------------------------------------------

     

    先来回顾一下刀剑Online的总体构架图:

     

     

     

    2.2 游戏逻辑服务器

        顾名思义,就是和游戏具体逻辑相关的服务器(这应是一个统称)。这块是网游服务器端的核心部分,不同的游戏差别会很大。在刀剑中,游戏逻辑服务器分为两部分:总控服务器和场景服务器。

     

     

    2.2.1 总控服务器(Master Server,MS)

        关于总控服务器的作用,刀剑Online的主程是这么解释的:

        总控服务器(以下简称MS)的作用之一是负责玩家在具体游戏内容之外的操作(即.玩家进入场景服务器之前地操作)。如:登录、注销、各种角色操作(创建、删除、选择)等等。

        MS和所有地场景服务器都保持连接,这样它就成为各个场景服务器间的枢纽,当需要一些跨场景服务器的操作或者需要访问别的场景服务器数据的时候,指令都先发给MS,然后MS根据需要再转发给相应地场景服务器或者直接发给相应的用户,并进行后续地协调工作。

        比如:在场景服务器1上的用户A希望向游戏中的用户B发出一条添加好友的请求,则场景服务器1向MS发送添加好友指令并附带了用户B的名字,MS查找发现有B这样的用户,则直接把指令发给CLS,然后由CLS转发给B用户;如果没有发现B用户则直接通知A未发现B。

        又比如:在场景服务器1上的用户A点中了传送点,将要传到场景X,场景服务器1发现X场景并不在自己的管辖范围内,于是发送转移指令给MS,MS查找发现场景X在场景服务器2上,于是先发送用户A的离开指令给场景服务器1,让用户退回到MS上,然后再发送用户A的进入指令给场景服务器2,并说明用户将要进入的场景为X,这样一次跨服务器的场景转移就完成了。[1]

     

    2.2.2 场景服务器(Zone Server,ZS)

        关于场景服务器的作用,刀剑Online的主程是这么解释的:

        场景服务器(以下简称ZS)就是具体负责游戏场景的服务器。玩家选择人物开始游戏之后就进入了这种服务器(即开始游戏之后CLS把所有玩家的操作指令都转给ZS)。

        玩家的各种操作的逻辑都是由ZS完成的,同时,ZS也要负责各个场景以及场景中的NPC和场景中各个物品的逻辑运行。

        每款游戏的真正游戏性的核心就是这些ZS。它的具体细节我就不过多的讲述了,各个游戏的具体内容应该都不相同。不过有几个原则是共同的:

        一、是要高效。如果ZS对游戏逻辑的处理效率低,会直接影响玩家同时在线的数量,并导致游戏中的玩家感觉很“卡”,这是除了网络延时之外第二个会造成游戏 “卡”的地方。提高效率的方法除了对代码进行优化外,就是要使用高效的脚本系统,直接把脚本转化为程序代码编译到程序中去也不失为一个办法。

        二、是要有灾难恢复机制,就是当ZS发生非法操作时(只要不停电)能够恢复出非法操作时各个用户的数据。这个在游戏运营初期服务器尚不稳定的时候非常重要。虽然我们也可以通过加快用户存盘间隔的方式(比如把每10分钟存一次盘改为每1分钟存一次盘),但是这会成倍加重数据库负担,同时也不能避免由于用户刚好在存盘间隔的时候获得了重要的金钱或道具而导致丢失的情况。刀剑采取的方法是在申请用户关键数据对象的时候通过包装的函数从共享内存中申请,这样即便ZS非法操作了,共享内存并不会消失,在重新启动的时候就可以从共享内存中恢复出程序非法时的用户数据。当然恢复的时候也需要对用户数据进行一些校验,以免把已经被破坏的数据存入数据库。[1]

     

     

    2.3 设计思想分析

        游戏逻辑服务器主要负责汇总所有在线的client发来的各种操作、状态等数据包,经过一系列的处理后有选择的广播给需要的client,从而给所有在线的玩家呈现一个“统一”的世界。

        优秀的逻辑服务器架构需要优秀的设计思想,而优秀的设计思想又源于对游戏虚拟世界的适度抽象。抽象可以看作一个工程问题,同时也可以看作一个哲学问题,这正是游戏开发的魅力所在。本系列blog将围绕这种抽象一步步展开,结合不同的项目来诠释网络游戏服务器端的设计思想(希望能做到....)。

        站在服务器端的角度对游戏虚拟世界进行抽象,首先要弄清楚构造虚拟世界需要些什么?让我们来想象一下吧(以下内容参照了《盗梦空间》-“Inception”),先来看一段视频:

     

        Inception是我非常喜欢的影片,第一次看到这一段的时候,就感觉非常像游戏设计。今天能把它写下来也算没浪费几十块的电影票钱。

        影片中饰演the architect(造梦师)的艾伦·佩姬(女),正在接受莱昂纳多(饰演the extractor-盗梦者)的训练。莱昂纳多说道:“Remember you are the dreamer you built this world。”,“I'm the subject my mind populates it”。值得关注的两个名词:world,subject。这就是我们要讨论的主题。那么构造网络游戏的虚拟世界需要些什么呢?其实莱昂纳多已经替我回答了这个问题:“We create and perceive out world simultaneously. You create the world of the dream, We bring the subject into that dream, and they fill it with their subconscious.”。world就相当于游戏里的场景,而subject就是一个个在线的玩家(player)。

        游戏世界(world,这里的world泛指游戏世界及地图,见2.3.2)及游戏对象(object,包括player)是构造网络游戏服务器端时,需要关注的两个重点。如何处理好world和object的关系和地位直接影响到服务器端的构架。

     

    2.3.1 游戏对象(object)

        先来看游戏里一般会有那些object,以Mangos为例:

    class_diagram

    图2 mangos游戏对象的class diagram[2]

         对于上面的类层次结构图这里不做展开(留到本系列后面的文章中展开),这里引用mangos的游戏对象是想给读者一个直观的印象,游戏中的object在服务器端是个什么摸样。类的层次是对游戏世界中的对象抽象后得到的结果,抽象需要“适度”:如果类的层次过深,维护起来困难,而且后期往往会导致基类过于臃肿、不堪重负;如果类的层次过浅,一些object的共性不能体现,很多代码会重复出现在各个子类里,复用性差。

     

    2.3.2 游戏世界(world)

        游戏世界在本文是泛指游戏对象所在的场景,以及附加在场景之上的地图管理和对象管理,这里统称游戏世界管理。

        如何进行游戏世界的管理是一个复杂的工程问题,网络游戏常常会把整个游戏世界分为若干张地图,每张地图又会分为若干个区域进行管理。这若干张地图能无缝的过渡就称为无缝大地图模式(类似WOW),如果像刀剑Online那样只能通过传送服务在两张不同地图之间穿梭的,称为有缝地图。而相对来说服务器端会比客户端简单一些,例:如果在客户端看到的场景是下面这个样子:

    yy4

    服务器端根据划分区域的不同可能看到的地图是这个样子:

    yy5

        这里服务器端用到了tile-based的方式来管理地图,这种tile的方式在2d游戏中十分的常见(打格子),而很多3d网游的服务器端为了减少运算量也采用这种tile模式划分区域进行管理。如果对地图管理有兴趣请阅读云风的blog《用四叉树管理散布在平面上的对象》、《碰撞检测》,本文先不做详细的展开。

     

     

    2.3.3 游戏对象和游戏世界的关系

        如何处理游戏对象和游戏世界的关系和地位,是影响服务器端架构的最直接因素。为了体会到这点,下面将以刀剑Online为例,分析玩家对象(player,游戏对象中最为重要的部分)和游戏世界的关系对整个服务器构架设计的影响。

     

    1. 玩家对象player的构建

        刀剑Online把游戏逻辑服务器分为总控服务器(Master Server,MS)和场景服务器(Zone Server,ZS,本文提到的游戏世界多指ZS),那么在client成功登陆server后,服务器端应该在哪构建player对象呢?在MS上?还是在ZS上?这是个工程问题,同时也是个哲学问题.......

    1. 如果把player(以及其他的游戏对象)放在Master Server上:也就是说所有登陆的玩家的数据都会在MS的内存中有一份映像,MS将保存着player最新的数据。这么做的好处是player的数据统一,从而使同服玩家的一些交互变得十分方便,比如同服玩家组队、交友等不需要知道玩家在那个ZS里。切换场景服务器时也不需要把player数据从一个ZS拷贝到另一个ZS,只需要把player身上记的ZS信息修改一下;player在MS上构建的缺点也是显而易见的,所有中心节点式的系统都会遇到单点不可靠的问题,player的信息都保存在MS上,假如有1w人在线,内存占用就是一个很大的问题(毕竟单个进程的内存使用还是有限制的,实际开发中曾经遇到占用十几G内存的进程......相当可怕),而如果一个player借住外挂发送一些非法消息给MS,错误处理不当时很有可能会core进程,这样一来整个服务器的玩家都会掉线。还有一些和地图相关的逻辑会很难操作,比如player与场景中怪物进行PK时,由于player的数据保存在MS,因此ZS需要做一个Attach操作告知MS某个player和某个monster进行战斗,MS进行完伤害计算后发AttachResult给ZS,最后由ZS再广播给相关的客户端,如图:image如图中标注的(1)~(4)的步骤,展示了这个过程,编程操作起来还是挺麻烦的。
    2. 如果把player放在Zone Server上:这是一种比较常见的方式,player和其他游戏对象在场景服务器中构造,隶属于Zone Server。由ZS来掌管player从编程角度讲好处多多:可以直接获得player的信息,对于场景内交互十分便利,场景内的操作不需要多余的数据传输。而在需要跨场景操作时只需用MS中转一下即可;但是这种方式缺点同样是很致命的,player在Zone Server上构造就失去数据放在中心节点的简洁,player的信息常常需要在ZS、MS和DB上进行同步,这种“三体同步”的痛苦只有做过的人才能体会。比如:几个独立的服务器之上需要增加一个跨服服务器,这几个普通服务器的玩家可以进入这个跨服服务器进行pk。那么就需要将player先从普通服务器ZS退到MS,由普通服务器的MS把player的数据发给跨服MS,最后再由跨服MS发送到跨服的ZS。如果还涉及DB则会更加的复杂。ZS、MS、DB相互独立,如果没有强制规定,这种同步往往是没有方向的:player的最新的数据一般在ZS上,但是有些交互不能在ZS上完成,那么可以有两种选择:(1)ZS把player数据发给MS,由MS进行操作,操作过程中ZS不能修改player的相关数据。(2)把player的最新数据存盘,然后由MS读盘取player的数据然后进行操作,操作过程中ZS还不能改变player的相关数据。不管哪种方法开发的逻辑多了以后都不好维护,从此维护人员都变成怨妇.......

        刀剑Online应该采用的是第2中方式,把player放在Zone Server上。

     

    2. 玩家对象player和world的关系

        如何处理玩家对象player和world的关系集中体现了服务器端的哲学,值得细细品味。处理两者的关系在本人看来有两种主要的模式:一种是以player的中心的“自我”模式;另一种是以游戏世界为中心的“上帝之手”模式。这两种模式的哲学主要体现在加锁模式上,接下来进行详细介绍:

    (一)player的“自我”模式

        “自我”模式顾名思义,就是player以自我为中心,什么事都要亲历亲为。以player使用物品为例:

    image

        如上图是一个完整的player使用物品的流程。“自我”模式体现在上图的(1)位置,在(1)中首先取到服务器中对应的player,加锁后用player调用自己的处理函数进行处理。由于(1)相当于处理客户端发来的请求的入口处,因此在这里进行加锁和解锁操作是十分合适的,此后的(2)~(5)player在调用自己的处理函数时,编程人员完全不需要考虑加锁的问题。

        所谓的“自我”模式,其实就是指在服务器端对player的操作其实都是player自己去完成的,“我”自己去把事情做完。处理逻辑时“我”(自己的player实例)不会主动去锁住对方的player实例,因此一个player不能修改另一个player的数据,world也不能修改player的数据。world和player的关系是“独立”的,player身上记着world的信息(相当于“我属于哪个世界”),world里存放着player的实例,但是它们直接不能直接修改对方的数据。这么做是为了避免死锁,使得加锁解锁变得简单而统一(如上图)。

        “自我”模式有加锁解锁的便利,但是一个网络游戏怎么可能player和player、player和world直接没有交互呢?交互就需要获得或修改对方的数据,遇到这样的问题“自我”模式怎么处理呢?请看下图:

    image

        如上图:client A向服务器发送“向玩家B发起攻击”的消息,服务器端client A对应的实例Player A收到消息后,发现需要与player B进行交互,根据“自我”模型的限定,player A不能直接修改player B的血量等信息,这时player A需要做的是将自己的信息打包成一个msg结构然后push_back到消息队列message queue并指定player B作为接收者。在message queue上将这个msg转发给player B前,会先调用lock(playerB)将B锁住,接着把msg传给player B进行处理,在处理完毕后再调用unlock(playerB)。lock和unlock都在统一的地方调用,加锁解锁十分简洁,playerB处理msg消息时不用关心任何加锁问题。在上图的(2)中,player B进行伤害计算后将伤害消息广播给周围的玩家。

        注意:“自我”模式下,伤害计算是在受攻击方进行的。player之间、player和world之间都是通过消息传递进行交互的。

    总结:

    优点:“自我”模式的优点集中体现在加锁上,编程人员在编写具体逻辑时不用担心加锁问题,也不用费尽心思来避免死锁,因为加锁都在消息入口处统一做了,同时不会主动去对别的player实例进行加锁操作。使用这种模式时,最好把移动的相关逻辑独立出来使用不同的锁,以免照成过多的加锁冲突和等待。

    缺点:“自我”模式的缺点也是十分明显的,每个player实例作为不同的“我”独立存在,需要交互时只能通过消息队列来传递信息,极大的增加了交流的成本(内存、CPU占用率都会增加)。一个player往往不能即时的取到别的player的数据,这样一来很多的计算都只能做延后处理,比如伤害计算就只能放在被攻击者的player上,使得很多需要做先验判断的技能实现起来变得复杂,这类技能只能靠释放技能的player,发送请求消息给其他player,然后再由其他player把自己的信息通过msg queue发给释放技能的player。异步处理方式往往会但来更多的烦恼——需要增加很多错误判断、错误处理以及超时处理等等。在线人数高的时候,message queue的容量以及所占用的内存也是需要考虑的问题。

        引用狄更斯的:“It was the best of times, it was the worst of times”。本人依葫芦画瓢:“自我”模式是一种nb的设计,也是一种sb的设计.......

     

    (二)world的“上帝之手”模式

        “上帝之手”模式是以world为中心(类似war3),以地图为单位进行划分,player、NPC、monster等游戏对象都隶属于world。在world的掌控之下,就像有一只上帝之手在拨弄着这些小玩意。以client A向服务器发送“向玩家B发起攻击”消息为例,服务器端的处理流程如下:

    image

        从上图中可以看出“上帝之手”模式的核心是world去完成这项任务:找到playerA和B,把他们都锁住,然后交给技能模块来进行伤害计算,最后把结果广播出去。整个过程就像在玩war3这样的RTS游戏,服务器就像一个神,以斜45度的上帝视角来观察所有的玩家。

        “上帝之手”模式的设计难点在于加锁策略,因为需要对多个对象进行加锁,加解锁的顺序不当容易产生死锁。加锁策略有很多种,这里不做具体的展开。只介绍一种最常用的方法,即对加锁对象进行排序。游戏对象在产生时都会有一个唯一的id做标识,当lock ()函数能按照一种稳定的算法对这些id进行排序时,就可以避免死锁。比如对游戏对象进行分类:player、npc、monster等,先对分类进行排序,再对对象的id进行排序。需要注意的是MMORPG游戏经常需要进行合服操作,为了保证合服后player的id不会重复,需要对player_id进行一些规划。

    总结:

    优点:服务器程序扮演上帝的角色,可以获得几乎所有的信息,这对逻辑编写带来极大的便利。和“自我”模式一样,最好把移动的相关逻辑独立出来使用不同的锁,以免照成过多的加锁冲突和等待。“上帝之手”模式更容易进行整体规划,更容易实现模块化设计,降低程序的耦合度。

    缺点:上帝也不是这么好演的,“上帝之手”模式对整体框架、接口设计、加锁策略等有更高的要求,同时对编程人员的要求也会更高。

     

     

    网络游戏服务器构架设计(四):云风的轨迹

        最近闲着没事把云风的《开发笔记》看了个遍,希望能从大牛的开发轨迹中得到一些启发。但可能是因为本人level太低,一遍看下来还是云里雾里,不甚明白。没办法只好再看一遍,希望能对他们的服务器端架构有个简单的认识,这里同时做些笔记。

    PS:本文是我个人对云风的开发笔记的读后感,可能会有很多错误,慎入!

     

    ----------------------------------------华丽丽的分割线-------------------------------

     

    一、服务器划分原则  

        在现有的网络游戏服务器端架构中,多是以功能和场景来划分服务器结构的。负载均衡和集群暂且不在本文中讨论(bigworld、atlas)。服务器划分可以基于以下原则:

    1. 分离游戏中占用系统资源(cpu,内存,IO等)较多的功能,独立成服务器。
    2. 以多线程或多进程的编程方式适应多核处理器。
    3. 在同一个服务器架构下,应尽可能的复用某些服务器(进程级别的复用,比如场景服务器)。
    4. 运行时玩家数据的保存、修改及数据流向应该是设计的焦点,它同时也决定了服务器应该如何划分。
    5. 服务器的划分应该适度,在保证清晰的数据流向的前提下,根据游戏的类型和规模尽量减少服务器或服务器进程的个数,以减少服务器之间过多的复制数据、锁冲突(使用共享内存进行通讯时)。
    6. 主要按照场景划分进程,若需按功能划分,必须保持整个逻辑足够简单,并满足以上1、3两点[1]。

     

        接下来我们来看看云风的服务器架构是如何处理好以上几点的。

    image

    图1 服务器架构(此图为本人猜测,可能有误)

     

    二、运行时的玩家数据

        网络游戏服务器程序一项重要的工作就是根据client发过来的数据包,在服务器端模拟玩家的行为操作并把这些行为广播出去。那么服务器程序在运行时就需要一些实体来保存玩家的数据,这些实体可以是一个类,也可以是一个线程,设计思想不同采用的实体差别也会很大。这里涉及服务器端设计的一个核心问题:运行时玩家数据的保存、修改及数据流向。

     

    agent

        云风通过抽象实体agent来处理单个client的服务请求,agent和client是1:1的关系(见图1)。agent是在gate程序后端,负责翻译、转发以及回应客户端发过来的请求。agent的主要工作内容见云风的《开发笔记 (1)》。值得补充的是设计agent的主要优势是:

    把对单个 client 服务的代码集中写在 agent 服务中。由 agent 再和内部其它服务沟通。数据加载使用共享内存的方案,由 agent 向持久化模块发出信号,做加载或纯盘处理,通过共享内存得到结构化数据块。[2]

        agent相当于client在服务器上对应的实体,玩家的属性和数据只能由agent来修改,别的服务只有读权限。通过attach操作获得数据(attach可能是通过服务器通讯框架skynet,也有可能直接mmap到共享内存sharedb上以获得数据)。

        agent的设计使得整个系统对玩家数据的修改只有一个输入点,数据流十分的明确,易于维护。虽然这种设计可能会照成数据的多次复制,但是带来的代码维护和查错上的便利是十分可观的。

        如果把所有的agent放在同一个进程里,在编程该程序时还应该考虑到容错问题,比如说(1)使用C++编写这个程序,agent以类的形式存在,使用thread pool来处理收到的数据包,实际操作时thread的数量是会远远小于agent的数量的,数据包到达后会在队列里等待thread调用agent的逻辑来处理。这是一种比较常见的设计方法,但要注意的是由于agent都放在一个进程里,程序的健壮性要求很高,一个进程core则会导致全服玩家掉线。而使用C++编写也增加了宕进程的可能性……..你懂的。(2)使用Java编写,对于这种“中心节点”式架构来说可能是更好的选择,起码不是因为一个玩家的误操作(可能使用外挂)导致全服玩家掉线。(3)云风似乎是使用lua coroutine来实现agent的相互隔离和协同工作的,这样可以减少单一agent失败对其他agent的影响(动态语言的好处)。

     

    sharedb

        sharedb在系统中的地位看上去像是database前端的cache,但就本人的理解sharedb的作用远不止是一个数据缓存。

        和天龙八部的ShareMemory类似,sharedb也采用了定长的结构化数据(见《开发笔记 (6)》),通过共享内存来实现进程间的数据共享。sharedb的存在使得游戏逻辑处理和数据保存逻辑得到很好的隔离,游戏逻辑不用关心后端的数据是如何保存的,只要sharedb挂上定期存盘的服务,在接口定义明确的情况下,后端到底采用什么样的数据库变得不是那么重要,从而降低了系统的耦合度。

     

    三、服务器底层框架skynet

        skynet的设计思想见《Skynet 设计综述》:

        我希望我们的游戏服务器(但 skynet 不仅限于用于游戏服务器)能够充分利用多核优势,将不同的业务放在独立的执行环境中处理,协同工作。这个执行环境,最早的时候,我期望是利用 OS 的进程,后来发现,如果我们必定采用嵌入式语言,比如 Lua 的话,独立 OS 进程的意义不太大。Lua State 已经提供了良好的沙盒,隔离不同执行环境。而多线程模式,可以使得状态共享、数据交换更加高效。而多线程模型的诸多弊端,比如复杂的线程锁、线程调度问题等,都可以通过减小底层的规模,精简设计,最终把危害限制在很小的范围内。这一点,Skynet 最终花了不到 3000 行 C 代码来实现核心层的代码,一个稍有经验的 C 程序员,都可以在短时间理解,做维护工作。 
        做为核心功能,Skynet 仅解决一个问题: 
        把一个符合规范的 C 模块,从动态库(so 文件)中启动起来,绑定一个永不重复(即使模块退出)的数字 id 做为其 handle 。模块被称为服务(Service),服务间可以自由发送消息。每个模块可以向 Skynet 框架注册一个 callback 函数,用来接收发给它的消息。每个服务都是被一个个消息包驱动,当没有包到来的时候,它们就会处于挂起状态,对 CPU 资源零消耗。如果需要自主逻辑,则可以利用 Skynet 系统提供的 timeout 消息,定期触发。 
        Skynet 提供了名字服务,还可以给特定的服务起一个易读的名字,而不是用 id 来指代它。id 和运行时态相关,无法保证每次启动服务,都有一致的 id ,但名字可以。

        本人感觉skynet像一个发布订阅的消息中间件(还没看源码,可能有误),这种基于服务的即插即用式的框架给服务器端带来很大的可扩展性,同时也使得各模块之间独立清晰,具有良好的可维护性。但是这里有个疑问,服务都以so的形式挂在skynet上,那么这些服务从哪里获取玩家、怪物、NPC等object的数据?是从skynet中获得还是直接从sharedb中获得,出于性能的考虑是不是要把skynet和sharedb部署在同一台物理主机上?这样一来就会增加设计和具体逻辑的耦合度。看了《Skynet 集群及 RPC》,感觉skynet上的服务是要通过skynet来获得玩家的数据,这样操作会不会导致数据被复制很多次,不知道最终的效率是否受到影响?

     

    四、gate

        满足服务器划分原则里的第一点:分离游戏中占用系统资源(cpu,内存,IO等)较多的功能,独立成服务器。

        gate的主要工作可以参见本系列blog的第二篇《网络游戏服务器构架设计(二):刀剑Online - 连接负载服务器CLS

     

    五、场景管理器

        主要用于管理静态场景和动态副本,比如agent登录时查询自己所在场景对应的服务器地址。

     

    六、场景服务器

        场景服务器的内容我没有从《开发笔记》中得到太多的信息(可能level太低),更多的是以功能模块的形式写,比如AOI。不过其中有一点比较新颖的是云风认为player的位置、动作状态,战斗数值状态等都是场景的一部份,应该保存在场景中而不是agent中。本节有所更正见(八)补充。

        据我的猜测,场景服务器应该会负责:

    1. 怪物行走控制,player移动更新及位置同步
    2. 怪物AI策略
    3. 区域性广播,场景广播
    4. 战斗逻辑
    5. AOI服务(Area Of Interest )
    6. 碰撞检测
    7. 自动寻径

        需要注意的是场景服务器修改的一些数据应该以什么样的频率通知agent呢?比如player的位置信息,该信息是完全保存在场景数据里还是说agent里也有一份?

     

    七、总结

        本文是一篇云风《开发笔记》系列blog的读后感,所述内容均是本人的猜测,虽恐贻笑大方,但也希望能抛砖引玉。收笔忐忑ing!

     

    八、补充:

      (1) 云风在微薄上的回复是:“我们最终采用的是单进程多线程, 每线程上一个 lua state 的结构. sharedb 是用来线程间数据交换的. gate 和 sharedb 以及 loader 和 agent map 一样, 都是 skynet 下的独立服务, 以 so 挂接进去的. 后来的商品交易, 掉落品分配也是 skynet 下的服务. ”

      (2) 关于场景服务器,云风已经给出完整的说明,见《开发笔记(14)

        场景服务分成两个部分,一是副本管理器,二是地图服务。在角色数据上,记录有角色应该属于的地图。agent 向地图所属的副本管理器查询,得到他所属的地图服务地址。便可以把自己注册到具体地图上。 
        地图服务管理了所有其中的角色 id ,以及若干 npc 。他的义务在于把让这些 id 对应的 agent 相互了解。但具体逻辑则放在每个 agent 服务上。每个 agent 自己所属进程 attach 其它 id ,可以获取其他对象的状态。

      .........

      (3) 风哥在《开发笔记(25)》中已经提到最终使用单进程多线程的模式。看来简单设计是有共识的:-)

     

    游戏服务器框架分析

    一个大型的网落游戏服务器应该包含几个模块:网络通讯,业务逻辑,数据存储,守护监控(不是必须),其中业务逻辑可能根据具体需要,又划分为好几个子模块。

    这里说的模块可以指一个进程,或者一个线程方式存在,本质上就是一些类的封装。

     

    对于服务器的并发性,要么采用单进程多线程,要么采用多进程单线程的方式,说说两种方式的优缺点:

     

    一、单进程多线程的服务器设计模式,只有一个进程,但一个进程包好多个线程:

    网络通讯层,业务逻辑,数据存储,分别在独立的线程中,无守护进程。

    优点:

    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.开服一刹那,所有玩家全部堆积在同一个新手村.->>>>卡,客户端卡(同屏人数过多渲染/广播风暴) 服务器卡(处理大量同场景消息/广播风暴)

    2.    中期-用户分离集群式
                    GameServe1 Client            |                    DB                 GameServer2
    玩家不断增多->分线->程序自动或玩家手动选择进入 缺点:运营到后期,随着每条线玩家的减少, 互动大大减少。

    3.    中后期 数据分离集群式

    按地图划分服务器,当前主流     新手村问题:《天龙八部》提出了较好的解决方案,建立多个平行的新手村地图,一主多副,开服时尽可能多的同时容纳新用户的涌入,高等级玩家从其它地图回新手村只能到达主新手村。
    4.    当前主流的网络游戏架构


            注:在GateServer和CenterServer之间是有一条TCP连接的。而GameServer和LogServer之间的连接可以是UDP连接。这是有一个大概的图,很多地方需要细化。

    GateServer:网关服务器,AgentServer、ProxyServer
     优点:      (1)作为网络通信的中转站,负责维护将内网和外网隔离开,使外部无法直接访问内部服务器,保障内网服务器的安全,一定程度上较少外挂的攻击。     (2)网关服务器负责解析数据包、加解密、超时处理和一定逻辑处理,这样可以提前过滤掉错误包和非法数据包。     (3)客户端程序只需建立与网关服务器的连接即可进入游戏,无需与其它游戏服务器同时建立多条连接,节省了客户端和服务器程序的网络资源开销。     (4)在玩家跳服务器时,不需要断开与网关服务器的连接,玩家数据在不同游戏服务器间的切换是内网切换,切换工作瞬问完成,玩家几乎察觉不到,这保证了游戏的流畅性和良好的用户体验。
       缺点:  1.网关服务器成为高负载情况下的通讯瓶颈问题 2由于网关的单节点故障导致整组服务器无法对外提供服务的问题
       解决:多网关技术。顾名思义,“多网关” 就是同时存在多个网关服务器,比如一组服务器可以配置三台GameGme。当负载较大时,可以通过增加网关服务器来增加网关的总体通讯流量,当一台网关服务器宕机时,它只会影响连接到本服务器的客户端,其它客户端不会受到任何影响。
    DCServer:数据中心服务器。主要的功能是缓存玩家角色数据,保证角色数据能快速的读取和保存 CenterServer:全局服务器/中心服务器,也叫WorldServer. 主要负责维持GameServer之间数据的转发和数据广播。另外一些游戏系统也可能会放到Center上处理,比如好友系统,公会系统。
        改进:将网关服务器细化为LogingateServer和多个GameGateServer.
    5.    按业务分离式集群 由于网络游戏存在很多的业务,如聊天,战斗,行走,NPC等,可以将某些业务分到单独的服务器上。这样每个服务器的程序则会精简很多。而且一些大流量业务的分离,可以有效的提高游戏服务器人数上限。

     

     

    优点:       1.业务的分离使得每种服务器的程序变的简单,这样可以降低出错的几率。即使出错,也不至于影响到每一个整个游戏的进行,而且通过快速启动另一台备用服务器替换出错的服务器。      2.业务的分离使得流量得到了分散,进而相应速度回得到提升 。      3.大部分业务都分离了成了单独的服务器,所以可以动态的添加,从而提高人数上限。
    改进:甚至可以将登陆服务器细化拆分建角色,选择角色服务器

    6.    一种简单实用的网络游戏服务器架构
    下图中每个方框表示一个独立的进程APP组件,每个服务进程如果发生宕机会影响部分用户,整体服务但不会全部中断。在宕机进程重启后,又可以并入整体,全部服务得以继续。

     

    gls:game login server,游戏登录服务器,某种程序上,其不是核心组件,gls调用外部的接口,进行基本的用户名密码认证。此外需要实现很多附属的功能:登录排队 (对开服非常有帮助),GM超级登录通道(GM可以不排队进入游戏),封测期间激活用户控制,限制用户登录,控制客户端版本等。 db:实质上是后台sql的大内存缓冲,隔离了数据库操作,比较内存中的数据,只把改变的数据定时批量写入sql。系统的算法,开发稳定性都要求非常高。 center:所有组件都要在这里注册,在线玩家的session状态都在这里集中存放,和各组件有心跳连接。所有对外的接口也全部通过这里。 角色入口:玩家登录游戏后的选择角色 gs:game server,最核心组件,同一地图,所有游戏逻辑相关的功能,都在这里完成。 gate:建立和用户的常链接,主要作sockt转发,屏蔽恶意包,对gs进行保护。协议加密解密功能,一个gate共享多个gs,降低跳转地图连接不上的风险。 IM,关系,寄售:表示其它组件,负责对应的跨地图发生全局的游戏逻辑。
    7.另一个架构图

        1-   这是一条WebService的管道,在用户激活该区帐号,或者修改帐号密码的时候,通过这条通道来插入和更新用户的帐号信息。     2-   这也是一条WebService管道,用来获取和控制用户该该组内的角色信息,以及进行付费商城代币之类的更新操作。     3-   这是一条本地的TCP/IP连接,这条连接主要用来进行服务器组在登陆服务器的注册,以及登陆服务器验证帐户后,向用户服务器注册帐户登陆信息,以及进行对已经登陆的帐户角色信息进行操作(比如踢掉当前登陆的角色),还有服务器组的信息更新(当前在线玩家数量等)。     4-   这也是一条本地TCP/IP连接,这条连接用来对连接到GameServer的客户端进行验证,以及获取角色数据信息,还有传回GameServer上角色的数据信息改变。     5-   这条连接也是一条本地的TCP/IP连接,它用来进行公共信息服务器和数个游戏服务器间的交互,用来交换一些游戏世界级的信息(比如公会信息,跨服组队信息,跨服聊天频道等)。     6-   这里的两条连接,想表达的意思是,UserServer和GameServer的Agent是可以互换使用的,也就是玩家进入组内之后,就不需要再切换 Agent。如果不怕乱套,也可以把登陆服务器的Agent也算上,这样用户整个过程里就不需要再更换Agent,减少重复连接的次数,也提高了稳定性。 (毕竟连接次数少了,也降低了连不上服务器的出现几率) 在这个架构里面,GameServer实际上是一个游戏逻辑的综合体,里面可以再去扩展成几个不同的逻辑服务器,通过PublicServer进行公共数据交换。     UserServer实 际上扮演了一个ServerGroup的领头羊的角色,它负责向LoginServer注册和更新服务器组的信息(名字,当前人数),并且对Agent进 行调度,对选择了该组的玩家提供一个用户量最少的Agent。同时,它也兼了一个角色管理服务器的功能,发送给客户端当前的角色列表,角色的创建,删除, 选择等管理操作,都是在这里进行的。而且,它还是一个用户信息的验证服务器,GameServer需要通过它来进行客户端的合法性验证,以及获取玩家选择 的角色数据信息。 采用这种架构的游戏,通常有以下表现。     1- 用户必须激活一个大区,才能在大区内登陆自己的帐号。     2- 用户启动客户端的时候,弹出一个登陆器,选择大区。     3- 用户启动真正的客户端的时候,一开始就是输入帐号密码。     4- 帐号验证完成之后,进行区内的服务器选择。     5- 服务器选择完成之后,进入角色管理。同时,角色在不同的服务器里不能共享。

    展开全文
  • 背景在中国的互联网诸多业务领域中,游戏一直是充当“现金牛”而存在的。但是,在游戏服务器端开发领域中的很多重要问题,并没有被明确的分辨出其特异性,从而得到专门的对待。我们不管是在业界开源领域,还是内部...

    背景

    在中国的互联网诸多业务领域中,游戏一直是充当“现金牛”而存在的。但是,在游戏服务器端开发领域中的很多重要问题,并没有被明确的分辨出其特异性,从而得到专门的对待。我们不管是在业界开源领域,还是内部分享中,很少会有专门针对游戏业务特征进行专门设计的组件、类库或者框架。我们从游戏的客户端方面来看,一款专业的游戏客户端引擎,已经是游戏开发的标配,比如最早的Flash Builder,到后期的Cocos2d-X,Unity,Unreal;但是服务器端,我们几乎找不到同样重量级的产品。

    游戏服务器和一般服务器的区别

      在游戏服务器端开发所有要面对的问题中,有两个是最核心和最普遍的:一是和客户端的通讯;二是游戏登录用户的数据处理。对于和客户端通讯的这个问题,大量的游戏开发者会使用“通用”的开源组件,比如Protocol Buffer,Thrift,Jetty,Node.js等等通信或RPC框架。虽然针对游戏,还是要做大量的改造,但一般都有很多现成的代码可供修改。

      在一般的互联网应用中,我们一般认为服务都是通过请求-响应的方式来完成的。而在游戏业务领域中,请求-响应可以看成是一种类型的通讯方式,但还有另外一种重要的通讯模型,就是“数据同步”方式:游戏中某个角色的HP、位置坐标改变了,需要在客户端和服务器之间、客户端和客户端之间同步。这造成了一般情况下通信协议的大量增加。

      对于第二个问题,不管是memcache还是MySQL,或者是Redis,都不能完全满足游戏开发者的需求。很多团队尝试过各种组合和修改,试图创造出利用现有开源软件,建设既能迎合灵活的需求变化,又具备低延迟和高可用的数据处理系统,但最后这些努力基本上都很难圆满成功。因此我们在游戏服务器端代码中,还是充斥着大量的内存、缓存管理,数据同步、落地等等代码。而且每个游戏都要重新去写一遍这些类似的功能,不能不说一种浪费。

      如果我们要想出一种能满足“游戏”这个业务领域的数据系统设计,那么就一定要搞清楚为什么在如此之多的开源项目和游戏团队中,没能实现完美契合的原因。

    电子商务/一般互联网业务的C-S通讯流程

      基于WebService类型的通讯模型,现在基本已经成为互联网开源组件的标准。由此而诞生的RESTful API,或者各种RPC模型,其实都是基于这样的客观事实:
    这里写图片描述

    • 用户主动请求,服务器产生回应。典型的就是网页的点击、表单的提交。

    • 主动通知的消息,仅仅是提示用户发起查询请求。比如在APP按钮上的小红点,消息页的数字提示等等,这些主动通知都是为了通知用户去刷新页面。

      游戏服务器和一般服务器对比,有何特别? ...

    游戏类业务的通信流程

      游戏中的通信,一般和操作有关。这些操作一般分为两类:

    • UI面板类操作

    • 战斗场景操作

        这两者的最大区别,就是UI面板类操作一般无需让其他玩家看见。而战斗场景操作则需要广播给所有玩家看到。

    这里写图片描述
    这里写图片描述

      在第二种情况下,一般就不是客户端主动发起,而是服务器端直接推送实际数据,然后客户端直接显示这些数据。这个模式和简单的“推送”还不一样,而应该更进一步,是一种从服务器端发起的,向客户端“同步”数据的请求。

      因此,一个好的游戏服务器端框架,应该是能同时支持请求-响应模型和“推送同步”模型的。

    电子商务/一般互联网类业务的数据处理流程

      Memcache、Redis、MySQL在一般互联网业务中的应用非常广泛。而且基本上能很好的应对各种常见的应用场景,包括类似BBS的社区、新闻门户、电子商务类系统。在企业内部信息系统中(Intranet),这一类数据软件也能发挥非常好的功效。由于电子商务类是其中最复杂的系统,所以我在这里以此为例说明,一般数据处理的流程是如何的。

    这里写图片描述

      假设我们浏览了一个网店,选中了一个商品,点击了下单这个流程,实际上需要的后台流程可能是下图所示:

      从上面的分析大概可以总结出几个特点:

      一、忍受延迟:每个操作的延迟要求较低,操作频率不会太高。一般我们页面在5秒内打开,都不会引起太多客户的抗议。所以,就算我们处理一个请求的时候,后台进行多次的进程间调用,产生的延迟和带宽消耗也是可以忍受的。

      二、在线交互少:互联网业务大多数是基于浏览器的,所以在线用户之间很少实时交互。

      三、数据分散:一般来说,互联网应用的数据可以在多个不同的业务系统中共用,但是需要专门的业务模块来做管理,以维持数据的一致性。

      四、数据变更面广:系统需要持续处理很多数据变更,互联网业务有很大一部分数据是来源于普通用户、网络编辑、店主等等使用者,在使用的过程中,他们会大量的修改系统所存储的数据。

      以上四个特点,导致了我们一般会把后台要处理的数据,分别用Cache系统和DB系统来处理。并且,我们一般会按业务功能划分模块,同时也划分业务系统。由于延迟和在线交互的需求较弱,所以使用大量进程来做模块隔离,依然是非常可行的,总体来说,就是一种比较“分散”的数据使用方式。

    游戏类业务的数据处理流程

      在各种游戏中,MMORPG是数据处理最为复杂的一类,也是最典型的一种“重服务器端”的游戏类型,因此可以作为游戏业务中通用性的参考标准。在MMORPG中,我们可以发现,数据的处理需求,和一般互联网业务大相径庭,它体现出的是一种明显的“集中”式的数据处理需求。我们可以从一般MMORPG的服务器架构中体现出来:

      在游戏业务中,一般我们都会发现以下的特点:

      一、延迟敏感:游戏中用户会产生大量操作,都要求“实时”进行反馈,所以一般都不能忍受1秒以上的延迟,在大量动作类型的游戏中,一般都会要求服务器的反馈时延在50ms左右。因此游戏开发者都习惯于尽量减少后台进程间的交互,尽管这对提高系统吞吐量很不利。所以大部分游戏服务器端都有一个所谓“GameServer”,里面运行了游戏70%以上的功能。

      二、大量实时交互:在线游戏的特点,就是很多玩家可以通过服务器“看见”彼此,能实时的互动。因此我们必须要把用户的在线数据,集中到一起,才能提供互相操作的可能;而且A用户操作B用户的数据,是最常见的数据操作,所谓战斗玩法,就是互相修改对方的数据的过程。

      三、数据集中:游戏是一个几乎完全虚拟的世界,在游戏中的数据,实际上很少能在其他系统中产生价值。而游戏逻辑也禁止通过游戏以外的方式,修改游戏的数据。所以游戏中的数据,一般都会集中存放在单独的数据库中。由于没有数据共用的需求,所以也不需要把GameServer里面集中的逻辑划分出很多单独的进程模块来。

      四、数据变更少:实际上游戏的数据变更还是很快的,比如游戏中的每次中弹,都要减少HP的数值。但是游戏里的数据,一般都遵守这样一个规则:“变化越快的数据,重要性越低”。也就是说,游戏中是可以容忍一定程度的数据不一致和不完整的。而游戏中的数据,一般会分成两类:玩家存档和游戏设置。对于玩家存档来说,其单条数据量一般不大,但会有大量的记录数,因为每个玩家都会有一个存档。但是其读取、修改,一般很典型的和玩家的登录、登出、升级等业务逻辑密切关联,所以其缓存时机是比较容易根据业务逻辑来把握的。而对于游戏设置数据来说,几乎只有升级游戏版本的时候才会修改,大部分运行时是只读的,其缓存简单的读入内存就解决问题了。

      一般的缓存系统的特点在游戏中的问题

      根据以上的分析,我们可以看到,普通的缓存系统,如memcache和Redis,实际上其特点是不太适合游戏业务的:

    • 一般跨进程的缓存系统,无法解决游戏要求的低延迟问题。级别是同机房,每次数据存取都需要10-20ms的时间,对于游戏战斗中大量的数据读、写来说,是很难接受的。(但是一些回合制战斗、低频操作还是有用的)

    • 通用型的缓存系统或者数据库,一般都比较难集结多个进程,形成一个完整的数据存储网格。这让玩家间的互相交互产生了额外的难度,开发者必须先想办法确定玩家的数据在哪个后台进程上,然后才能去读写。一般的数据库或缓存系统,为了保证数据的一致性或者完整性,往往会需要牺牲一些分布式的能力。而这种牺牲在游戏业务中,其实是一种浪费,因为游戏的很多数据都无需这种能力。

    • 通用性数据系统一般不依赖于特定的语言,所以很少能直接把某种“对象”存入到数据系统中。在游戏开发中,需要存储的数据结构数量往往是非常大量的:一个普通的游戏,基本上都会超过100种数据结构。对于每个数据结构,都去建表或者编写序列化/反序列化配置,是一种非常累人的工作。–明明在代码中,已经用编程语言定义了他们的结构,还要重复的搞一次。

        根据上面说的这些问题,我们实际上是需要另外一种完全不同设计思想的数据系统。

        对于游戏业务来说,一个好用的数据系统,应该包括这样一些特点:

    • 可以利用GameServer进程内的内存进行自动化的缓存管理。由于GameServer进程往往集中了大部分的逻辑运算,所以大部分的数据缓存也应该在这个进程中,这样才能符合游戏所需的延迟要求。

    • 自动进行数据落地和容灾管理。由于游戏数据中有大量的“过程数据”,所以其一致性和完整性要求会稍微低于其他业务,所以应该利用这一点,让GameServer本身也可以是分布式的程序,从而提高系统整体的吞吐量。

    • 具备良好的编程易用性。最好是能直接存取编程中的对象,避免反复对数据结构的描述,节省大量的开发时间。

    总结

      游戏服务器和普通互联网业务服务器端,最大的区别实际上就在于“状态”。游戏服务器的状态是实时快速变化的、可以容忍丢失的、需要大量广播同步的;普通互联网业务服务器的状态一般是持久化的、不容忍丢失的、只和特定客户端相关的。所以一个好的游戏服务器框架,在通讯和数据这两个基本层面,会和一般我们所接触的开源组件有很大的差异。这也是作为游戏服务器端开发者,需要去共同建设行业标准的地方。

    展开全文
  • Java游戏服务器搭建

    千次阅读 2019-03-19 20:26:03
    游戏服务器架构是一个单服的形式,也就是说所有游戏逻辑在一个工程里,没有区分登陆服务器、战斗服务器、世界服务器等。此架构已成功应用在了多款页游服务器 。在此框架中没有实现相关业务逻辑,只有简单的测试用...
  • 游戏服务器是干什么的(大话、浅析)

    千次阅读 多人点赞 2019-06-22 22:38:00
    在做游戏服务器开发之前之前一直有疑问,服务器是干什么的?问了几位前辈,得到的答案大概都是:服务器就是一台电脑,你可以访问,然后做一些事情(我现在觉得这个答案是很精辟的)。这个答案对于之前的我来说,由于...
  • 游戏服务器开发(基本需求)

    千次阅读 2019-04-04 17:12:39
    基本上不管做什么开发,都是一个团队来完成的,游戏也是如此,游戏团队一般由老板,总经理,CTO(技术主管),主策划(领导一些人,包括数值策划,系统策划,特效策划),主美(领导一些人,包括原画,UI设计,特效动作...
  • 游戏服务器开源框架(xinyue-game-frame)

    千次阅读 2020-03-24 08:56:02
    今天给大家介绍一个开源的游戏框架,它是基于Spring Cloud + Netty实现的一个分布式游戏服务器框架,支持负载均衡,集群部署,动态扩展和伸缩,能基本满足休闲游,卡牌游戏,SLG游戏的服务器框架快速搭建。...
  • 开源游戏服务器你中意哪款?

    千次阅读 2019-10-22 12:52:26
    有哪些开源游戏服务器框架,值得学习呢。基于node.js 、java、C#、golang 、c++、python 等技术栈有各种各样的游戏框架。 本文收集一些比较常用的 github上star和fork有一定数量的较为完整的框架 skynet 云风大神的...
  • 10.9k 作者为网易 Skynet c lua 消息处理框架 9.1k 作者为网易云风 KBEngine c++ Python 适合大型 MMO 4k leaf go 游戏框架 3.6k mqant go 分布式微服务框架 1.9k goworld go 分布式 1.5k cellnet go 分布式 3.2k ...
  • 深度解析Java游戏服务器开发

    千次阅读 2018-09-03 20:18:00
    ---恢复内容开始--- 1.认识游戏 ... RPG角色扮演游戏、ACT动作游戏、AVG冒险游戏、FPS第一人称视角射击游戏、TPS第三人称视角射击游戏、FTG格斗游戏、SPT体育游戏、RAC竞速游戏、RTS即时战略游戏、STG...
  • 学习游戏服务器编程基础篇

    千次阅读 多人点赞 2017-01-22 20:52:30
    笔者介绍:姜雪伟,IT... 前段时间,一直给开发者灌输学习3D游戏引擎技术,包括游戏底层数据结构封装,算法与游戏实战技术分享课程,以及编写了一些使用算法解决游戏实际问题等等方面的文章。在给读者介绍3D游戏引擎
  • 游戏服务器的常用架构

    万次阅读 多人点赞 2017-11-24 19:12:38
    游戏服务器,是一个会长期运行程序,并且它还要服务于多个不定时,不定点的网络请求。所以这类服务的特点是要特别关注稳定性和性能。这类程序如果需要多个协作来提高承载能力,则还要关注部署和扩容的便利性;同时,...
  • 高性能分布式游戏服务器框架

    万次阅读 2017-05-21 22:39:46
    目前网上优秀的开源游戏服务器框架也不少(当然与web框架比起来就少太多了),但总结起来都各有各的优缺点,下面列出我在选型过程中的一些考量,希望大家能开放的讨论,有不恰当的地方也请指正。 首先是开发语言 目前...
  • Java游戏服务器成长之路——2016随笔总结

    万次阅读 多人点赞 2017-02-09 15:01:05
    写在开头Java游戏服务器成长之路的系列,已经很长时间没写了,不是不想写,而是这一年,基本都是在忙别的了,今天特地挤出时间,对我的2016年,做一个不留遗憾的总结。2016的事件不知不觉,又到了春节抢票的时候了,...
  • Win11微软商店更新“游戏服务”时提示“我们这边出了错” 解决方法 删除 C:\Program Files\WindowsApps 下面所有关于 Gaming Services 文件夹(由于权限问题删不掉,可能需要进入pe删除) Win+R 输入 regedit 删除...
  • 开源游戏服务器框架汇总

    千次阅读 2019-11-11 17:01:15
    有哪些开源游戏服务器框架,值得学习呢。基于node.js 、java、C#、golang 、c++、python 等技术栈有各种各样的游戏框架。 本文收集一些比较常用的 github上star和fork有一定数量的较为完整的框架 skynet 云风大神的...
  • 游戏服务器框架pomelo基础详解

    千次阅读 2018-10-26 10:23:59
    pomelo是一个游戏服务器框架,与以往单进程的游戏框架不同, 它是高性能、高可伸缩、分布式多进程的游戏服务器框架,并且使用很简单。它包括基础开发框架和一系列相关工具和库,可以帮助开发者省去游戏开发中枯燥的...
  • 大型多人在线游戏服务器架构设计

    万次阅读 多人点赞 2016-09-24 20:37:54
    由于大型多人在线游戏服务器理论上需要支持无限多的玩家,所以对服务器端是一个非常大的...一款游戏服务器的架构都是慢慢从小变大的,不可能一下子就上来一个完善的服务器构架,目前流行的说法是游戏先上线,再...
  • 作为一名业内资深的游戏开发人员,经常会遇到实习的新同事在工作中会问到这样的问题: 工作中到底有哪些开源游戏服务器框架,该去值得学习呢? 囊括到node.js 、java、C#、golang 、c++、python 等技术栈有各种各样...
  • Matchvs作为国内首款落地的商业化游戏服务器引擎,本文将以它的GameServer”的自定义服务端框架作为例子进行分享。 与skynet等游戏服务器开源框架不同,作为一款商业版的游戏服务器引擎,由于Matchvs本质上是将一...
  • 游戏服务器架构发展史

    千次阅读 2016-07-15 13:40:55
    手游页游和端游,本质上没有区别,区别的是游戏类型:  类型1:卡牌,跑酷等弱交互服务端  卡牌跑酷类因为交互弱,玩家和玩家之间不需要实时面对面PK,打一下对方的离线数据,计算下排行榜,买卖下道具即可,...
  • 我是如何设计游戏服务器架构的

    千次阅读 2017-07-30 10:34:53
     现在游戏市场分为,pc端,移动端,浏览器端,而已移动端和浏览器端最为接近。都是短平快的特殊模式,不断的开服,合服,换皮。如此滚雪球! 那么在游戏服务器架构的设计方面肯定是以简单,快捷,节约成本来设计的...
  • 在分布式系统领域,支持在线弹性扩展,实时多人专属游戏服务器意味着特殊的挑战。随着游戏专业人士创造的各种特殊方案,Kubernetes被整合成跨云和物理机,支持复杂工作流的开源分布式标准。今天,我们很高兴发布开源...
  • MMO游戏服务器从零开发(架构篇)

    万次阅读 多人点赞 2018-08-08 16:39:33
    MMO游戏服务器属于大型多人在线游戏服务器,负载,稳定,效率(包括反馈延迟和开发效率)是这种服务器基本要求。 本人从10年入行至今一直从事MMO游戏的研发和架构设计工作,对此类服务器有一些理解和见解。下面分享...
  • &nbsp; 发现一款好的免费开源游戏服务器引擎scut,网址...可下载SDK版本即可用于游戏服务器开发任务,也可下载源码版研究,更改相应代码。以下是官网的基本介绍: &nbsp; &nbsp; &nbsp;...
  •  游戏服务器装载着游戏对外服务,对于房间类游戏其功能包括房间的创建、进入房间、离开房间、开始游戏、结束游戏。由于不同游戏对应的逻辑不通,如果需要代码共用,则可将房间的操作分离出来做成一个共用库。只有...
  • 网络游戏服务器构架设计

    千次阅读 2015-05-27 16:44:16
    网络游戏服务器构架设计(一):前言 这篇blog题目涉及的范围真大!以至于在这里需要先写一篇前言把范围缩小。选择写这样一个系列的文章,主要是想给工作了两年的自己一个交代,或者说是一个阶段性的总结。两...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 355,970
精华内容 142,388
关键字:

游戏服务