Bri*_*ian 13 multithreading zeromq redis node.js dnode
所以我现在正在开发一个node.js游戏服务器应用程序,我在这里遇到了一些问题.我的问题是我使用socket.io来接受来自游戏客户端的入站连接.这些客户端可能连接到游戏世界的几个区域或区域之一.
基本架构如下所示.主进程为运行区域管理器进程的游戏的每个区域分配子进程; 专门用于维护区域数据的过程(3d模型,玩家/实体的位置等).然后,主进程为其创建的每个区域管理器分配多个"通信线程".这些线程创建了一个socket.io实例,并侦听该区域的端口(多个线程在单个端口上侦听).这些线程将在其自己的进程中处理大多数游戏逻辑,并与支持游戏服务器的数据库通信.唯一的问题是,在某些情况下,他们可能需要与区域管理器进行通信,以接收有关区域,玩家等的信息.

例如:玩家想要在区域内购买/出售/交易非玩家角色(NPC).区域通信线程需要向区域管理器线程询问玩家是否足够接近NPC进行交易才能进行交易.
我在这里遇到的问题是我计划使用node.js集群功能,并使用进程send()和on()方法来处理来回传递消息.除了我遇到过的一个警告之外,那没关系.由于所有与子程序分离的子进程cluster.fork()只能与"主"进程通信.node.js根进程成为所有通信的瓶颈.我使用一个脚本在我的系统上运行了一些基准测试,这个脚本只是使用集群的进程间通信(IPC)来回传递消息,并跟踪每秒执行的继电器数量.似乎最终节点在可以传输多少IPC的情况下以每秒约20k的速度出现.这个数字在Phenom II 1.8ghz四核笔记本电脑和FX-8350 4.0ghz 8核桌面上都是一致的.
现在这听起来相当高,除了这基本上意味着无论有多少个区域或通信线程,所有IPC仍然是通过单个进程的瓶颈,该进程充当整个应用程序的"中继".这意味着虽然看起来每个单独的线程每秒可以传输> 20k的IPC,但整个应用程序作为一个整体将永远不会传递更多,即使它是在一些疯狂的32核心系统上,因为所有通信都通过单个线程.
这就是我遇到的问题.现在进退两难.我已经阅读了很多关于其他各种选项的内容,并在这里阅读了关于这个主题的20个不同的问题,并且我已经看到一些事情经常出现:
Redis: 我实际上是在我的服务器上运行Redis并将其用作socket.io数据存储区,以便多个线程中的socket.io可以共享连接数据,以便用户可以连接到任意N个socket.io它们的区域的线程,因此服务器可以自动对传入的连接进行负载平衡.
我对此的关注是它贯穿网络堆栈.非常适合在同一服务器上的多个进程之间进行通信.从长远来看,我觉得延迟会成为一个主要问题.
0MQ(zeromq/zmq): 我之前从未使用过这个,但最近我听到了一些关于它的内容.根据我已经完成的阅读,我发现很多人将它与TCP套接字一起使用,但是有很多关于人们将它用于IPC的嗡嗡声.我希望也许有人在这之前使用0MQ for IPC(甚至可能在node.js中),并且可以为我提供一些关于此选项的信息.
dnode: 我再也没用过这个,但是从我看到的情况来看,这似乎是另一个设计用于TCP的选项,这意味着网络堆栈再次受到阻碍.
node-udpcomm: 有人在这里将另一个问题联系起来(不幸的是,我似乎再也找不到了).我从来没有听说过它,它看起来像一个非常小的解决方案,可以打开并监听UDP连接.虽然这可能仍然比TCP选项更快,但我们仍然拥有正确的网络堆栈?我绝对喜欢在我的"程序员区域"之外一英里,就像在这里,并进入网络/计算机架构的领域,我不太了解lol
无论如何,底线是我完全被困在这里,并且不知道在这种情况下IPC的最佳选择是什么.我现在假设0MQ是我上面列出的那个的最佳选择,因为它是唯一一个似乎为通信协议提供"IPC"选项的设备,我认为它意味着它使用的是UNIX套接字或其他东西.不通过网络堆栈,但我无法确认或任何事情.
我想我只是希望这里的一些人可能知道足够指出我正确的方向或告诉我,我已经走向那里了.我正在开发的项目是一款多人游戏服务器,旨在通过多人游戏客户端"开箱即用"工作,同时为Three.js提供3D图形/计算功能.一旦我将它们全部工作到令我满意的程度,客户端和服务器将成为开放源代码,我想确保架构尽可能地扩展,这样人们就不会在此基础上构建游戏,然后进行扩展起来并最终击中一堵墙.
无论如何,谢谢你的时间,如果你真的读了这一切:)
我认为0MQ将是一个非常好的选择,但我承认我不了解其他人:D
对于0MQ,您决定使用的传输是透明的,库调用是相同的.它只是在调用zmq_bind和zmq_connect开始时选择特定端点(以及传输).您可以决定采用以下四种途径:
"inproc://<id>" - 线程之间通过内存进行的进程间通信端点"ipc://<filepath>" - 依赖于系统的进程间通信端点"tcp://<ip-address>" - 清楚"pgm://..."或"epgm://..."- Pragmatic Reliable Multicast的端点简而言之,列表越高,越快,考虑到延迟和可靠性的问题就越少.所以你应该尽量保持高度.由于您的组件是进程,因此您应该自然地使用IPC传输.如果您以后需要更改某些内容,则只需更改端点定义即可.
现在,实际上比您选择的传输更重要的是套接字类型,或者您决定使用的模式.您的情况是典型的请求 - 响应类型的通信,因此您可以这样做
然后,线程将其套接字连接到分配给它们的单个Manager套接字,这就是所有,它们可以开始发送请求并等待响应.他们必须决定的是他们用作终点的路径.
但是要详细描述所有这些套接字类型和模式的含义绝对超出了本文的范围,但您可以而且应该在ZeroMQ指南中阅读更多相关信息.在那里,您不仅可以了解所有套接字类型,还可以了解如何连接组件并让它们相互通信的许多不同方法.我提到的那个只是一个非常简单的.理解后,您可以构建任意层次结构.这就像乐高;-)
希望它有所帮助,欢呼!