Nodejs关于Http模块疑惑

Nodejs关于Http模块疑惑

我创建了一个http服务端,在接收请求函数中查找数据库里面的数据,将数据传回给客户端,当另外一个请求来临时,他要等到前面那个请求查找完数据返回客户端后,才能执行。如何解决该问题,是否要创建子进程去处理数据查询。

9 回复

当然可以!你提到的问题主要是关于如何在 Node.js 中处理并发请求,特别是当你需要从数据库中查询数据并返回结果时。默认情况下,Node.js 是单线程的,这意味着如果一个请求正在处理耗时操作(如数据库查询),其他请求会被阻塞直到当前请求完成。

为了解决这个问题,你可以采用几种不同的方法:

  1. 使用异步操作:确保你的数据库查询是异步的,这样不会阻塞事件循环。
  2. 使用连接池:如果你使用的是关系型数据库(如 MySQL 或 PostgreSQL),可以考虑使用数据库连接池来管理数据库连接。
  3. 使用多进程或多线程:虽然不常见,但如果你的应用非常复杂且性能要求很高,可以考虑使用子进程来处理数据库查询。

示例代码

假设你使用的是 Express 框架和 MongoDB 数据库,这里是一个简单的示例:

const express = require('express');
const MongoClient = require('mongodb').MongoClient;

const app = express();
const url = 'mongodb://localhost:27017';
const dbName = 'myproject';

app.get('/data', async (req, res) => {
    try {
        const client = await MongoClient.connect(url);
        const db = client.db(dbName);

        // 异步查询数据库
        const data = await db.collection('mycollection').findOne({});

        res.json(data);
        client.close();
    } catch (err) {
        console.error(err);
        res.status(500).send('Internal Server Error');
    }
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

解释

  • 异步查询:通过 await 关键字确保数据库查询是非阻塞的。这允许其他请求在同一时间被处理。
  • 连接管理:每次请求时打开和关闭数据库连接。对于生产环境,建议使用数据库连接池来管理连接,以提高性能和资源利用率。

使用连接池

如果你使用的是 MongoDB,可以考虑使用 mongodb 库的连接池功能。例如:

const { MongoClient } = require('mongodb');

const uri = 'mongodb+srv://<username>:<password>@cluster0.mongodb.net/test?retryWrites=true&w=majority';
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });

async function run() {
    try {
        await client.connect();
        const database = client.db('myproject');
        const collection = database.collection('mycollection');

        app.get('/data', async (req, res) => {
            const data = await collection.findOne({});
            res.json(data);
        });
    } finally {
        await client.close();
    }
}

run().catch(console.dir);

这种方法可以更好地管理连接,并且更高效地处理多个并发请求。

希望这些示例能帮助你理解如何在 Node.js 中处理并发请求。如果你有更多具体需求或问题,请随时告诉我!


  1. 用的什么数据库客户端?它只支持同步模式?
  2. 如果支持异步模式。那么与数据库的连接数多少,是否只有1;查询数据量大不大?如果以上皆是,增加连接数。

用oracle,数据库的数据是亿级的,异步了也没用,还是要等待数据返回给客户端,另外一个请求才能获得请求,就像我们在http响应函数里面,计算一个长时间的计算一样。有什么好的办法吗,用child_process的话,几个请求就把CPU的用光了

数据库调试(tuning)有问题吧。亿级的数据库响应也要快。Goolge,Facebook 的数据量超亿级,响应有多快。

如楼上童鞋所言,楼主的问题在于数据库优化这块。

  1. 用node.js哪个oracle客户端,请明确写出来。如果路过的童鞋有相关使用经验,就能提出一些更具体的建议,不是吗。
  2. 首先请确认sql查询语句的执行效率,在pl/sql developer之类的oracle客户端跑一次sql语句。如果比较耗时,下面该干什么就不必说了。
  3. 开个网络抓包/监视工具之类,在http请求的过程中,监视与oracle数据库的连接数有多少,如果自始至终只有1,那么就如说过的,增加连接数。为什么一直强调连接数?因为连接数只有1的情况下,确实有可能阻塞。有数据库的地方,就有必要使用连接池来控制连接数。

另外,建议把sql查询、发起查询的伪代码(去掉业务逻辑!)贴出来。所谓旁观者清,当局者迷。

目测连接池的问题哈哈,肯定是程序有问题啦,

var oracle = require(‘oracle_bindings.node’); var oracleOperator = new oracle.OracleClient();

module.exports = function(app){ app.get(’/locate’,function(req,res){ try{

        console.log('begin');
        var sql = 'select * from xx';
    oracleOperator.connect('xx','xx','xx',function(error,conn){
        if(error){

        }
        else{  //查询在PLSQL也要4 秒多
            conn.query(sql,function(err,result){
                for(var i=0; i &lt; result.length;i++){
                    console.log(result[i]);
                }

                res.send('locate');

            });
        }

    });

}catch(e){
    console.log(e);

}finally{


}

});

}

  1. pl/sql中执行查询需时4s+,考虑在相关的检索字段上设置索引吧,不过这与本帖的问题主旨无关。
  2. nodejs连接oracle的客户端模块,看来楼主是自家开发的(访问oracle的nodejs插件,目前支持windows)。结合给出的代码片段-conn没有close,就是说conn由底层的c++来维护,那么这个conn能建立多少个呢。如果只支持单连接,请考虑改进此oracle模块,支持多连接吧。单一连接同一时间只能执行一个查询,要并行执行2个查询,就得建立2个数据库连接。这也就是为什么child_process就能同时执行n个查询,因为oracle客户端模块实例化n个,可用的数据库连接也有n个。 另外conn执行查询的部分,估计也是同步执行的,在查询结束前,程序流程被卡住了?
  3. 换用其他oracle模块nearinfinity/node-oracle / mariano/node-db-oracle。做个对比,对自家模块的开发也是有好处的,闭门造车不可取。

在Node.js中,HTTP模块是单线程模型,这意味着每个请求都会在一个事件循环中顺序处理。如果你希望在接收到一个请求时不会阻塞其他请求的处理,可以通过异步操作来实现,而不是创建子进程。

示例代码

你可以使用Promises或者async/await来处理异步查询,这样不会阻塞其他请求的处理。

const http = require('http');
const db = require('./db'); // 假设这是你的数据库模块

const server = http.createServer(async (req, res) => {
    try {
        const data = await db.query(req.url); // 假设这是查询数据库的方法
        res.writeHead(200, {'Content-Type': 'application/json'});
        res.end(JSON.stringify(data));
    } catch (error) {
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.end('Internal Server Error');
    }
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

解释

  1. 异步查询:通过await关键字等待数据库查询完成,这样当前请求不会阻塞其他请求。
  2. 错误处理:使用try...catch来捕获并处理可能发生的异常。
  3. 并发处理:由于Node.js的非阻塞性质,即使你在处理一个请求,其他请求也可以被接受和处理。

不需要创建子进程

除非你的查询非常耗时且频繁,导致CPU或内存资源瓶颈,否则通常不需要创建子进程。创建子进程会增加复杂性和资源消耗,而且Node.js本身已经很好地支持了异步和并发处理。

如果你确实遇到性能瓶颈,可以考虑使用数据库连接池或者优化查询逻辑,而不是直接创建子进程。

回到顶部