所以我想通过Node.js服务器使用Express、Mongoose和Multer的GridFS存储引擎上传大的CSV文件到mongoDB云数据库,但是当文件上传开始时,我的数据库就无法处理任何其他API请求**。例如,如果在文件上传时,不同的客户端请求从数据库获取用户,服务器会收到请求,并尝试从MongoDB云获取用户,但请求会被卡住,因为大文件上传会消耗掉所有的计算资源。因此,客户端执行的get请求将不会返回用户**,直到正在进行的文件上传完成。
我理解如果一个线程花了很长时间来执行回调(事件循环)或任务(Worker),那么它被认为是“阻塞”的,Node.js在事件循环中运行JavaScript代码,同时提供一个Worker Pool来处理昂贵的任务,如文件I/O。在任何给定时间与每个客户端关联的工作必须是“小的”,我的目标应该是最小化任务时间的变化**。这背后的原因是,如果一个Worker的当前任务比其他任务昂贵得多,它将无法处理其他挂起的任务,从而将工作者池的大小减1,直到任务完成。
换句话说,执行大文件上传的客户端正在执行一个昂贵的任务,这会降低Worker Pool的吞吐量,从而降低服务器的吞吐量。根据上述博客文章,当每个子任务完成时,它应该提交下一个子任务,当最后一个子任务完成时,它应该通知提交者。这样,在长任务(大文件上传)的每个子任务之间,Worker可以从一个较短的任务工作在一个子任务上,从而解决阻塞问题。
但我不知道如何在实际代码中实现这个方案,有没有具体的分区函数可以解决这个问题?我上传文件是否需要使用特定的上传架构或multi-gridfs-storage以外的节点包?请帮助
以下是我目前使用Multer的GridFS存储引擎的文件上传实现:
// Adjust how files get stored.
const storage = new GridFsStorage({
// The DB connection
db: globalConnection,
// The file's storage configurations.
file: (req, file) => {
...
// Return the file's data to the file property.
return fileData;
}
});
// Configure a strategy for uploading files.
const datasetUpload = multer({
// Set the storage strategy.
storage: storage,
// Set the size limits for uploading a file to 300MB.
limits: { fileSize: 1024 * 1024 * 300 },
// Set the file filter.
fileFilter: fileFilter,
});
// Upload a dataset file.
router.post('/add/dataset', async (req, res)=>{
// Begin the file upload.
datasetUpload.single('file')(req, res, function (err) {
// Get the parsed file from multer.
const file = req.file;
// Upload Success.
return res.status(200).send(file);
});
});
4条答案
按热度按时间kyks70gy1#
我认为这个问题是来源于
buffer
。因为buffer必须接收所有chunk,然后将整个buffer发送给consumer,所以缓冲需要很长时间。流可以解决这个问题,所以流允许我们在数据从源到达时立即处理数据,并做通过缓冲数据不可能做的事情然后一次性处理**。我在multer GitHub页面找到了storage.fromStream()
方法,并上传了一个122MB的文件进行测试,对我来说很有效,感谢Node.js流,每一个数据块在收到后都会被消耗并保存到云数据库中。上传的总时间不到1分钟,并且服务器可以在上载期间容易地响应其他请求。h6my8fg22#
所以经过几天的研究,我发现问题的根源不是Node.JS或我的文件上传实现。问题是MongoDB Atlas无法在处理文件上传工作负载的同时处理其他操作,例如从我的数据库中获取用户。正如我在问题帖子中所说,Node.js正在接收来自其他客户端的API调用,这是应该的,但是他们没有返回任何结果。我现在意识到这是因为他们在DB级别卡住了。一旦我切换到MongoDB的本地部署,问题就解决了。
根据this blog post about MongoDB Best Practices,相对于CPU数量的活动线程总数(即并发操作)会影响性能,因此会影响Node.js服务器的吞吐量。然而,我尝试使用最多8个vCPU的专用MongoDB集群(M50集群包),MongoDB Atlas仍然无法在处理其他客户端请求时上传文件。
如果有人使用云解决方案使其工作,我想知道更多。谢谢。
nkoocmlb3#
我也遇到了类似的问题,为了解决这个问题,我(以某种方式)为MongoDB实现了多个连接。
所以上传操作将由一个新的MongoDB连接处理,在上传过程中,您仍然可以使用另一个连接查询数据库。https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs
wwtsj6pe4#
你能管理架构/基础设施吗?如果是这样,这个挑战将通过不同的方法得到最好的解决。这实际上是无服务器解决方案的完美候选者,即Lambda。
Lambda不会在一台机器上并行运行任何请求。Lambda将一个请求分配给一台机器,直到请求完成,这台机器将不会接收任何其他流量。因此,您永远不会达到您现在遇到的限制。