使用Express路由的NodeJS RabbitMQ

6
My server is using NodeJS and the amqplib api to retrieve data from another application. Although the NodeJS server can successfully receive information, there seems to be a noticeable delay. I am currently exploring whether there is a more efficient way to handle this process, particularly in terms of opening and closing connections. Project Layout There are two controller files, request.img.server.controller.js and receive.img.server.controller.js, that manage data retrieval and reception respectively. The methods in these controllers are called by the routes file, oct.server.routes.js, when a button on the frontend is clicked.

request.img.server.controller.js

'use strict';

var amqp = require('amqplib/callback_api');
var connReady = false;
var conn, ch;
amqp.connect('amqp://localhost:5672', function(err, connection) {
    conn = connection;
    connReady = true;
    conn.createChannel(function(err, channel) {
        ch = channel;
    });
});


exports.sendRequest = function(message) {
    console.log('sending request');

    if(connReady) {
        var ex = '';
        var key = 'utils';

        ch.publish(ex, key, new Buffer(message));
        console.log(" [x] Sent %s: '%s'", key, message);
    }
};

receive.img.server.controller.js

var amqp = require('amqplib/callback_api');
var fs = require('fs');
var wstream = fs.createWriteStream('C:\\Users\\yako\\desktop\\binarytest.txt');

var image, rows, cols;
exports.getResponse = function(resCallback) {
    amqp.connect('amqp://localhost:5672', function(err, conn) {
        conn.createChannel(function(err, ch) {
            var ex = '';

            ch.assertQueue('server', {}, function(err, q) {
                console.log('waiting for images');
                var d = new Date();
                var n = d.getTime();
                ch.consume(q.queue, function(msg) {
                    console.log(" [x] %s: '%s'", msg.fields.routingKey, msg.content.toJSON());
                    rows = msg.content.readInt16LE(0);
                    cols = msg.content.readInt16LE(2);
                    console.log("rows = %s", msg.content.readInt16LE(0));
                    console.log("cols = %s", msg.content.readInt16LE(2));
                    image = msg.content;
                    var currMax = 0;
                    for (var i = 4; i < image.length; i+=2) {
                        if (image.readInt16LE(i) > currMax) {
                            currMax = image.readInt16LE(i);
                        }
                        wstream.write(image.readInt16LE(i) + ',');
                    }
                    console.log('done writing max is', currMax);
                    //console.log(image);
                    resCallback(rows, cols, image);
                }, {
                    noAck: true
                });
            });
        });
    });
};

oct.server.routes.js

'use strict';

module.exports = function(app) {
    var request_img = require('../../app/controllers/image-tools/request.img.server.controller.js');
    var receive_img = require('../../app/controllers/image-tools/receive.img.server.controller.js');

    // oct routes
    app.get('/load_slice', function(req, res) {
        console.log('load slice hit');
        receive_img.getResponse(function (rows, cols, image) {
            res.end(image);
        });
        request_img.sendRequest('123:C:\\Users\\yako\\Documents\\Developer\\medicaldiag\\test_files\\RUS-01-035-09M-21.oct');
    });
};
1个回答

15

你打开连接的方式有问题,这至少是性能问题的一部分原因。

连接的开启代价很高。它们在客户端和RabbitMQ服务器之间的TCP/IP端口上开启了一个新的 TCP/IP 连接。这需要时间,并且消耗了客户端和服务器的有限资源。

因此,应该在每个node.js进程内创建并使用单个与RabbitMQ的连接。这个连接应该被所有代码共享。

每当你需要使用 RabbitMQ 时,在共享的连接上打开一个新的通道并进行工作。通道便宜,并且应该在连接内根据需要打开和关闭。

更具体地说,在你的代码中,`receive.img.server.controller.js` 文件是主要问题。每次调用 `getResponse` 方法时,它都会打开一个新的 RabbitMQ 连接。

如果有10个用户访问网站,当1个足以时,你将有10个打开的 RabbitMQ 连接。如果有成千上万的用户访问网站,那么当1个足以时,你将有数千个打开的 RabbitMQ 连接。你还会冒充耗尽RabbitMQ服务器或客户端可用的TCP/IP连接的风险。

`receive.img.server.controller.js` 应该像 `request.img.server.controller.js` 一样,始终只开启一个连接,并重复使用。


此外,对于RabbitMQ与node.js,我建议使用wascally库。该库基于amqplib,但会让事情变得更容易。它会为你管理一个连接,并使发送和接收消息更容易。

我还提供一些有关RabbitMQ和node.js的培训材料,涵盖了amqplib的基础知识,然后进入使用wascally进行真实应用开发的内容。


1
优秀的回答。跟进问题:如果每个用户都会请求多张图片,那么为每个用户保持一个通道是否更好? - Daniel Kobe
另外,我在打开连接后应该关闭它吗? - Daniel Kobe
Q1:每条消息生产者(交换机)和每条消息消费者(队列)的通道是更常见的方法。它可能最终会变成每个用户一个通道,但我会把它看作“我正在发布到这个交换机,所以我需要一个通道”和“我正在从这个队列消费,所以我需要一个通道”。 - Derick Bailey
1
Q2: 当Node.js进程启动时,立即打开连接。保持相同的连接永远处于打开状态。在关闭Node.js进程之前,请不要关闭它。 - Derick Bailey
其他情况变得更加复杂,涉及到消息生产者也是消费者的情况——为状态更新拥有一个特定的队列,并基于原始消息的生产者将消息路由到该队列。 - Derick Bailey
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接