节点服务器异步调用后端服务

时间:2017-04-18 09:28:49

标签: javascript node.js asynchronous axios event-loop

我是Node的新手,我正在编写我的第一个节点服务器。它应该在调用后端休息服务后用简单的页面回答一个简单的get请求。

我使用express来管理请求和axios包来发出后端请求。问题是服务器阻塞了事件循环,我在理解如何异步调用后端时遇到了问题。

截至目前,前端服务器一次只能管理一个请求!我希望如果后端服务每次都需要10秒钟才能回答,前端服务器可以在10秒内回答两个并发请求,而不是20秒。

我哪里错了?

以下是前端节点代码的摘录:

app.get('/', function(req, res) {

      //Making the call to the backend service. This should be asynchronous...
      axios.post(env.get("BACKEND_SERVICE"), 
      { "user": "some kind of input"})
        .then(function(response){

        //do somenthing with the data returned from the backend...

        res.render('homepage');
        })
    }

这里是后端节点代码的提取和提取:

app.post('/api/getTypes', jsonParser, function (req, res) {

      console.log("> API request for 'api/getTypes' SLEEP");
      var now = new Date().getTime();
      while(new Date().getTime() < now + 10000){ /* do nothing */ }
      console.log("> API request for 'api/getTypes' WAKE-UP");

      res.json({"types":"1"});
    }

1 个答案:

答案 0 :(得分:1)

问题是你的忙碌等待绑定了后端服务器,以至于它甚至无法开始处理第二个请求。

我假设您正在尝试模拟获取类型的过程需要一段时间。您可能正在做的事情是将异类和I / O绑定(读取文件,查询数据库等)。要模拟它,只需使用setTimeout

app.post('/api/getTypes', jsonParser, function (req, res) {

  console.log("> API request for 'api/getTypes' SLEEP");
  setTimeout(function() {
      console.log("> API request for 'api/getTypes' WAKE-UP");
      res.json({"types":"1"});
  }, 10000);
});

这可以避免占用后端服务器的唯一线程,让它可以自由地开始重复处理第二个(第三个,第四个......)请求。

这是Node的关键原则之一:如果你避开它,不要同步做事。 :-)这就是为什么API是如此异步的。

如果你确实发现你需要做大量CPU烧录运算来处理请求,你可能会将其作为服务器的子进程而不是在服务器进程中进行。节点是单线程设计,通过强调异步I / O实现了非常高的吞吐量。这对你需要做的大部分工作都很有用......直到它没有。 : - )

重新评论:

  

后端进程将使用节点以外的其他技术编写,它将调用数据库,可能需要一段时间。我写了那个简单的节点休息服务来模拟它。我想了解的是,如果后端需要时间来处理请求,前端服务器将如何反应。

在处理请求和占用唯一的服务器线程忙等待(或执行大量CPU繁重工作)之间存在很大差异。你忙碌的等待模型正在做大量繁重的CPU工作,但是如果获取类型将是Node的外部,你就不会忙于等待它,你将排队回调异步完成(等待来自子进程的I / O,或来自连接到第三个服务器进程的套接字的I / O,或等待来自DB的I / O等)。因此,上面的setTimeout示例是您正在做的事情的更好模型。

忙碌等待使前端无法完成,因为它是这样的:

                               Backend
Time    Frontend                Queue                        Backend
−−−−    −−−−−−−−−−         −−−−−−−−−−−−−−−−−−−−−        −−−−−−−−−−−−−−−−−−−−−
0 sec   Request #1  −−−−−−> Receive request #1   −−−−−> Pick up job for request #1
0 sec   Request #1  −−−−−−> Receive request #2
                                                        Busy wait 10 seconds
10 sec  Got #1 back <−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Send response #1
                                                 −−−−−> Pick up job for request #2
                                                        Busy wait 10 seconds
20 sec  Got #2 back <−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Send response #2

所以即使前端没有忙碌等待,它也会看到20秒,因为后端忙于等待(无法做任何其他事情)10秒钟。

但这不是你真正的设置会做什么,除非你使用的其他技术也是单线程的。 (如果是,您可能希望不止一个并行运行。)