我们最近已开始为其中一种应用程序使用 Typescript语言进行工作,在这种应用程序中,服务器和客户端之间应该进行队列通信。
为了实现队列通信,我们尝试将 ZeroMQ 库版本4.6.0用作npm软件包: npm install -g zeromq and npm install -g @types/zeromq
。
确切情况:
客户端将通过ZeroMQ向服务器发送数千条消息。反过来,服务器将根据来自客户端的每个传入消息响应一些确认消息。客户端将根据确认消息发送下一条消息。
使用的ZeroMQ模式:
ROUTER/DEALER
模式(我们不能使用任何其他模式)。
客户端代码:
import Zmq = require('zeromq');
let clientSocket : Zmq.Socket;
let messageQueue = [];
export class ZmqCommunicator
{
constructor(connString : string)
{
clientSocket = Zmq.socket('dealer');
clientSocket.connect(connString);
clientSocket.on('message', this.ReceiveMessage);
}
public ReceiveMessage = (msg) => {
var argl = arguments.length,
envelopes = Array.prototype.slice.call(arguments, 0, argl - 1),
payload = arguments[0];
var json = JSON.parse(msg.toString('utf8'));
if(json.type != "error" && json.type =='ack'){
if(messageQueue.length>0){
this.Dispatch(messageQueue.splice(0, 1)[0]);
}
}
public Dispatch(message) {
clientSocket.send(JSON.stringify(message));
}
public SendMessage(msg: Message, isHandshakeMessage : boolean){
// The if condition will be called only once for the first handshake message. For all other messages, the else condition will be called always.
if(isHandshakeMessage == true){
clientSocket.send(JSON.stringify(message));
}
else{
messageQueue.push(msg);
}
}
}
在服务器端,我们已经配置了 ROUTER
套接字。
上面的代码非常简单。 SendMessage()
函数实际上是为成千上万条消息调用的,并且代码可以成功运行,但会消耗大量内存。
问题:
由于 ZeroMQ 的行为是异步,因此客户端必须在有以下情况时等待回叫 ReceiveMessage()
将新消息发送到ZeroMQ ROUTER
(这在方法 Dispatch 的流程中很明显)。
基于我们对TypeScript的有限知识和对ZeroMQ与TypeScript的结合使用,问题在于,因为默认线程运行打字稿代码(该脚本会创建所需的1000余条消息并发送到 SendMessage()
)在发送第一条消息(本质上是握手消息)后继续执行(创建和发送更多消息),除非所有1000条以上的消息均已创建并发送到 SendMessage()
(不是发送数据,但由于我们要解释路由器套接字发送的确认消息而仅对数据排队,并且仅基于我们要发送下一条消息的确认),因此呼叫不会到达< strong> ReceiveMessage()
回调方法。
这就是说,只有在创建和调用ReceiveMessage()
的默认线程完成了1000条以上的消息之后,才调用 SendMessage()
,现在没有了还有其他任务可以做。
由于ZeroMQ不提供使用ROUTER/DEALER
发送/接收数据的任何同步机制,因此我们必须使用 messageQueue
对象按照上述代码利用队列
此机制将在内存中加载庞大的messageQueue
(带有1000多个消息),并且仅在默认线程最后到达 ReceiveMessage()
调用之后才出队。如果说我们有10000条甚至更多的消息要发送,情况只会变得更糟。
问题:
我们已经肯定了这种行为。因此,我们确信上面已经解释了理解。我们对TypeScript或ZeroMQ用法的理解是否有差距?
是否有像Typescript中的阻塞队列/大小限制数组这样的概念,它将在队列中接收有限的条目,并阻塞队列中的所有新添加内容,直到现有的添加到队列中为止(本质上适用于默认线程)暂停处理,直到调用回叫 ReceiveMessage()
时,这将使队列中的条目出队)?
是否有任何同步ZeroMQ方法(我们在C#的类似设置中使用了它,我们在ZeroMQ上合并并同步接收数据)。
在这种情况下,是否有人使用多线程?不确定Typescript是否在很大程度上支持多线程。
注意::我们在许多论坛上进行了搜索,但在任何地方都没有任何潜在客户。上面的描述可能在一个问题中有多个问题(违反stackoverflow论坛的规则);但是对我们来说,所有这些问题都与在Typescript中有效使用ZeroMQ相互关联。
期待从社区中获得一些线索。
答案 0 :(得分:0)
如果这是您第一次阅读有关ZeroMQ的文章,请先阅读5秒钟,以了解[ ZeroMQ hierarchy in less than a five seconds ]部分中的主要概念差异。
1)... 我们对或者/或者TypeScript或 ZeroMQ的使用情况有什么了解?
尽管我不能担任TypeScript部分的工作,但让我提及一些细节,这可能有助于您前进。虽然ZeroMQ主要是一种无代理的异步信号发送/消息框架,但它具有多种使用方式,并且存在一些工具来强制应用程序代码与ZeroMQ Context()
-instance之间的同步和异步合作。所有服务设计的基石。
本机API提供了一种方法,用于定义是否应阻止相应的调用,直到能够完成Context()
实例边界上的消息处理为止,或者相反,是否应遵循调用 ZMQ_DONTWAIT
,然后将控制异步返回给调用方,而与操作(完成)的操作无关。
作为其他技巧,人们可以选择配置 ZMQ_SND_HWM + ZMQ_RCV_HWM
和其他相关的.setsockopt()
选项,以满足特定的阻止/静默行为。
因为ZeroMQ 不提供任何发送/接收数据的同步机制
好吧,ZeroMQ API确实提供了对.send()/.recv()
方法的同步调用的方法,在该方法中,调用者被阻止,直到任何可行的消息可以从 Context()
引擎的控制范围。
很明显,TypeScript语言绑定/包装负责将这些本机API服务公开给您。
3)是否有任何同步ZeroMQ方法学(我们在C#的类似设置中使用了该方法,我们在ZeroMQ上合并并同步接收数据)?
是的,有几种这样的方法:
-如果未通过 ZMQ_DONTWAIT
标志指示,则本机API会阻塞,直到可以发送消息为止
-本机API提供了 Poller()
对象,如果给定 .poll()
作为{{1},则可以-1
}持续时间说明符,以等待所寻求的事件,阻塞呼叫者,直到任何此类事件出现并出现在long
实例中为止。
同样,TypeScript语言绑定/包装负责将这些本机API服务公开给您。
... 大内存消耗...
嗯,这可能表明资源管理不善。一旦分配了ZeroMQ消息,则在适当的情况下也应成为Poller()
-d。如果资源被系统性地释放并从内存中释放出来,请检查您的TypeScript代码和TypeScript语言绑定/包装器源。