« 多进程的游戏服务器设计 | 返回首页 | 驾照终于考出来了 »

数据服务器的设计

今天开始正式开始做数据服务器。在这点上,我希望一组服务器上所有的逻辑服务遇到的数据存取需求都通过一个单一的数据服务器完成。而且,写入数据是单向通讯的。即,逻辑服务器只提读写盘请求,而无须确认。写数据好说,读数据稍微难处理一点,我现在的方案是,数据服务器加载数据的部分只对位置服务器负责,把数据提交到位置服务器即可。位置服务器可以通过分析数据知道玩家的数据流应该流向哪台逻辑服务器。

以上逻辑是基于每个玩家有独立的数据的,而且一个玩家同时只存在于唯一一个场景。也就是说,当一组数据存活的时候,只唯一属于一台逻辑服务器。这样做的好处是,切换场景非常的简单,只是让玩家从一个场景退出,给数据服务器发出写盘指令,并发送所有数据。数据服务器写盘的同时也 cache 了这些数据,并向位置服务器提交新的位置,并把这些数据转发向位置服务器。位置服务器可以再转交给新的场景。

对于玩家登陆和登出的处理并没有特别之处,我们可以设立两个虚拟场景,一个负责登入,一个负责登出。每个新连接自动导入登入场景,这个场景负责发出加载指令(下面可以看到,甚至无须设置加载数据的协议)。然后再做一个自动的场景切换操作即可。而玩家登出,则是转入登出场景,这是一个黑洞,玩家的连接可以在这里安全的断掉。

当玩家不停的穿梭于各个场景之间时,为了避免频繁的数据转发,我们可以给玩家数据做一个赃标记。如果没有弄赃,实际的数据可以不被转发。这个标记的另一个意义在于,若数据没有弄赃,而数据服务器的 cache 中又没有数据时,就需要从外存加载了。其实这就是一个读请求。

月初我在公司内部讲解这个设计时,遭到了一些同事的疑问。最典型的一个是,帮派信息如何处理。的确,类似帮派的信息,不属于任何一个玩家。如果你单独设一个非玩家对象保存这些数据时,可能会分布到不同的逻辑服务器上。的确对数据服务器的设计是一个挑战。

今天仔细考虑过以后,我发现可以从设计上避免这个问题。方法如下:

以帮派为例,可以设一个帮派总坛的场景。这个场景可以是虚拟的,在 client 表现上甚至可以只有一个界面,进入这个场景的玩家之间可以相互不可见。这样减少了大量的通讯量。

玩家任何时候查询,修改,帮派数据的时候,都强制他进入这个场景工作(也就是独立进程维护唯一数据)。做完操作后,玩家可以从哪来的回哪去。表现上,他可能并不会察觉到自己进入了一个遥远的地方。

甚至很多玩法应蕴而生。比如帮派在各地开了分舵。组织要求你把总坛的物质运输到分舵。其实仓库里的数据都是放在一个进程中。表现上,玩家可能千里迢迢的押运货物,只是修改了一下物品的归属地而已。

帮派也可以开出空头支票,玩家接受支票交易时,或许要去帮派回所去查一下帮派的信誉度,或者验证一下支票能不能兑现。因为支票开出去到了玩家手上后,数据已经交给玩家个人管理,和帮派数据无关了。

这样,复制出来的帮派数据都有了时延,比如你不能及时得到帮主是谁,帮派里有什么变化等等。(只是举例,实际万一想解决,可以走聊天这种不可靠通道)但是我个人认为这是符合现实的。因为现实中要得知一件事情,也是依赖一个信息发生源的。

想通了这些后,个人感觉我们的设计最终还是保持了简洁。满符合 KISS 原则。每个进程好好干好一件事吧 :)

ps. 这里也突出了心跳服务器的重要。许多虚拟场景,如帮派管理等,可以放慢它的心跳(至少不用处理战斗时 10Hz 那么高的频率),这样也降低了这些进程的负载。而玩家体验却并不会有太大的影响。

Comments

我晕
为什么我觉得您 讲的很多技术都 很 低级

我设计的服务器中,这种处理是通过特殊NPC来完成的,你要执行这种动作时,服务器将这种请求翻译成一个聊天消息,直接给特殊NPC:“帮派管理主席”发送如下信息:“我要加入/退出/读取xxx帮派,是否可以?,可以则反馈我xxxx”。这个特殊NPC是看不见的,可以在任何时候访问它。而且专门像开外挂一样,在副服务器上运行着这么一个“bot玩家”,这个bot玩家的后面其实就是数据库和帮派的逻辑操作了,所有操作都由聊天信息的次序按队列执行。

Why we should all mimic korean-style architecture? Central database server isn't a best choice I'm afraid, use more in-memory database inside map server, or a clustered database group as a back-end, in-memory database query might cause overhead, but they are less time to block your server logic than a central database would cast you....See those korean servers, the bottleneck is always that database server.

以前曾遇到过类似的实现,当然和您说的也不完全相同,游戏的逻辑服务器是一个程序,启动起来当然就是一个进程了,专门处理一张地图,启动时是通过参数加载不同的地图,也是有一个register server,所有的Logic server在启动后,都要注册到上面,玩家在不同的logic server上切换,就是通过register server中转的。

单机游戏一般让逻辑和显示同步跑;但是网游不可能做到这一点,每个客户端的显示帧数都不相同,所以肯定要插值。既然要插值,不如让逻辑跑慢点,因为服务器的cpu一般最先成为瓶颈。30fps对于服务器来说,实在是太浪费了,16fps比较合适

看了云风一系列关于网游服务器的设计,总觉得太过理想化了,期待着运用这套架构的游戏早日释出。

另外,想请问一下云风,你之前所说的server以fps的方式运行逻辑是否也是借鉴于bigworld,因为听说很多商业引擎都采用这种方式的。

你在使用这种方式后是否觉得有什么不妥? 假设一个server跑3000人以30Hz Run.那么意味着33ms跑100人的逻辑,这显然是不合理。我手头资料显示,这种方式运行的server只能跑不下于500人的逻辑。

不知道你有没有做这方面的测试?

你说的这些,实现起来,好象很有点难度。

引入这个数据服务器的作用和优点是什么?文章一开始就没交代清楚。
我想,即便有了一个维护所有玩家数据的服务器,逻辑服务器上还是要维护它感兴趣的那些玩家的数据,而且数据的改变也是从逻辑服务器发起的。如果这个假设没有错的话,跨服之前的存盘是不可能不需要回包确认的;因为这时将牵涉到两条连接,而两条连接上的数据包的时序无法控制。
后面讲到了帮会数据处理,更加显得是先有了框架,再把没考虑到的内容往里套。其实不仅仅是帮会,将会有很多和任何玩家无关或者和多个玩家相关的数据需要集中管理,你那个解决方法显得很生硬,并不直观。

我们以前的想法和这很像,逻辑分块,可惜没有时间去实现它们

有些逻辑无关信息(不参与逻辑运算,只是通知性质)可以走聊天通道。可以创建专有聊天频道来广播。

对于像帮会成员列表之类的功能该如何处理?比如WOW的成员列表,可以显示等级,所在地,在线以及不在线信息等。再有就是组队时跨区域队友的状态如何显示。。

没有合适的项目使用引擎是很难发挥出威力来的。我个人认为网络游戏引擎都是有局限性的。zona的情况我听说过一些,zona确实做的不错,负载均衡上是下了不扫功夫,但是做的不够完善,原因可能是开发者没有具体的网络游戏项目经验吧,而且时间上也不够,而且后来使用上也有一些问题,导致后来。

我不喜欢 bigworld ,bigworld 跟我说的也不一样 。

参考的只有 server/client 通讯的 rpc 形式,但是具体也不一样。设计结构上恐怕有很大的区别。

不过论复杂度 bigworld 要复杂很多,它最突出的特点是可以做超大连续场景,并动态负载均衡。可惜我一不喜欢复杂,二觉得这个最突出的特性对我的游戏没有需要。

我的个人看法是,若无具体项目在先,并得到持续支持。纯粹的网游引擎开发不会有什么好下场。bigworld 找到网易这样一个好买家是他们的幸运;当然“天下”能有这样一个好引擎也同样幸运。

听说网易购买了bigworld的网游引擎,想必云风现在这个系统的设计是参照了bigworld的设计的吧。云风文中提及的问题恐怕也是bigworld的一些缺陷之处吧。

其实盛大的美国zona子公司的zona网游引擎设计思想还是蛮先进的,对与云风文中提及的一些问题大多都有较好的解决方案。可惜这个公司高层差不多走光了,引擎实现有些问题,还没完善。现在基本无人维护了,可惜了

这里的关键是不是把每个玩家零散的跨服数据操作全部集中到了一起,就是把帮派相关的跨服数据操作,全部都集中在了虚拟帮派场景所在的服务器内,这样就可以通过单独的心跳控制来简化和减少跨服操作。
对于那些对时效性要求比较高的跨服操作,应该还是要想其他的办法

Post a comment

非这个主题相关的留言请到:留言本