【问题标题】:NodeJS Event Emitter Blocking IssueNodeJS 事件发射器阻塞问题
【发布时间】:2016-01-28 11:53:50
【问题描述】:

我有一个节点应用程序使用此处找到的 Node-ZMQ 绑定处理来自另一个应用程序的一些 ZeroMQ 事件:https://github.com/JustinTulloss/zeromq.node

我遇到的问题是某个事件的操作需要很长时间才能处理,这似乎会阻止在此期间处理任何其他事件。尽管应用程序当前没有集群,但这样做只会提供更多线程,并不能真正解决问题。我想知道是否有一种方法可以让这些异步调用在它们处理时不阻塞其他传入请求,以及如何实现它们。

这是我目前正在做的一个高度浓缩/人为的代码示例:

var zmq = require('zmq');
var zmqResponder = zmq.socket('rep');
var Client = require('node-rest-client').Client;
var client = new Client();

zmqResponder.on('message', function (msg, data) {
  var parsed = JSON.parse(msg);
  logging.info('ZMQ Request received: ' + parsed.event);
  switch (parsed.event) {
    case 'create':
        //Typically short running process, not an issue
    case 'update':
        //Long running process this is the issue
        serverRequest().then(function(response){
            zmqResponder.send(JSON.stringify(response));
        });
     }

});

function serverRequest(){
    var deferred = Q.defer();
      client.get(function (data, response) {
      if (response.statusCode !== 200) {
        deferred.reject(data.data);
      } else {
        deferred.resolve(data.data);
      }
  });
    return deferred.promise;
}

编辑** 这是代码的要点:https://gist.github.com/battlecow/cd0c2233e9f197ec0049

【问题讨论】:

  • 抱歉,这是做作,请允许我编辑。
  • 如果serverRequest() 是真正的异步,它不应该阻塞任何东西。
  • 老实说,这就是我的想法,但事实并非如此,我不确定如何最好地优化代码,或者我在哪里失误。
  • @Brian,您当前的示例是您的实际代码,还是只是一个人为的代码示例?因为您正在显示不会阻塞的完全异步 I/O。但是,如果您编写了任何 javascript,而不是 I/O 调用,而是在行 javascript,这需要很长时间才能执行,即使您异步调用它也会阻塞主事件循环(即即使它是在client.get() 调用中运行)。 See my answer here 了解更多信息。
  • 我想知道是否有可能某些 zmq 方法实际上是同步的,而不是异步的,例如 this line of code

标签: javascript node.js zeromq


【解决方案1】:

我认为,通过评论线程,我已经确定了您的问题。 REQ/REP 有严格的同步消息顺序保证...您必须接收-发送-接收-发送-等等。 REQ 必须以发送开头,REP 必须以接收开头。因此,您一次只处理一条消息,因为您选择的套接字类型强制执行该操作。

如果您使用的是不同的、非事件驱动的语言,当您尝试连续两次发送或接收时,您可能会收到一条错误消息,告诉您您做错了什么,但 node 允许您这样做并且只是将后续消息排队,直到轮到它们按消息顺序。

您想将REQ/REP 更改为DEALER/ROUTER,它会按您期望的方式工作。您必须稍微更改 ROUTER 套接字的逻辑才能使其正确发送,但其他一切都应该相同。


粗略的示例代码,使用已发布要点的相关部分:

var zmqResponder = zmq.socket('router');

zmqResponder.on('message', function (msg, data) {
    var peer_id = msg[0];
    var parsed = JSON.parse(msg[1]);
    switch (parsed.event) {
        case 'create':
            // build parsedResponse, then...
            zmqResponder.send([peer_id, JSON.stringify(parsedResponse)]);
            break;
    }
});

zmqResponder.bind('tcp://*:5668', function (err) {
    if (err) {
        logging.error(err);
    } else {
        logging.info("ZMQ awaiting orders on port 5668");
    }
});

...您需要获取peer_id(或任何您想称呼它的名称,在 ZMQ 命名法中,它是您发送的套接字的套接字 ID,将其视为某种“地址”)从您收到的消息的第一帧开始,然后将其用作您发回的消息的第一帧。

顺便说一句,我刚刚注意到你的主旨是connect()-ing 和 bind()-ing 在同一个套接字上(分别是 zmq.js 第 52 和 143 行)。不要那样做。从其他线索推断,你只是想bind()在这个过程中。

【讨论】:

  • 你有一些示例代码吗?我很难通过 zmq 文档上的示例来弄清楚这个模型。试图让我的第二个要点发挥作用。
  • 用示例更新答案
猜你喜欢
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-27
相关资源
最近更新 更多