游戏的多线程服务器是什么怎么如何设计

下次自动登录
现在的位置:
& 综合 & 正文
基于MYSQL的 网络游戏 多线程 数据库 服务器 设计与实现
的性能很赞,但要是这样游戏有个几万人在线,数据库服务器肯定吃不消。得益于innodb
的行锁支持,很多数据库的请求都是可以被并行处理的,比如两个角色A
同时登录,进行登录验证并且获取角色列表请求,角色A
数据是完全不相干的,所有可以并行处理。
多个工作线程,并行处理
数据库操作API
用预处理方式(mysql_stmt_*
省去了解析sql
语句的工作,直接传入参数执行查询,对于大量复杂的相同查询,用预处理方式节约不少。
接下来讨论一下服务器的工作模式(
。考虑一下这样一种情况,同一个角色发送了两个请求,并且都是针对同一条数据操作,第一个写第二个读。那么为了保证数据的正确性,两个请求必须保证顺序执行。要是使用简单的生产者-
消费者模型,来一个请求,只要有空闲的工作线程就被处理,这种方式的话两个请求的执行顺序是不能保证的。这样我们必须保证同一个角色的数据请求会被顺序执行。
为了保证这一点,我们就得为每个请求加一个标记,比如角色ID
,这里称这个标记为阻塞项。用阻塞项让请求按照我们的期望顺序执行,为了避免线程竞争加锁带来的开销,可以采用boss-worker
模型,即由一个boss
线程来为其他worker
线程分配工作。
这样思路就清晰了,boss
线程从等待队列中顺序取请求,然后检查该请求是否可以被立即处理,若不可以则加入队列,等待再次调度,若可以则分配请求到一个空闲的worker
线程,分配工作后boss
线程更新当前正在被处理请求的阻塞项集合。
这里有个问题,当请求不能被立即调用时,我们先把它放入一个队列,取下一个请求再来进行相同的操作,那么什么时候再执行这些请求呢?当检查请求不能被立即执行的时候,其实我们是先跳过它,那么可以设个计数N
,从有一个请求被放入等待队列开始,再向后取N
条请求处理,这时再回过头来处理等待队列中的请求,注意处理等待队列中的请求时,boss
线程必须逐个为请求分配工作线程,若不满足执行条件,则boss
线程等待直到条件满足。
还有个细节问题如何维护正在执行的阻塞项集合?显然只有两种操作,添加和删除。当boss
线程分配工作给worker
线程时,需要添加阻塞项到阻塞项集合,这个操作不需要加锁;当worker
线程处理一个请求结束后,必须要将处理完的请求的阻塞项从集合里删除,为了避免加锁带来的开销,这个删除操作可以由boss
线程分配工作检查是否有空闲线程时,判断哪个线程的工作已经完成,然后删除对应的阻塞项。
:很多问题都是仁者见仁智者见智,相信解决方法没有最好只有更好,希望与大家多多交流。
【上篇】【下篇】豆丁微信公众号
君,已阅读到文档的结尾了呢~~
网络游戏服务器端设计和实现,网络游戏服务器端编程,图解服务器端网络架构,网络游戏服务器端下载,svn服务器端下载,android服务器端开发,服务器端口,java服务器端开发,android服务器端搭建,服务器端
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
网络游戏服务器端设计和实现
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口博客分类:
博客好久没打理了,今天有时间,把在公司wiki上写的一些东西移植一下吧
我们的游戏至今已经上线第四个同步玩法了
有点想法,也有些疑惑,在这里发一下,欢迎各位tx各抒己见
准确点说,这里所谓的“同步服务器”其实包括两个部分的内容,第一是说明通信方式是长连接,第二是服务器不具有动态扩容的能力,也就是说想增加用户数不能通过增加机器的方式来做
当然,同步服务器按道理说只包含第一部分的内容,但在这里算是一个特殊的语境吧
1.区别(主要区别于普通的web服务器)
a.通信模式很显然的,不多说了
b.冲突的解决方式
(这里的特殊语境,是指做游戏常用的数据库:腾讯的cmem,redis)
现在我所知道的冲突解决方案有这么几种
一致性缓存锁:这种锁的劣势是没有普通锁的notify机制,也就是说,必须事先加锁,锁失败了只能退出,一些在逻辑中间的事务性操作用这种方式就不能实现了
一致性缓存cas:cas是cpu操作原语,也就是compare and swap,通常在一致性缓存中是基于乐观锁的方式(对比版本号)来实现的
redis作者曾说了这种方式性能是非常不好的,但是如果我们在程序逻辑做一些优化,也未尝不可
普通锁:这种锁也不好:很不优雅,必须将逻辑框在一个个的try finally中,而且容易出错,而且一旦在逻辑中作为一个常态出现了,那么就不得不把整个逻辑当做了一个巨大的耦合体(除非规范定得很好,能将锁分离,但大部分情况下貌似很难,起码我做不到)
cpu cas:比较推荐这种方式,优点很明显,风险低,效率高,缺点也很明显,通常cas只能用于解决单个变量的冲突,一旦涉及到了多个变量,代码就很难写了
同步服务器比较偏向于使用后两种,而普通的web则一般只会用前两种
c.思维方式
这方面其实我一直都没想透
比如通常我们写功能都习惯于使用请求响应模式,但显然这种模式用户体验是偏差的
实际应用中,同步服务器其实能给予更好的用户体验,也就是由服务器去驱动一些事件,注意,这里说的是事件
也就是说服务端给前端返回的不是状态了,而是事件,去驱动前端
虽然写了第四个了,但是由于种种原因,一直都逃离不开请求响应模式,主要不知道前端应该怎么改变它的架构
只是在局部做了一些服务器驱动的功能
2.协议
(指的是flash做客户端,java做服务器端的特殊场景)
由于个人经验也不是太足,这里只讨论两种协议,protobuf跟amf,而也只考虑跟flash进行交互
之前仔细斟酌过amf好还是protobuf好的问题
首先先做一个对比
数据大小:
protobuf无疑是最小的,除了数据,它只多了一个类型编号,跟一个位置索引,当然,该压缩的都压缩了
amf:amf对数据也会做压缩,而对string还会进行重用(这点有可能如果传输大量的类似的文本信息,amf的压缩比会更高),编码方式跟protobuf差别不大
但是有一点很致命,它会将对象的类型信息加进去,包括变量名等信息,也就是说,如果是数组,可能会好一点,如果是每个对象只用一次,传n个对象,无疑这部分的数据量是很大的
效率:
由于游戏服务器基本都是出流量远远高于入流量,这里只考虑服务器向客户端发的情况
protobuf用的方式是生成代码,而amf是反射,虽然没做具体的测试,但无疑,差距应该是很大的,由于是同步服务器一般给前端发的都是短消息,频度高
易用性:
flash默认兼容amf协议,从通道中可以直接简单地解析出对象,非常方便,protobuf则需要编写文件,生成代码,重新编译,数据转换,等等
但是否amf真的完胜了?
经过与我们的首席架构师跟前端的讨论,其实不是这样的
同步服务器一般需要比普通的web更严谨的编码风格,在协议上也是这样的
protobuf定义了前后端交互的协议,非常明确,再也不需要前端debug,查看这样的方式,也就是说,即使我们用amf,我们也需要一份这样的协议,而且是纯手工写的(如一样的dto),个人觉得,会比protobuf产生的更麻烦
当然,为了使用protobuf,还需要一些额外的编码,但这些是一次性的
一比较之下,显然protobuf更好,更优秀,但如果是非常简单的应用,用amf也未尝不可
再补充一点
最近发现前端非常依赖于数据,归根到底其实是amf惹的祸,因为amf返回给前端的是一个动态对象,所以前端想要知道对象里面的值,都习惯性的debug,所以每次,都必须得后端写完,提供数据,前端才能开始做一些事情
这样的前后端合作模式显然是有问题的
相对而言,protobuf会给他们生成一个类文件,对象里面的变量都是确定的,能一定程度上的改变前端这个坏习惯
3.业务架构
现在4个同步项目的业务架构,都沿用了三国里面的面向服务的架构方式,也就是service,bo,这样的方式,在现在所写的4种业务中,这样的方式挺好用的
大体的区别是:
service后面默认都添加了一个参数:“连接上下文”
增加了两个配置文件
把返回的map去掉了,返回数据通过“连接上下文”发送
多了一种叫task的东西,跟bo同一层次,是一种主动运行的事件(这到底在我们业务模型里面应该是一个什么东西呢?之前考虑过让他居于服务层,让他去调用服务,但貌似也不好,因为task调用的逻辑与前端调用的逻辑没有任何地方可重用的,而且会破坏endpoint调用service的方式)
现在有一个问题是:这样的架构如果用于复杂的游戏,例如mmo,能不能用,可用性怎么样?
我们知道,像我们社交游戏的业务,都有一个特点,层次简单,比如过:用户,下一层是兵营,将领,客栈……都处于同一层次上,就没有更深入的层次了
然而复杂的游戏,显然会有很多层,比如说之前写的同步战棋战场,整个服务器有多个战场房间,战场包含着小据点,据点中又包含用户,用户带着将领,都是一层嵌套一层的,这就会我们拿数据的时候,每一个service都需要一层一层地找到数据,然后操作,我们看到的也许就是多个大bo,我们写方法可能都是Abo.doSomething,然后Abo又在方法内调Bbo,这样其实是挺不好的
还有一点,越复杂的业务,task的逻辑就会越多,最后task会越来越多,越来越乱
跟我们的首席架构师多次讨论过这个问题,虽然看法不一致,但我还是觉得,这种业务模型应该还是适用的,起码在有新的方式之前,个人感觉还是利大于弊的
4.异常
在同步服务器中,异常的控制很关键,必须考虑所有可能的情况,定义异常,并捕获,比如之前我在写cas避免冲突的时候,考虑到必须限制cas的次数,否则会造成数据库压力,但是当cas连续失败多次之后,怎么办呢?
以前是直接抛出一个异常,就不管了
但显然,在同步服务器中,这是有严重问题的
我们之所以用同步的方式,除了数据及时性,有一个很重要的部分:通常我们需要写的业务存在着大量的数据竞争。显然用非同步服务器来解决冲突是很困难,并且很不靠谱的一件事,它往往只适合数据分离的业务。
基于这一点,我们如果也像之前一样,抛出一个异常,那很可能会引起数据的不一致,然后是迅速地连锁反应,蔓延,相对而言,我们普通的业务对数据一致性的要求低很多,因为影响的最多是1,2个用户而已
5.同步模型
同步1v1,3v3,老-虎-机用的方式都是房间内单线程,将同步相关的操作封装在了线程池内
国战用的则是锁,所有都是显式加锁,写得很麻烦,而且不好看
总的来说,能不用锁最好还是不用的好,房间内单线程模型,既不用考虑可见性,也不用考虑冲突,而且可以没有限制地使用jdk的集合类,相对起来编码简单很多,房间内操作在锁的层次基本没有任何的耦合,而且不容易错,之前也考虑过,如果写复杂的游戏,也许我们可以把所有场景都抽象成一个个房间,这样,我们只需要考虑房间之间的切换就可以了,然后其他的都是房间内操作,这样的话,我们大部分业务都不需要考虑同步问题了
6.服务器组
我们知道,单服,又不可扩容,对游戏的限制是很大的,于是,有了服务器组的实现(现在做的新游戏原计划是做多区多服的,全部请求都用长连接实现(最后改变了初衷))
所以我们一个区,其实会需求一个服务器组,按业务去划分,比如说:场景1服务器,场景2服务器,交易服务器,战斗服务器,用户状态服务器,等
这其实会有个很关键的需求:网关服务器
既然用了java,肯定希望要用就用全套的,网关服务器也不会考虑用c的实现了
大家都说java比c慢,但慢多少?大家都没有个准确的说法,网上的文章看了几篇,不是测试错误就是检测方法有问题,没有可参照性
按之前在做消息服务器时,与我们的架构师tx做的c版本的比较
c版本:单线程,cpu100%,极限大概是32000qps
java版本:4核多线程,cpu60%-70%,极限大概是68000qps
如果按这个看的话,其实没有太大的区别(个人认为,如果每组能撑10w同时在线,那改为撑7,8w,也不是什么大不了的事情,也就是说性能如果没达到150%,可以忽略不计)
后来也试着在内网做了下压力测试,可是没把服务器压死,先把公司的路由器压死了,后来就没测了
出于这个计划,仔细研究了下mina,netty(还sb兮兮去看了下的游戏开源服务器darkstar,想去看看别人怎么设计网关服务器的,谁知道就一个分布式的业务框架,跟游戏没一毛钱的关系)
发现一个问题,在decoder的时候,mina都会将byte[]从directbuff拷贝一遍到heapbuff中(而且这块代码是写死的,很难动)
如果我们用netty或者mina做这个网关服务器,无疑,我们的做法大部分应该是将byte[]从入口拷贝到出口去,然后发送,这样就会涉及到byte[]的2次拷贝,相当于netty和mina中做的大量的细节优化,都被这简单的两次拷贝给抹杀了
当试着去修改netty的源码时,资料片改为了用类似普通社交的玩法实现,这个计划就不了了之了
之后也去问了下别的公司的开发者(java的),都是说现在这浮躁的网页游戏行业很少有服务器组的实现了,都是单服务器,撑3,5千人就差不多了
c++的代码很多这样的源码,像传奇,魔兽世界,等等,java难道做不了么?
7.时间问题
在同步服务器中,时间是个很恶心的东西,因为客户端是有渲染时间的,但后端没有时间的概念, 后端是按事件去触发,去响应的,
举个简单的例子,一个简单的限制,A从x点移动到y点,时间,距离,后端其实是需要检测的,不然就各种外挂,但是如果前端每走一步又跟后端请求一遍,玩家会疯掉的
还有像资料片中的连招的释放,你必须在固定时间内按键,才算正确,又还有国战中我们需要按各自战斗时间决定排队顺序(谁跟谁打,什么时候打)
关于移动网上有的是各式各样的算法,这里就不罗嗦了
说一下在国战中和在资料片中是怎么解决这个问题的
终于找到是用java的了!LZ想问一下你们项目中protobuf,message在经过网络传输后是怎么还原的?如果在知道协议消息名称,该如何生成对应的java对象呢?自己翻一下api啊~有很简单的方法的
浏览: 56226 次
来自: 北京
想法很好。。万一 c就一个人下车 b很浪费啊
楼主是大神,膜拜啊,不过有个地方说的不太对啊, if (poo ...
milk_36 写道终于找到是用java的了!LZ想问一下你们 ...
终于找到是用java的了!LZ想问一下你们项目中protobu ...
额,是我说的不准确哈,server不仅仅是options的集合 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'游戏技术网-专注于游戏服务器开发,独立游戏开发者
对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,...
注册服务相信大家都很熟悉,基本上不管开发什么项目,只要有用户,都需要注册和登陆。也是我们做的最多的一个服务。它的功...
当用户在大厅登陆成功之后,大厅会分配一个网关的地址给客户端。客户端与这个网关建立长连接,负责与服务器的通信。网关的...
大厅就是一个房间的入口。对于游戏服务器来说就是一个用户进入游戏的入口。他的主要功能一般有登陆,注册,网关选择,用户...
不管是游戏服务器开发,还是其它服务开发,越来越多的平台都要求服务端必须支持https的访问。以增加安全性。比如目前...
对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,...
当用户在大厅登陆成功之后,大厅会分配一个网关的地址给客户端。客户端与这个网关建立长连接,负责与服务器的通信。网关的...
对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,...
注册服务相信大家都很熟悉,基本上不管开发什么项目,只要有用户,都需要注册和登陆。也是我们做的最多的一个服务。它的功...
对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,...
当用户在大厅登陆成功之后,大厅会分配一个网关的地址给客户端。客户端与这个网关建立长连接,负责与服务器的通信。网关的...
大厅就是一个房间的入口。对于游戏服务器来说就是一个用户进入游戏的入口。他的主要功能一般有登陆,注册,网关选择,用户...
不管是游戏服务器开发,还是其它服务开发,越来越多的平台都要求服务端必须支持https的访问。以增加安全性。比如目前...
对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,...
注册服务相信大家都很熟悉,基本上不管开发什么项目,只要有用户,都需要注册和登陆。也是我们做的最多的一个服务。它的功...
当用户在大厅登陆成功之后,大厅会分配一个网关的地址给客户端。客户端与这个网关建立长连接,负责与服务器的通信。网关的...
大厅就是一个房间的入口。对于游戏服务器来说就是一个用户进入游戏的入口。他的主要功能一般有登陆,注册,网关选择,用户...扫一扫体验手机阅读
游戏服务器架构2
<span type="1" blog_id="1346961" userid='
566篇文章,440W+人气,0粉丝
前百度高级工程师的架构高可用实战
¥51.00218人订阅
<span type="1" blog_id="1346961" userid='

我要回帖

更多关于 多线程服务器是什么 的文章

 

随机推荐