如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com
本文整理自APMCon 2016中国应用性能管理大会HTML5调优最佳实践专场 HTML5技术专家 魏子钧题为《Lie to Me-聊聊HTML5多人实时在线游戏的优化》的演讲,重点讲解『基于HTML5技术的多人实时在线游戏』的研发过程中学习和整理的一些关于相关的优化知识,包括:多人实时在线游戏的基本工作原理。
魏子钧:大家好,我先做个自我介绍,我叫魏子钧,目前属于自由职业者,所以我也非常感谢这次大会邀请。我属于国内比较早的折腾HTML5的那群人,很遗憾到现在也没折腾出来什么东西,但是我自认为在技术方面还是比较多的积累的。
我这次标题比较奇怪,因为今天讲的东西严格上来讲并不算是优化。我们先说一个最近比较火的游戏——《守望先锋》,除了这个游戏过去可能大家玩过很多网游,大家即使不开发游戏,在玩游戏的过程当中心里肯定也有很多的关于游戏的疑问和好奇之处,我今天的分享也算是跟大家简单来聊一聊网络游戏背后的一些故事。
我们先来看看常见的HTML5游戏,包括迷你小游戏、益智类休闲游戏、社交游戏、挂机、挂机+X,X代表一个未知元素。HTML5游戏发展的也是有几年了,虽然发展得比较尴尬,但是还有很多人一直尝试着想在HTML5游戏领域内做出一些不太一样的东西,而这其中实时在线对战游戏成为了很多人研究的方向,我个人也是在一年前左右开始在这方面作一些简单的研究。
我们之所以把实时对战游戏和HTML5联系起来,也离不开HTML5在这些年的发展,首先大家知道wifi、4G的全面普及,以及WebSocket、HTML5转化高等原因。还有最后一点,iogame在国外蛮火的,也衍生出了蛮多的iogame游戏,大家也有玩过,这些都是实时对战的游戏。所以说HTML5游戏从技术上已经是具备了,而且还有一些不错的小产品出来,这奠定了我个人在这方面研究和投入的决心。
其实这些游戏都有一些共同的特性,首先都需要联网,另外就是控制单体,在游戏里面偏动作项,位置比较敏感,注重操作,还有数据包小,带宽要求低。联网游戏有很多种,我写的这些共性,主要是今天要讲的是围绕这些特性游戏展开的,比如斗地主也开始自主实时对战了,但是它们不在我今天讨论的范围内,我今天讨论的比较偏向于动作项的游戏。
一、原理
讲优化的时候还要说一下原理的,不管实时多人练级游戏多复杂,其实它的本质跟多人聊天是一样的,无非就是做了这四件事情:客户端输入、服务端处理、服务端广播、客户端输出,而游戏跟聊天室之间主要的差别无非就是服务端处理和客户端输出部分更复杂一些。
上图左边是一个客户端在不断地向游戏服务端发送自己输入数据,服务端处理一下,再把数据不断返回给客户端,不管什么游戏无非都是这样一个原理,多人游戏就是一个Server多个客户端,如下图。
二、优化
1.底层优化
接下来再说优化的东西,主要是考虑一般从底层优化。其实底层和HTML5两点结合起来也是蛮尴尬的,比如协议这一层,我们不管是用一些自定义的协议还是其他协议,这些协议其实有很多修改版本或者优化版本,但是在HTML5里面我们其实比较尴尬,因为我们不能做太多底层的东西,我们唯一选用的就是WebSocket,但是大家认为还有WebRTC,但是它的UDP不是完全一致,而且系统也不像UDP那么高,所以现阶段用WebRTC来做游戏是得不偿失的,所以就老老实实的用WebSocket然后做TCP这种协议。TCP协议做网游也不是不可以,比如鼎鼎大名的魔兽世界,因为确实用TCP协议会更省心一些。
上图我们看到,我们还需要在服务端把Nagle算法关闭掉,现在至少两个主流浏览器已经默认把Nagle算法关掉了,这个算法其实是用来减低网络传输的频率,比如客户端数据要上传服务端,它不会马上传,它会涨到最大才传,但是这种情况实际对于我们所要讨论的游戏来讲是没有什么意义的,因为这个游戏有一个特点就是数据包非常小,我们每个数据包都很小,它每一个数据就不会及时的传给数据端,好在浏览器默认都已经把它关掉了,我们要注意的无非就是在Server端把它也关掉。
2.数据层优化
底层这边优化完了下一阶段是数据层优化,同样大家能做的也不多,无非就是把我们要传的数据压缩成二进制进行传输,但是正常我们在程序当中使用还是用JSON对象或者二进制对象,这种情况下我们可以用protobuf。
我们团队里面实际在用的并没有在做protobuf,是因为它太复杂了而且太强大了,因为我们要做的数据非常简单,你想客户端输入是什么?无非是按键信息,然后再把各个东西返回,返回的无非就是状态、坐标等等,基本上就是数字,偶尔一些数字串,没有太复杂的结构,所以protobuf太复杂,我们就做了一个简单的东西,原理都是一样的。但是有一点非常重要,就是这个事情本质上它和性能无关,为什么这么说?首先我们这种网络游戏不管多复杂,但它数据传输量真的非常小,每秒大概就几K,所以说压成二进制这个事情其实并不会说让你原来带宽不够。
还有一点大家注意一下,就是把js对象转换成二进制也是要耗时间和CPU系统的,所以说做二进制这一层主要目的并不是为了性能,更多的其实是为了服务端的带宽,再说白一点其实是为了省钱,因为同样的数据平均测下来压成二进制传输的数据量是很少的。
3.“骗术”
其实数据层这边也说差不多了,真正分享的核心就是逻辑层的优化。逻辑层的优化并不能算是一个真正的优化,可以这样想,性能优化的本质是什么?其实是优化用户的体验,当然你愿意挑战自我,觉得优化好了比较爽那另当别论,对于大多数的应用项目来说,性能优化的目的是为了优化用户体验。但是用户体验优化当中总有一些东西是你事优化不掉的,这时候我们通常做的办法就是“欺骗”。落实到网游这个事情上也是同样的道理,我们要做的事情并不是优化而是欺骗,努力的骗用户,让用户觉得我这边网很牛,这个游戏玩的很流畅。
回过头来说为什么要欺骗用户?因为影响网络游戏体验的很重要的因素首先是带宽,然后是ping值还有丢包,程序员或者游戏开发商无论如何都解决不了这三个问题,而这三个问题直接导致了后面更严重的问题。这三个因素是我们无法解决的,导致了无论你用什么方法去优化总是优化不掉,那就要用到“欺骗”了。
具体有哪些欺骗用户的方法?无非就是上图这么几种,一是客户端自动适配的插值延迟,二是消除位移波动,三是客户端预测,四是及时响应,五是降低服务端推送频率,这个一会儿再讲,六是服务器不再权威。因为在传统理念当中一切事情是服务器说了算,否则万一作弊了呢?但是你如果真的较真总是咬定一切事情都要服务器说了算,服务器告诉我了才做,那么这个游戏基本上没法儿玩了。所以我们实际开发网游的时候,基本上都会在某些情况下放弃掉服务器权威性。
这几个概念其实非常笼统,我给大家通过DEMO来演示一下这几个东西到底是什么意思。我这边有一个简单的小DEMO,大家可以先看一下,非常简单。我用GSD控制这个蓝块来移动,大家看着很简单,但是它其实已经用到了刚才提到的网络模型,比如我现在做的每一个事情,按左它往左移动并不是客户端往左移动,而是告诉服务器,服务器计算完了再返还给我,我再更新。大家看左上角的ping值,如果说ping值不稳定这个蓝块一跳一跳的感觉会更加明显。
这个时候我们要启动一个常见的方法就是客户端延迟,这个事情怎么做?看到一出来的白块,在这个游戏当中其实玩家看不到那个蓝块,比如我们在游戏当中看到那个游戏的角色其实后面那个白色的幽灵是假的,大家这么一对比就能看出来,蓝块在一跳一跳很不均匀的往前走,但是这个白色用动态差值其实相当于总是比蓝块慢那么几十毫秒,这几十毫秒导致的结果是什么?可能这个位置不准确,但是至少从玩家来说是能够感觉蛮流畅的,网也不卡,所以这就是我刚才前面提到的第一条,就是自动适配的插值延迟,通常有这个已经能够解决大部分的问题了。用延迟主要带来的一个明显的问题是什么?就是真正操作你们感觉不到,我按左的时候它并没有马上动,就是蓝块的先动,白块过一会儿才走后面一直跟着,蓝块的抖动白块并不会马上跟着去抖动,这是一种常见的方式。
第二个更复杂一些,客户端预测。这个红块的其实就是预测的一个位置,这个白块仍然是采用追随的策略,只是它追的不是那个蓝块,而是追的预测那个块,这就是我按左它不会马上动,而是过几十毫秒再动。我程序上已经让白块延迟100多秒,ping值再很低加一起就二百多毫秒,所以在这种情况下这种预测就非常重要,降低服务端推送频率一会儿再跟大家讲,这个相对复杂一些。
用了这种方式之后大家觉得白块体验非常好,把这个真实位置和预测位置去掉,大家只看白块,这个白块就感觉很流畅了,这时候我们再开启一个新的窗口大家看一下这里面产生了一个新的问题,我先把网络打开,这个工具不知道大家用过没有,用来强制延迟一下带宽的,我把ping值调低一些。
其实当我把跟踪插值追随打开,再把预测打开之后,大家就能感觉出来在两个人的屏幕上,这个2到达边缘的时间其实是不一样的,如果网络环境再差一些,再有一些波动的话就感觉更明显了。这是我刚才提到的放弃了一致性,两边同一时刻两边看到的东西应该允许它不一样,允许这种差异存在,如果说把这些东西关掉只看真实的,你会觉得这个差异更大。
再说一下降低服务端推测频率是什么意思?我们回想一下上面那张图,客户端比如每秒30次的推数据,然后服务端也每秒30次推,但是推之后频率就没有必要这么高,因为两帧差距非常少。
这里面再做一个例子,上面一个逻辑处理频率是每32毫秒处理一次,我把这个改成64号毫秒发生一次,如果说不开预测,蓝块就没办法使用低频率的发出数据,但是要是开了预测的话,白块是会相对流畅一些,但是肯定永远不如客户端本真服务率发生的流畅。所以说当客户端开启了预测之后,服务端就可以不用那么较真的每一帧都把数据告诉客户端。
下面就又衍生出一个新的问题,我们允许在两个人屏幕上看到的东西不一样,在一些游戏里面就会在逻辑判断上产生差异,比如说射击,如上图屏幕上开一枪打到上面的牛仔,但在牛仔那个屏幕上看,这个骑士是没有打到我的,这种情况下服务器怎么处理?逻辑还是一样,还是骗,这个骗怎么理解?首先在骑士的屏幕上这种情况下我会处理牛仔被打的浑身冒血,在牛仔在这边我很安全,什么事都没有。最终这个牛仔费没费血,由服务器来做一个判断。从骑士的角度来讲他会产生疑惑,这个人我打他怎么还不死?但是对于正常玩家来说不会想太复杂,一般你会觉得是不是网卡,或者是不是没有打中要害,总之在一个快节奏的竞技类游戏当中,玩家在一瞬间可能有很多想法,但是这些想法都不会在在意。
因为我玩游戏比较多,你打对方十枪对方没有死,你只会觉得枪法不准,没有爆头,没有打中要害,上子弹再重新打一拨。所以在这种情况下我们骗用户远远要好过卡在那个地方,打一枪半秒后才告诉你打没打中,所以这种欺骗在很多时候是用户体验的优化。
我们再看一个例子,就是目前最火的《守望先锋》。在游戏里一个角色开一枪过了大概100毫秒左右对面才打到,这种延迟是无法避免的,但是我们来看《守望先锋》的处理方式,一个人物往左边跑,其实从他的角度来说已经躲开了,但是从另外一个角色的角度来看打它它还是浑身喷血,这就是我说的欺骗行为。跑的角色感觉不到自己被打,他觉得很安全,这样的话他俩都很爽,一个觉得我灵活的躲开了,另外一个觉得我打中了。
但是这时候服务器判断之后觉得你还是被打着了,就给你减血,但这个时候也不会觉得很别扭,就觉得还是被他扫到一点,其实很早之前我们玩CS很多时候有些枪会穿墙,因为那时候大家不专业,觉得枪威力大,有一定概率穿墙,但是墙确实逻辑上穿不了,我们通常见到穿墙都是类似这种情况,你觉得你躲开了,其实服务器判断还是一丝一毫没有躲开。说了这么多就是这个道理,就是两边骗,服务器过一会儿做一个判断。
说到最后其实所有的网络游戏无非就处理一件事情,就是把你眼中的你,服务器眼中的你,还有别人眼中的你,这三个尽量让它一致,但是有时候我们由于能力或者是网络等等原因它不能一致,在这种情况下我们要做的就是进可能的自然,总是用一些障眼法让一些变得很自然,很顺滑,这几乎是所有游戏的不二法则,几乎是一个终极目标。
而至于大家刚刚提到的当你服务端说的不算的时候,客户端外挂作弊情况下怎么办?这个问题其实你可以理解为为什么像《守望先锋》那么牛的游戏外挂仍然生成的原因,这个事情是无解的,作弊这件事情就是说我不能阻止你作弊,但是我一定要做到发现你作弊,一般采用监控或监测来发现你作弊。最终的结果就是说我允许你作弊,但是我要抓到你。
再回到今天的演讲题目,说这么多大家能明白为什么这个题目叫对我说谎了,这属于善意的谎言,玩家会很高兴。而且还有一点我今天讲的这些东西这不是我自己发明的,都是经过了十几年不断地沉淀和积累下来的东西,新的《守望先锋》也好,还是十几年前的CS也好都是差不多的,做法都是一样的,而且现在聊的东西其实不限于HTML5。
最后感谢一下V社,因为你看到HTML5这些大量的文章都是源于这个公司的贡献,这是非常了不起的DOTA1、DOTA2、CS的开发商,他们公司有一个开发者网站,这个网站上面有大量的东西,可以看到这公司在这方面的沉淀和积累真的非常雄厚,而且是非常开放的会把自己一些技术的东西分享出来,所以大家有空的时候可以更多的去这边研究一下,网上其它的资料也有,这就是我今天的分享,就到这里,谢谢大家!
Q&A
Q1:小胖你好,我想问一个关于游戏的问题,因为我刚才听您说了这么多,好像现在HTML5游戏都不做像真同步、追真之类的这种,因为你刚才分享的内容看来,好像如果说要做到完全一致同步的话会和你刚才说的“欺骗”会有一些冲突,为什么不考虑一下同步这些?
魏子钧:其实刚才讲的东西就是一个状态同步,也并没有说用到那些东西,但是只是追真这个东西确实是我刚才讲的是没有用到,但是《守望先锋》其实是用到了,它的服务端会缓存到过去很多的一些信息,昨天田博辉老师分享的他现在也会用到真同步,状态同步的,所以你具体上用哪个技术还是取决于你的游戏对偏差的容忍度。
我之前玩过一个游戏有一个很诡异的设计,就是两个人在不同位置同时打一个塔,但是在另外一个人的屏幕上他俩都在左边,因为两个人打一个塔,这件事情达成事实,而基于这两个人站在哪个位置他不关心,不重要,那么这个游戏不那么追求真同步,状态同步。但是像我今天分享的游戏,它对位置、移动、速度、坐标这些东西还是比较敏感的,虽然可以允许差异,但是并不是说可以放任各种速移,所以在这种情况下还是要用到传统的那种技术。目前没有什么人说下铁律说这个技术就不用了。包括有些像《王者荣耀》什么的,它用的还是真同步,因为它不允许中途有人观战等等,所以这个事情我觉得不能一概而论,更多的大家可以私下交流。
Q2:你好,我对刚才你讲的WebSocket特别感兴趣,我想问一下WebSocket都用在什么场景下?像推送或者是聊天那种东西,能不能说一下WebSocket?
魏子钧:首先我觉得WebSocket这个资料已经不要太多了,因为我一直折腾HTML5游戏,我主要用它就是用在游戏这边,像你刚才说的聊天、排行榜那些实时的东西都可以用到WebSocket,你这个问题我觉得首先比较抽象,而且比较大,你说WebSocket怎么用或者有什么应用,这个东西单独讲能讲个40分钟,所以我觉得你上百度看一看,但是你刚才说的两点很对,就是对推送、聊天,对实时性的要求都很高的。
关于APMCon:
2016中国应用性能管理大会(简称APMCon 2016)于8月18日至19日在北京新云南皇冠假日酒店隆重召开。APMCon由听云、极客邦和InfoQ联合主办的作为国内APM领域最具影响力的技术大会,首次举办的APMCon以“驱动应用架构优化与创新”为主题,聚焦当前最为热门的移动端、Web端和Server端的性能监控和管理技术,整个会议设置包含了:性能可视化、服务端监控实践、运维自动化、数据库性能优化、APM云服务架构和HTML5调优最佳实践等话题,致力于推动APM在国内的成长与发展。