[导读]腾讯游戏讯,7月30日消息,第九届中国游戏商务大会网页游戏论坛30日在上海浦东嘉里大酒店展进行相关主题论坛活动。
30日,在上海chinajoy嘉里酒店进行了游戏开发者大会,腾讯游戏的研发部助力总经理聂志明进行了演讲。
他为大家演讲的题目是“游戏后台开发中的九个选择”,他解释,使用这个标题的原因,是因为我们在生活中总会遇到很多选择,这个道理同样适用在游戏开发中。
这九个选择分别是:
第一,选择什么样的架构。
第二,选择单线程还是多线程。
第三,如何在游戏中使用脚本。
第四,如何处理网络通讯。
第五,如何处理游戏通信协议。
第六,如何设计存储结构。
第七,如何设计网络同步。
第八,如何定义性能基准。
第九,如何在不同项目间进行代码复用。
聂志明先生在他的PPT里详细地为大家讲解了这九个问题,具体情况请参看演讲实录。
以下是演讲实录:
聂志明:大家好!我们现在开始演讲,我先自我介绍,我是腾讯游戏研发部助理总经理。我今天的题目是“游戏后台开发中的九个选择”,为什么用这个题目?在生活中我们有很多选择,对这些选择的不同处理方式会决定不同的品质,我们在游戏开发里面会遇到很多选择,我今天说九个,但不一定每个人都碰得到,我在这里会把一些经验给大家分享一下。
首先介绍一下在腾讯开发跟别的公司会有不同,在我内部遵从两个岗位,每个公司里面是按照不同模块来分。为什么会这样分?前台是通过便,后台讲究的是不便,我们不是追求新的技术,而是解决问题。
下面我开始演讲,这是北京最盛名的一座桥,每次都不知道怎么走,越来越复杂。我们每天都会遇到很多选择,所以导致人也不是很愉快。
我现在来讲九个选择,从Q1到Q9,后面一一按照这个顺序做个阐述。
第一,选择什么样的架构?
其实是SNS特点决定的,不同的特点决定不同的架构。玩发围绕的是玩家之间偏真实的关系链,位置对玩家是不重要的,玩家之间没有物理上的距离概念,SNSGame是大世界的模式,通用大世界方案的系统必须平行发展。MMO的特点,前几年是一个发展重点,很多人了解也不是很多,它的特点是存在世界地图,位置很重要,有地形概念,每个玩家都有自己的物理坐标。交互频繁,逻辑复杂,交互的实时性要求高,严重依赖于预先设计的游戏内容。小世界有小世界的好处。第一易于就近部署及,减轻国内网络复杂与MMO对网络要求高的矛盾。大家知道网络有很多问题,大家知道问题也解决不了。对MMO来讲,是一个很高的类型,所以会用小世界。
通过分区服务,降低了因为架构导致的运营问题的严重性,小世界的内部在架构上也需要有一定的可伸缩性,这取决于游戏的设计。并不是所有的小世界只有一台服务器搞定,因为它的元素、它的特点对它也会有不同的要求。
在我选择这种架构的时候,我们会有原则,选择什么样的架构取决于游戏自身的设计,这取决于某些特点,并不是所有服务都有同样的需求,并不是大世界就好,小世界就不行。我们不从纯技术角度追求大世界的架构,大世界需要游戏内容的支持,通常美术策划无法支撑百万在线的世界,这是最根本的原因。大世界在架构上有困难,但这是部分不可克服的。
我讲大家非常熟悉的一个例子,通常最复杂的大区概念,大区通常是做帐号,服务器在服务器里面按角色区分。线,就是有的游戏有,有的游戏没有,在这些线里面只是为了扩展这个世界的流量上线,线目前来说只是一个方便,这是一个样对复杂的示意部署视图(PPT)。
我们看一个架构,如果展开来讲,左边是一些辅助服务,右边的Worldsvr像公会的那种会放在这个里面,加在服务器上面,不同的游戏会有不同的处理。这是一个简单的示意图,在不同的游戏里面会有不同的区分。
第二,选择单线程还是多线程?
不同的公司会有不同的做法,这个问题并不是所有人都碰到,也有个概率,但是大家也会有争论。争论的原因,通常是双方关注的重点不同,单线程程序的执行只有一条主线,容易跟踪、调试和定位。我们腾讯也不是一定说要这样选择,我们理由非常理由,单线程加异步模式可以提供更好的性能,我们会选择单线程模式。现在我们游戏开发周期很长,在漫长的运行周期里面每周都会更新,交接过程中会有问题的,使用多线程容易导致问题。这个时候我们会进行一些处理,我们对里面的要求角度来看,运行的周期很长、节奏很快,为了达到要求我们可以想更简便的方式。
新形势,对我们也是有一些影响,现在有一些四核以上的CPU出现,这个时候我们会尝试把一些通用的服务,把相对固定的进程变成简单化,这是一个新趋势。
这是适应新趋势的原则,只在必须的时候才使用多多线程,如果使用了多线程,尽量减少线程间的交互需求,这样我们就好把握。
第三,如何在游戏中使用脚本?
在游戏开发中通常大家都会使用一些脚本。客户端对脚本的需求非常明显,这里主要讨论服务器端。两种使用脚本的方式:一种是C/C++的框架,主要逻辑用C/++编写,脚本用来做一些局部扩展。C/C++的框架,主要逻辑用脚本来编写,耗性能的地方用C/C++决定的。
使用脚本的原则,脚本是一种胶水语言,通常用来隔离变化,易变化的逻辑用脚本实现,快速响应。一般情况下是说这个性能高,那个性能低,上面两种方法没有对错之分,取决于两点,开发团队成员的能力,对不同语言的掌握程度;公司或者项目组的导向,偏重性能还是偏重开发速度,如果是创业型的团队,对性能方面要求多一些,怎么样把游戏做好才是最重要的。
第四,如何处理网络通讯?
其实网络通信本身是非常复杂的事情,目前的开发环境已经提供了相对来讲简单得多的编程接口,但是网络程序还是需要处理很多的问题。
两种处理方式:一种是跟游戏服务器耦合带一起,游戏服务器既处理问落接入相关的逻辑,也处理游戏逻辑。一种是把网络通信部分剥离住来,向游戏服务器提供一种以消息为单位的、非阻塞的、有Qos能力的中间服务,游戏服务器看不到网络的细节。
我们选择第二种好处,是基于这样的考虑,首先简化了游戏服务器的处理逻辑,降低了编程的难度。更易于提升后台整体的处理性能,不同部分可以独立的优化,因为它可以不断的优化和在不同项目里面去继承的。
这是非常简单的一张示意图,我们会有一个界面,在客户端和服务器端给它不同的接口,会有不同的形式,看不到网络的问题,而且都是非阻塞的形式,面向消息的服务,类似于有保障的、可持续的服务。
第五,如何处理游戏通信协议?
协议分两大类:文本协议和二进制协议,这是两个非常典型的例子,左边是UDP,非常高兴。右边是文本的协议,都是文字。文本协议直观,版本兼容性好,但是效率低。其实对于游戏来讲,我们最好能够做到不同的版本都可以玩,不强调所有的客户端都去升级,这对运营商有非常强的周期,这对运营商来说有很大的挑战。版本兼容性问题其实是我们在通信协议的时候,都需要重点考虑的。二进制协议效率高,但是不直观,版本兼容性处理相对复杂。
Web相关的游戏根据与浏览器交互的方式可能采用文本协议,基于效率原因,C/S类型的游戏通常采用二进制协议。
下面我会介绍腾讯的经验,游戏服务器是时钟消息和网络消息驱动的,大部分代码都是接受消息,或者接纳,其实有很多的解码、编码、代码占了相当大的比例。我们可以把协议做一个区分,就变成一个消息的协议描述,然后生成工具,然后得到网络协议处理代码。
这是我们的做法,我们自己定义了一套协议描述方法,并实现了相应了工具集。我们这个协议重点会有所不同,在于高性能、与C/C++的无缝结合以及多协议版本共存能力。利用我们这个版本来描述协议,不断在上面添加新的内容,但是其实可以进入到所有的低版本的客户端协议,不需要开发者做任何处理,它会自动生成。类似的方式大家可以看Google protobuf orFacebook thrift。
第六,如何设计存储结构。
从游戏来讲,所有的在线游戏通常使用数据库来存储用户数据。通常MMO使用关系型数据库来存储数据,后面主要针对MMO进行存储方式的讨论。会有两种方式:一种是把游戏的每一个数据对象的属性看成一个单独字段,遵循RDBMS的要求来设计数据库表和索引,尽量符合3NF。以MMO为例,有帐号表、角色基本信息表、物品表、装备表等等,这是一种方式。
还有一种方式更具体,角色的列表类数据尽量采用blob来存储而不是另一个表。原则是这些列表数据只被角色自身所拥有,就是这个玩家所拥有,其他玩家不会拥有个数据,它的生命周期跟玩家是一致的,不存在其他的交叉拥有情况,技能、物品、装备、任务、好友等等都属于这种情况。
优点是存储表结构简单,通常几张表就可以玩一个游戏,不超过10个。存取交互简单,角色登录或者推出时通常只需要存取一到二条记录。同一个角色的数据易于保持一致,易于多版本数据共存。我们把这些数据存到数据库的时候,会把编码存到数据库里面。所以在数据库里面做完的数据可能会不一样,不过不会影响,它会共存。
这种方式也会有缺点,数据维护工具、客服工具实现相对复杂,需要提供特殊的API来操作数据。如果手上工具是通用的,可能比以前要直白一点。某些类型的统计相对要麻烦一些,有些常用的数据,比如说角色的等级,在这方面可以用一些方式解决你的问题。
举个例子,在MMOG这块,存储角色的概要信息,包括名字、基本属性等,用于显示角色列表和防止重名。还有存储角色的详细信息,存储帐号的仓库信息,存储公会的信息。
新趋势的影响,就是Nosql数据库,性能高,存在好的开源实现,游戏的数据访问多为唯一键访问,很少复杂的Query,符合Nosql数据库的特点。后面在游戏应用上,可能也会涉及到。
第七,如何设计网络同步?
网络同步面临的主要问题:第一如何减少网络波动对同步的影响;第二如何减少外挂对同步的破坏。如果没有外挂,网络几大问题没有服务器去运行。这两个问题单独都好解决,但是在一起比较难解决。我们解决这两个问题,会遵循几个原则:第一网络条件好的玩家获得好的体验;第二网络条件差的玩家尽可能获得好一些的体验,但不能拖累其他玩家的体验;第三外挂不能在网络同步方面获得持续的好处。对外挂方面,玩一个游戏是一个人,或者说非人类不清楚,所以说外挂不能在网络同步获得持续的好处。
为了解决问题我们有一些基本方法:首先要探测玩家的网络质量;第二在玩家机器与服务器之间进行时钟同步;第三基于游戏特点,设计合理的同步机制。像竞技类的游戏,都是根据它的某些特点决定的,这是需要我们权衡考虑的。这里强调一点,在外挂获得好处,跟玩家体验时间做一个折中,你要保证外挂持续得到源源不断的好处,这样外挂就会上去。对于探测、时钟同步都需要控制好。
第八,如何定义性能基准?
做游戏开发通常不太注重事先对于性能的规划,多以结果作为目标,基本上是看后来测试出来的性能,能优化则优化。性能基准包括客户端和服务器,客户端的性能基准与游戏的目标市场有关。在服务器当中我们可以分析出来服务器能支撑多少用户?我们分解一下,制约性能的因素,网络IO/磁盘IO/内存/CPU。
具体的方法,可以通过经验的方式,或者计算的方式来确确定理论上限。网络IO,可以分析,取悦于由游戏类型、游戏设计所形成的业务模型,可估算。内存,相对来讲更简单,取决于用到的主要数据结构,相对来讲更聚焦,更能估算出来支撑多少人。CPU计算能力,其实也不是计算,需要更多对CPU的支撑,简单的方式,这个游戏取决于游戏类型导致的逻辑复杂性。推过这三点,可以有一个目标,大概需要多少人。
我们的数据,以实时列MMOG来讲,单一物理服务器1CPU,2核心,支撑3000-4000在线。平均每用户流量12-20Kbps。
第九,如何在不同项目间进行代码复用?
当一个公司内在不止一个项目在开发、运营时,复用的想法的产生是自然而然的。简单的把上一个心目的可用代码拷贝过来自行维护是最简单的方式,但是会导致同一个功能有N种实现变体,每个变体都解决一部分问题。把共用的代码收归一个杜立德组织来开发和维护,形成公共组件,能够解决上述的问题,但是又会带来新的问题。要解决这些问题,也很难有一些具体的方法,有几个原则,以服务、进程、库来提供。提供充分的工具,满足调试、验证、部署、运营等需求,如果推广好对你有很大的关系。最后还有充分的提供扩展能力,可以降低组件开发的压力。
我这边就讲到这里,九个问题,并不一定所有问题都会碰到,但希望这些问题对大家有所帮助。谢谢!