首页 > 解决方案 > 我们正面临 Nodejs 响应时间问题

问题描述

当我们达到大约 100 个在线用户时,我们正面临 Nodejs 响应时间问题,我们的响应时间达到 10 秒。我认为有一个混乱的代码使我的应用程序运行缓慢。有没有办法在我的 nodejs 应用程序上追踪问题(在我的应用程序变慢的女巫代码上)?我正在使用 nodejs、expressjs、mongodb 和 nginx

NGINX:

upstream http_backend {
   server 127.0.0.1:8087;
   keepalive 32;
}

server {
    listen 80;
    listen [::]:80;
    server_name  cdn.amjilt.com;
    return 301 https://$server_name$request_uri;
}
server {
    listen 7070;
    listen [::]:7070;
    server_name  cdn.amjilt.com;
    return 301 https://$server_name$request_uri;
}


server {
    listen       443 ssl http2 default_server;
    listen       [::]:443 ssl http2 default_server;
    server_name  cdn.amjilt.com;

    ssl on;
    ssl_certificate /etc/nginx/cert/media/media.crt;
    ssl_certificate_key /etc/nginx/cert/media/media.key;

    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    client_max_body_size 500M;
    client_body_buffer_size 500M;
    proxy_buffer_size   16M;
    proxy_buffers   24 8M;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;

    location /images{
            root /home/ubuntu/projects/amjilt_media/static;
    }
    location /tmp{
            root /home/ubuntu/projects/amjilt_media/static;
    }
    location /images/uploads{
            root /home/ubuntu/projects/amjilt_media/static;
    }
    location /images/avatar{
            root /home/ubuntu/projects/amjilt_media/static;
    }
    location /api/video/show{
            expires off;
            proxy_buffering off;
            chunked_transfer_encoding on;
            proxy_pass http://http_backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
    }
    location /api/video/mobile{
            expires off;
            proxy_buffering off;
            chunked_transfer_encoding on;
            proxy_pass http://http_backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
    }
    location /api/pdf/show{
            expires off;
            proxy_buffering off;
            chunked_transfer_encoding on;
            proxy_pass http://http_backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
    }
    location / {
            proxy_pass http://localhost:8087;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
    }

    # gzip
    gzip_types text/css text/less text/plain text/xml application/xml application/json application/javascript;
    gzip on;
}

路由器:

let flname = '../../..' + video.path;
var file = path.resolve(__dirname, flname);
fs.stat(file, function(err, stats) {
    if (err) {
        winston.error('/video/show/:id fs.stat error ',err);
        if (err.code === 'ENOENT') {
            // 404 Error if file not found
            res.status(404).json({msg: 'log.n_request'});
        }
        res.status(404).json({msg: 'log.n_request'});
    }
    var range = req.headers.range;
    if (!range) {
        var stat_ = fs.statSync(file)
        var header = {
            'Content-Length': stat_.size,
            'Content-Type': (!req.useragent.isSafari ? token : 'mp4'),
        }
        res.writeHead(200, header)
        var stream = fs.createReadStream(file)
            .on("open", function () {
                stream.pipe(res);
            }).on("error", function (err) {
                res.end(err);
            });
    }else{
        var positions = range.replace(/bytes=/, "").split("-");
        var start = parseInt(positions[0]);
        if(isNaN(start)){
            start = 0;
        }
        var total = stats.size;
        var end = positions[1] ? parseInt(positions[1]) : (start+102400);
        if(isNaN(end)){
            end = start+102400;
        }
        if(total <= end){
            end = total-1;
        }
        var chunksize = (end - start) + 1;

        res.writeHead(206, {
            "Content-Range": "bytes " + start + "-" + end + "/" + total,
            "Accept-Ranges": "bytes",
            "Content-Length": chunksize,
            "Content-Type": "video/mp4"
        });

        var stream = fs.createReadStream(file, {start: start, end: end})
            .on("open", function () {
                stream.pipe(res);
            }).on("error", function (err) {
                res.end(err);
            });
    }
});

标签: node.jsmongodbexpressnginx

解决方案


您必须删除fs.statSync(). 这会阻塞事件循环,因此您的服务器每次运行时都会一次处理一个请求。而且,事实证明,您可以完全删除调用,因为您已经fs.stat()在函数的前面调用了同一个文件并且可以使用这些结果。

我还在发送错误后添加了几个返回语句,因为您不希望在发送错误后执行其余代码:

let flname = '../../..' + video.path;
var file = path.resolve(__dirname, flname);
fs.stat(file, function(err, stats) {
    if (err) {
        winston.error('/video/show/:id fs.stat error ',err);
        if (err.code === 'ENOENT') {
            // 404 Error if file not found
            res.status(404).json({msg: 'log.n_request'});
            return;
        }
        res.status(404).json({msg: 'log.n_request'});
        return;
    }
    var range = req.headers.range;
    if (!range) {
        var header = {
            'Content-Length': stats.size,
            'Content-Type': (!req.useragent.isSafari ? token : 'mp4'),
        }
        res.writeHead(200, header)
        var stream = fs.createReadStream(file)
            .on("open", function () {
                stream.pipe(res);
            }).on("error", function (err) {
                res.end(err);
            });
    }else{
        var positions = range.replace(/bytes=/, "").split("-");
        var start = parseInt(positions[0]);
        if(isNaN(start)){
            start = 0;
        }
        var total = stats.size;
        var end = positions[1] ? parseInt(positions[1]) : (start+102400);
        if(isNaN(end)){
            end = start+102400;
        }
        if(total <= end){
            end = total-1;
        }
        var chunksize = (end - start) + 1;

        res.writeHead(206, {
            "Content-Range": "bytes " + start + "-" + end + "/" + total,
            "Accept-Ranges": "bytes",
            "Content-Length": chunksize,
            "Content-Type": "video/mp4"
        });

        var stream = fs.createReadStream(file, {start: start, end: end})
            .on("open", function () {
                stream.pipe(res);
            }).on("error", function (err) {
                res.end(err);
            });
     }
});

推荐阅读