数据广播方案的优化
在服务器组的架构下,我们一般会引入一个网关服务器,或类似功能的组件,所有的客户端连接都是到这里,数据然后转发给当前所在的地图服务器。
这样,在数据广播时便存在一个很大的优化可能性。以前的单服务器架构时,比如要广播移动消息,可以直接找出周围的玩家列表,构造要发送的数据,然后依次调用send即可。但是在多服务器架构下要是还这么做的话,那地图服务器与网关服务器之间的数据传输量将会非常大,而且这些数据之间除了目标IP地址不一样外,实际内容完全相同。
其实在以前单服务器架构时就曾考虑过该优化方案。最初使用的立即发送数据包的方式在遇到需要同时发送大量数据时出现了问题,为了避免由于在逻辑线程内的send调用导致的游戏逻辑被阻塞,我们将数据发送工作放到了一个独立的线程中,游戏逻辑线程在需要向客户端发送数据时,只是将要发送的数据包和客户端连接句柄递交给了发包线程。这个过程也就和带网关的多服务器架构完全类似了。
当时也是为了避免给发包线程递交太多的请求,因为每个发包请求都需要拷贝一次数据包并添加到发送队列中,显而易见的弊端就是数据多次拷贝的CPU消耗和队列中存在多份数据的内存消耗,所以优化的必要性非常高。
最终采取的方案是只递交一次发包请求,在请求包里面包含了这个数据包要发送到的客户端句柄列表,这样数据完全不需要做拷贝,而且内存占用也只有一份。
放到多服务器架构下也可以这样做,区别仅在于发包请求是发送给了网关服务器。
以前的方案只做到了这一步,再继续考虑一下,其实还有进一步优化的可能。
拿比较简单的聊天数据包来说,比如在一个小组频道内聊天,服务器在广播此类数据包时,每次递交的发包请求中的客户端句柄列表都是相同的,除非队员发生变动。所以,可以考虑的是这个列表其实不用每次都发送。通过控制命令在网关服务器上先建立好这些广播组,以后广播数据时只需要指明广播组编号即可。在云风的《游戏服务器内的组播》一文中对此有介绍。
这里的组我们也可以称之为频道,比如小组频道,团队频道,公会频道,世界频道,本地频道,当前频道等,当然还可能会有自建的频道,每个频道有一个唯一ID。不同玩家间的当前频道需要独立,但其他频道可以共用。
关于当前频道需要特别说明一下。这里的当前频道指的是以玩家当前所在位置为中心点的一个可见范围,也就是当玩家移动,或者说话时需要广播到的范围。因为玩家位置是经常会变动的,所以这个频道内的玩家列表变动也非常频繁,而且不同玩家间的当前频道不能像小组频道一样进行共用。
这个方案对于玩家列表变动不频繁的组队聊天这类情况很有效,但是对于玩家列表会频繁变动的当前频道广播却有些麻烦,维护这类频道会使得地图服务器与网关服务器之间的频道成员管理命令非常频繁。
但是这里也有个选择,一是在频道成员发生变化时立即向网关服务器通知变动,另外一种做法是只在有频道数据要递交时才检查有无成员变动。
比如一个玩家坐着没有动,不停有玩家从其旁边经过,这时他的当前频道玩家列表是不断变化的,但如果该玩家不做任何操作,比如移动和在当前频道聊天,这个变动情况其实是不需要反馈到网关服务器的,因为不会有这个频道内的数据需要广播。
当然,如果这样做的话,可能就需要在地图服务器上也保留两份当前频道玩家列表,用于比较该列表的变动情况,这也就是要在内存占用和网络数据传输量上做个权衡。虽然未经实践验证,目前来说我还是比较倾向于后一种方案。
阅读(788) | 评论(0) | 转发(0) |