晃儿和慕寒为什么散了在玩什么游戏,,在那个服务器,,叫...

当前位置 & &
& 网络游戏的服务器维护都是在做些什么?
网络游戏的服务器维护都是在做些什么?
17:20:13&&出处:&&
编辑:随心 &&)
让小伙伴们也看看:
阅读更多:
好文共享:
文章观点支持
当前平均分:0(0 次打分)
[01-14][01-13][01-05][12-30][12-23][12-18][12-18][12-15][12-09][12-04]
登录驱动之家
没有帐号?
用合作网站帐户直接登录中国领先的IT技术网站
51CTO旗下网站
游戏服务器:到底使用UDP还是TCP
一般来说你会听到人们这样说:“除非你正在写一个动作类游戏,否则你就用TCP吧” 或者是 “你能够在MMO游戏中用TCP,因为魔兽世界就用的TCP!”
作者:菜鸟浮出水 编译来源:伯乐在线| 09:51
在编写网络游戏的时候,到底使用UDP还是TCP的问题迟早都要面对。
一般来说你会听到人们这样说:&除非你正在写一个动作类游戏,否则你就用TCP吧& 或者是 &你能够在MMO游戏中用TCP,因为魔兽世界就用的TCP!&
遗憾的是,这些观点都没有反映这个问题的复杂性。
首先,说明一下,我之前主要是用TCP进行网络编程。我曾为一个流行的在线纸牌游戏编写服务器了好几年,在高峰期我们的每台服务器能够承受个连接(同一台物理机器上有多个服务器进程在跑)都没有问题。在我来看,TCP是一种安全而且常见的选择。
尽管如此,我们最新的项目却是使用UDP协议,而且我们的项目无法通过任何方式在TCP下工作。事实上,项目一开始使用的TCP,但是后来发现我们使用TCP无法达到我们需求的连接数量时,我们只能换成UDP了。
在使用中TCP表现怎么样呢
从原理上,TCP的优势有:
简单直接的长连接
可靠的信息传输
数据包的大小没有限制
任何一个和TCP打过交道的人都知道,要实现一个稳定的TCP网络连接,需要处理各种隐藏的坑,比如断线检测、慢速客户端响应阻塞数据包,对开放连接的各种dos攻击,阻塞和非阻塞IO模型等等。
除了上面列出的这些问题外,一个好的TCP模块确实不好编码实现。
但是,TCP最糟糕的特性是它对阻塞的控制。一般来说,TCP假定丢包是由于网络带宽不够造成的,所以发生这种情况的时候,TCP就会减少发包速度。
在3G或WiFi下,一个数据包丢失了,你希望的是立马重发这个数据包,然而TCP的阻塞机制却完全是采用相反的方式来处理!
而且没有任何办法能够绕过这个机制,因为这是TCP协议构建的基础。这就是为什么在3G或者WiFi环境下,ping值能够上升到1000多毫秒的原因。
为什么不用UDP
UDP相对TCP来说既简单又困难。
举个例子来说,UDP是基于数据包构建,这意味着在某些方面需要你完全颠覆在TCP下的观念。UDP只使用一个socket进行通信,不像TCP需要为每一个客户端建立一个socket连接。这些都是UDP非常不错的地方。
但是,大多数情况下你需要的仅仅是一些连接的概念罢了,一些基本的包序功能,以及所谓的连接可靠性。可惜的是,这些功能UDP都没有办法简单的提供给你,而你使用TCP却都可以免费得到。
这也是人们为什么经常推荐TCP的原因。在用TCP的时候你可以不考虑这些问题,直到你需要同步连接的数量级达到500以上的时候。
所以,是的,UDP没有提供所有的解决方法,但是就像你看到的那样,这也正是UDP好用的地方。在某种意义上来说,TCP对UDP就好比是Hibernate和手写SQL的区别。
使用TCP失败的地方
人们经常给你建议,让你去使用TCP,比如&TCP跟UDP一样快&或者&游戏X用TCP如此成功,所以TCP当然是首选&,然而,他们完全没有理解为什么在那个特定的游戏中TCP是有效的,为什么UDP不按照顺序发送数据包呢?
那么为什么魔兽世界采用TCP呢?首先我们需要解释这个问题。这个问题其实是&为什么魔兽世界有的时候1000毫秒以上的延迟还能够运行?&这是TCP的性质决定的,在发生丢包的时候,会产生巨大的延迟,因为TCP首先会去检测哪些包发生了丢失,然后重发所有丢失的包,直到他们都被接收到。
可靠的UDP也是有延迟的,但是由于它是在UDP的基础之上建立的通信协议,所以可以通过多种方式来减少延迟,不像TCP,所有的东西都要依赖于TCP协议本身而无法被更改。
就这一点来讲,一些人要开始提到Nagle算法了,实际上它是你在实现任意一个对延迟敏感的TCP模型时首先需要禁止使用的。
那么魔兽世界以及其他的一些游戏是怎么处理延迟问题的呢?
方法也很简单,他们能够隐藏掉延迟带来的影响。
在魔兽世界中,玩家和玩家是无法碰撞的:因为这类碰撞是无法通过一些预测来处理的,但是玩家和环境之间的碰撞却是可以通过预测来处理的,所以这里使用TCP是没有问题的。
我们来看一下魔兽世界的战斗就会发现,玩家的攻击指令发送给服务器的操作是放在比如&attack_entity(entity_id)&或者&cast_spell(entity_id, spell_id)&的接口中来做的,换句话说,瞄准操作是独立于进行的。如此一来,一些类似发起攻击动作和释放技能特效就能够在没有收到服务器确认的情况下就直接执行,比如展现冰冻技能的效果就可以在服务器没有返回数据前在客户端就做出来。
客户端直接开始进行计算而不等待服务端确认是一种典型的隐藏延迟的技术。
几年前,我为一个叫&Five Card Jazz&的纸牌游戏编写过客户端。它使用的是http协议,它比直接的TCP协议连接的延迟更加严重。
我们用简单的纸牌绘制和抽牌的动画来掩盖延迟的问题,所以延迟的问题只在非常糟糕的连接下才会被看出来。这种方法也非常的典型:发送请求的同时开始播放牌桌的动画,一直播放翻动最后一张牌直到接收到了服务端传回来的数据为止。魔兽世界的战斗特效就是使用类似的原理。
这也意味着,我们到底是使用TCP还是UDP取决于我们能否隐藏延迟。
TCP在什么时候失效
一个采用TCP的游戏必须能够处理好突发的延迟问题(纸牌客户端就很典型,对突发性的一秒的延迟,玩家也不会产生什么抱怨)或者是拥有缓解延迟问题的好方法。
但是如果你运行的是一个无法使用任何减缓延迟措施的游戏呢?玩家对玩家的动作类游戏通常就属于这个范畴,但是这也不仅仅限于动作类游戏。
举个例子:
我目前正在写一个多人游戏(War Arcana)。
一种常见的操作是,你快速的移动你的角色通过一张充满战争迷雾的世界地图,但是一旦你探索过,迷雾就会被打开。
为了确保游戏的规则,防止玩家***,服务器只能显示玩家当前位置附近的信息。这意味着不像魔兽世界,玩家无法在没有得到服务器响应的情况下,做出完整的动作。和Five Card Jazz相比,我们即使允许500毫秒的延迟,也已经非常困难了。
在实现了游戏的原型后,在局域网内一切都进行的非常顺利,但当我们在WiFi环境下测试时,操作会间歇性的卡起来或者延迟高起来。写了一些测试程序之后发现,WiFi环境下偶尔会发生丢包行为,每当发生丢包的时候,服务器的响应速度就从100-150毫秒上升到毫秒。
没有任何办法可以绕过TCP的这个设置来避开这个问题。
我们替换了TCP的代码,用了自定义的可靠的UDP来实现,把大量的丢包产生的延迟降到了仅仅只有50毫秒,甚至比以前TCP不丢包的情况一个来回的延迟还要小。当然,这只可能建立在UDP之上,这样我们才对可靠性拥有完全的掌控力。
困惑:可靠的UDP只是TCP的一种简单的实现?
你有没有听过这种说法:&可靠的UDP就像TCP一样,所以还是用TCP吧&。
问题是这种说法是错误的。可靠的UDP一点也不像TCP,要去实现一个特殊的阻塞控制。事实上,这也是你使用可靠UDP代替TCP的最大的原因,避免TCP的阻塞控制。
另一个重点是可靠的UDP的可靠性是如何保证的。这里有很多种方法去实现。我非常喜欢Quake3网络库代码里的一些想法,它们也激发了我在War Arcana中使用UDP协议。
你也可以使用许多支持可靠通信的UDP库,当然,这样在可靠性方面,相比自己手动实现全部的代码而言,可能会更加通用而失去了一些性能优势。
那么到底是用UDP还是TCP呢?
如果是由客户端间歇性的发起无状态的查询,并且偶尔发生延迟是可以容忍,那么使用HTTP/HTTPS吧。
如果客户端和服务器都可以独立发包,但是偶尔发生延迟可以容忍(比如:在线的纸牌游戏,许多MMO类的游戏),那么使用TCP长连接吧。
如果客户端和服务器都可以独立发包,而且无法忍受延迟(比如:大多数的多人动作类游戏,一些MMO类游戏),那么使用UDP吧。
这些也应该考虑在内:你的MMO客户端也许首先使用HTTP去获取上一次的更新内容,然后使用UDP跟游戏服务器进行连接。
永远不要害怕去使用最佳的工具来解决问题。
原文链接:&&&&翻译:&-&
译文链接:&
【编辑推荐】
【责任编辑: TEL:(010)】
大家都在看猜你喜欢
热点头条热点头条热点
24H热文一周话题本月最赞
讲师:782758人学习过
讲师:228052人学习过
讲师:91259人学习过
精选博文论坛热帖下载排行
本书采用“如何解决问题”的方式阐述Ruby编程,涵盖了以下内容:Ruby术语和基本原理;数字、字符串等低级数据类型的操作;正则表达式;国际...
订阅51CTO邮刊用户名:rangercyh
文章数:173
评论数:477
访问量:545522
注册日期:
阅读量:1297
阅读量:3317
阅读量:585257
阅读量:470891
51CTO推荐博文
机缘巧合的机会,我有幸能够从头开始设计一个游戏的服务器。中间遇到很多欢声笑语和悲伤泪水,这里分享一下。我之前所在项目组的游戏服务器架构如下图:650) this.width=650;" src="/shard/s12/res/22f-40b9-a959-f6af2a0f3cd5/1.jpg" alt="" class="en-media" style="margin:.857412em 0px 1.286padding:0border:0height:" />这款游戏是一款MMO的端游,GateWay网关的任务是接受客户端的连接,然后通过分发策略,把玩家丢进GameSvr上去,之后玩家的所有请求都直接发给GameSvr,由GameSvr处理了。当然这里的分发策略跟一般的web服务器是不同的,web服务器一般会做成无状态的服务器,也就是对于客户端来说请求到达哪一个服务器都没有关系,都能够被处理,但是游戏服务器大多都是有状态的,web的一般分发策略是做一个负载均衡,只要保证服务器的整体压力没问题就已经是一个好的架构了,但是游戏服务器由于存在状态需要维护,所以通常都没办法做简单的负载均衡。举个例子,由于我们是MMO游戏,所以在服务器逻辑上存在地图的概念,好比魔兽世界的游戏里不同的玩家出生的地图是不一样的,而且你从一张地图下线后,下次上线的地点一般来说都会是你上次下线的地点,而根据游戏历程和策划想要营造的游戏效果来看,游戏里不同地图之间的压力通常来说是不一样的,比如主城的玩家就通常比一张偏远的野外地图的玩家要多,而游戏服务器的压力通常都出现在玩家聚集的时候,例如大量IO的压力。所以从设计人员的角度来看,一般会把不同的地图分配到单独的进程中去,所以GameSvr通常会按照地图来进行划分,那么GameSvr进程天生就具备了自己的状态,因为两个GameSvr进程已经就不一样了,玩家是在哪个地图,就只能把玩家丢到哪个GameSvr上去。当然,这只是我们采取的一种做法,其他人还有不同的做法,不过大致是类似的。我曾仔细考量过上面那个游戏单个GameSvr的承载能力,通常在1000人左右就已经开始吃紧了,这点也比较好理解,根据这个服务器的架构,几乎所有的玩家逻辑都在同一个进程内被处理,只有一些公共的逻辑被分配给Relay进程处理,这里的Relay进程承担两个作用,一个是做不同的GameSvr间的通信转发,另一个是它自身也会维护游戏里的公共逻辑,什么叫公共逻辑呢?比如聊天、帮会、排行榜等等,这些不跟地图相关的游戏逻辑,又被多个GameSvr共享的部分就被抽离到Relay进程上,其实这里有两种做法,一种是让每个GameSvr进程自己去维护这份公共逻辑,但显然这会浪费GameSvr进程仅剩的不多的压力负载。但是把逻辑放入Relay进程也带来一些问题,比如在游戏研发中会发现,越来越多的逻辑需要放进Relay进程,导致Relay进程越来越庞大,比如我们游戏中的帮会数据和全局定时器的维护就由Relay进程来维护的,但是程序员在写功能的时候经常就直接一个RPC调用来使用Relay的功能,因为这很方便,而且从现有架构的设计来看也是合理的,我们当时的relay的rpc接口设计的是同步的接口,于是当rpc激增的时候,整个游戏逻辑就变卡了。Relay的庞大导致两个问题,一个是单点故障的概率变高了,另一个就是Relay的性能低下会导致整个游戏服务器变卡。我们的服务器有段时间在每天晚上10点左右就开始卡,只要涉及到公共逻辑的部分就几乎无法使用,例如无法聊天、无法进行帮会操作等等,最后排查问题的结果就发现是游戏中的某些功能把逻辑写在Relay上,到10点进行了一个十分复杂的计算,导致Relay阻塞在那里,而无法响应GameSvr发来的请求。我是在游戏的开发末期加入这个项目的,当时Relay的体积还是比较小的,大家都刻意的去尽量避免游戏逻辑放在Relay上,但是当游戏真正进入运营期之后,deadline的限定,大家不得不把逻辑放Relay上,因为这是最快的实现方式。我眼看着Relay一步步的胖起来,在我离开这个项目的时候,Relay上的代码已经满目苍夷了。再来谈谈这个架构的其他部分,比如Bishop是用来进行我们游戏内交易数据的统计和验证的模块,主要是和公司的交易系统进行对接,AccoutSvr的作用是处理游戏内账户的相关操作,比如建立账户,新建角色等等,它的主要作用其实是为了保证游戏数据的唯一性,例如角色名的唯一、宠物名的唯一等等。接着是Mysql的部分,云风曾经在博客里说过游戏服务器中数据库的作用应该只是一种备选方案,&也就是说如果存在理想的游戏服务器,永不宕机,永不维护,那么实际上数据库是不需要的部分,数据库承担的是一个游戏恢复和容错的机制,我很赞同云风的这种说法,而一旦不需要去考虑数据库的部分,那么游戏设计其实减掉了很多容错的做法。关于数据库的部分我后面还会谈到。然后是这个架构的扩展性,对于游戏服务器来说,扩展通常有三种,一种是开新区、另一种是合服、最后才是由于服务器压力顶不住而扩展逻辑进程。上面我们这个端游的服务器模块从设计上就不去考虑开新服的机制,单套服务器架构基本只支持一个区,所以在开新区的时候,做法是部署同一套服务器架构,利用客户端更新服务器的地址来实现不同服的架构;合服的情况要更加复杂,因为在设计上没有考虑多服的设计,所以不同服之间的数据可以说是毫不相关,那么在合并服务器的时候必然存在一些冲突数据需要处理,不光是一些玩家数据,甚至还有一些游戏逻辑数据,例如我之前做过一个功能,是实现一个全服的玩家联赛,最后每个区会产生一个冠军,然后冠军的雕像会被放置到游戏中的主城中展示一个月,但是后来有两个区合并了,那么到底展示谁的雕像,因为无论你展示哪一个区的,玩家都会不满,当然,这种事情一般需要策划去考虑然后解决,但是从程序上来说,确实存在这种需要特别处理的地方。在合服的时候,另一个问题是之前保证的角色名不重复是利用的各自区的accsvr,通常accsvr保证惟一性的做法是使用同一个数据库来保存需要排重的信息,但是对于不同的网络运营商,这个数据库很可能没办法统一起来,这样一来,当两个处于不同网络中的区需要合并的时候就出现了难以解决的问题,比如我们有一次把电信和网通的两个区进行合并,本来这两个区各自确实能够保证角色名唯一,但是当跨运营商合并的时候却会发现冲突。然后是服务器压力,不知道是由于当年设计这个架构的人没有考虑到还是当时不存在这样的问题,所以服务器横向扩展的能力是十分弱的,对于新开的副本,relay进程会根据gamesvr的压力来选择把新副本开在哪个gamesvr进程上,但对于常驻地图,却是写死在配置表里,绑定固定的gamesvr,而relay又没有提供动态添加gamesvr的功能,这导致了如果在服务器运行期间出现了单个服务器进程压力,除了重启服务器,几乎没有任何办法。这个在运营期暴露的很明显,由于GameSvr按照地图进行划分,当开新区的时候,玩家大量涌入同一张地图,导致单个GameSvr压力出现峰值,但这个时候却没办法动态的扩展进程进行分压,而导致服务器宕掉。在后期的运营中这样的情况屡见不鲜。后来我还听到过很多关于页游的架构,页游服务器整体上跟端游思路是类似的,由于客户端的通常通信方式不再像端游那样采用原生tcp连接,而是使用http等短连接的协议,所以在客户端连接的部分设计上更加灵活,而且大部分页游的游戏逻辑没有端游那么复杂, 在客户端的表现力有限的情况下,基本上整体的游戏服务器设计要更加精简,所以我看到通常服务器后端会更加偏重于如何进行横向扩展。上面我提到的架构扩展性差的问题,对比页游的滚服方式,体现的最明显了。这就是关于我上一个游戏服务器的样子了,下一篇开始我自己的服务器设计。本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)

参考资料

 

随机推荐