游戏服务器内的组播
游戏服务器在设计时,会有许多组播的需求。比如一个 NPC 需要向周围的观察者播出它的状态信息。无出不在的各种聊天频道中需要向频道中的参于者广播聊天消息等。
通常,我们会为每个组播的请求维护一张列表,然后再把需要的信息包发送给指定列表上的多个连接。这个过程在很多地方都会遇到,一个设计的不太好的引擎,再这里有可能滋生诸多 bug 。尤其在多服务器的设计时尤其如此。
这两天,我试图寻找一种简洁统一的解决方案。
前几天的一篇 blog 讨论了一组服务器设置多个外部接入点的设计。就着这个思路我们可以引申一下。
当每台连接服务器设置一个不大的上限,比如最多同时处理 8192 个外部连接,那么管理分组倒不会带来太大的负担。
我们只需要在逻辑服务器与连接服务器间定义四条协议。
- 把一个连接加入指定分组。
- 让一个连接退出指定分组。
- 向一个分组广播消息。
- 删除一个分组。
这里,后两条协议是冗余的。
对于第三条协议,如果表示连接号的容量足够大,我们完全可以留一部分号码用于组播。这在 IP 协议中定义 IP 地址的构成时就是用的类似方案。不过我们的设计为了节省带宽,全部用的 2 字节做内部连接号,资源比较紧张,所以就单独设计一条协议了。
对于第四条协议,当最后一个连接退出时,分组就自然取消了。增加一个专门的删除协议,纯粹是使用上的方便。
在连接服务器上维护一个分组,仅仅需要一个 1K 的数组(8192 bits)。而有组播需求时,只用遍历这个数组。在 32 位系统下,只是一个 256 次的循环而已。因为大部分分组的成员都不会太多。数组中充斥着大量的 0 。扫描一下就非常的快了。
连接服务器用一个简单的 freelist + hash 表的技术,就可以高效且动态的管理不限量的分组,无论从 CPU 还是内存的负载来看,都是可以接受的。
我们额外需要做的只是一个分组编号分配管理器。为每个进程分配唯一独立的分组号就够了。在我们现在的设计中,为了尽量避免交互通讯。分配新组号采用不需要反馈的形式。每个需要申请组号的进程,都有独立的组号 id 空间。由分组管理器对若干独立的分组号做一次统一映射。
换句话说,每个服务器进程都可以直接从 0 号分组用起,然后直接用 1 号,2 号,3 号 …… 类似操作系统管理物理内存一样。独立进程拥有的只是虚拟分组号,由管理器映射到全局唯一分组号上。这样就完美的解决了不同服务器进程间的分组编号冲突问题。
Comments
Posted by: windlucid | (12) June 27, 2007 05:03 PM
Posted by: N/A | (11) April 25, 2007 08:48 PM
Posted by: analyst | (10) April 15, 2007 11:40 PM
Posted by: DD | (9) April 5, 2007 09:56 AM
Posted by: Cloud | (8) April 4, 2007 03:30 PM
Posted by: sunway | (7) April 4, 2007 09:21 AM
Posted by: Albert | (6) April 3, 2007 04:17 PM
Posted by: anders | (5) April 3, 2007 08:43 AM
Posted by: Cloud | (4) April 2, 2007 09:38 PM
Posted by: Arbow | (3) April 1, 2007 07:56 PM
Posted by: Cloud | (2) April 1, 2007 05:32 PM
Posted by: cat | (1) April 1, 2007 11:05 AM