因此,我想使用 Express、Mongoose 和 Multer 的 GridFS 存盤引擎使用 Node.js 服務器將大型 CSV 檔案上傳到 mongoDB 云資料庫,但是當檔案上傳開始時,我的資料庫變得無法處理任何其他 API 請求。例如,如果在上傳檔案時,另一個客戶端請求從資料庫中獲取用戶,服務器將收到請求并嘗試從 MongoDB 云中獲取用戶,但由于檔案上傳大,請求會卡住吃掉所有的計算資源。因此,客戶端執行的get請求將不會回傳用戶,直到正在進行的檔案上傳完成。
我知道如果一個執行緒需要很長時間來執行回呼(事件回圈)或任務(作業人員),那么它被認為是“阻塞的”,并且 Node.js 在提供作業人員的同時在事件回圈中運行 JavaScript 代碼用于處理檔案 I/O 等昂貴任務的池。我在NodeJs.org 的這篇博客文章中讀到,為了讓您的 Node.js 服務器保持快速,在任何給定時間與每個客戶端相關的作業都必須是“小”的,我的目標應該是盡量減少任務次數。這樣做的原因是,如果 Worker 的當前 Task 比其他 Task 昂貴得多,它將無法處理其他待處理的 Task,從而將 Worker Pool 的大小減一,直到 Task 完成。
換句話說,執行大檔案上傳的客戶端正在執行一個昂貴的任務,這會降低 Worker Pool 的吞吐量,進而降低服務器的吞吐量。根據前面的博文,當每個子任務完成時,它應該提交下一個子任務,當最后一個子任務完成時,它應該通知提交者。這樣,在長任務(大檔案上傳)的每個子任務之間,Worker 可以從一個較短的 Task 處理一個子任務,從而解決阻塞問題。
但是,我不知道如何在實際代碼中實作此解決方案。是否有任何特定的磁區函式可以解決這個問題?我是否必須使用 multer-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);
});
});
uj5u.com熱心網友回復:
我認為這個問題源于buffer. 因為緩沖區必須接收所有塊,然后將整個緩沖區發送給消費者,所以緩沖需要很長時間。Streams可以解決這個問題,因此 Streams 允許我們在資料從源頭到達時立即對其進行處理,并完成通過緩沖資料和一次處理所有資料不可能完成的事情。我在 multer GitHub 頁面上找到了方法,并通過上傳122 MB 檔案對其進行了測驗,它對我有用,這要歸功于 Node.js 流,每塊資料都會在收到后立即被消耗并保存到云資料庫中。上傳總時間少于storage.fromStream()1分鐘,上傳程序中服務器可以輕松回應其他請求。
const {GridFsStorage} = require('multer-gridfs-storage');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const express = require('express');
const fs = require('fs');
const connectDb = require('./connect');
const app = express();
const storage = new GridFsStorage({db:connectDb()});
app.post('/profile', upload.single('file'), function (req, res, next) {
const {file} = req;
const stream = fs.createReadStream(file.path); //creates stream
storage.fromStream(stream, req, file)
.then(() => res.send('File uploaded')) //saves data as binary to cloud db
.catch(() => res.status(500).send('error'));
});
app.get('/profile',(req,res)=>{
res.send("hello");
})
app.listen(5000);
uj5u.com熱心網友回復:
所以經過幾天的研究,我發現問題的根源不是 Node.JS 或我的檔案上傳實作。問題是 MongoDB Atlas 無法同時處理檔案上傳作業負載以及其他操作,例如從我的資料庫中獲取用戶。正如我在問題帖子中所述,Node.js 正在接收來自其他客戶端的 API 呼叫,但它們沒有回傳任何結果。我現在意識到那是因為他們被困在了資料庫級別。一旦我切換到 MongoDB 的本地部署,問題就解決了。
根據這篇關于 MongoDB 最佳實踐的博客文章,活動執行緒的總數(即并發操作)相對于 CPU 的數量會影響性能,從而影響 Node.js 服務器的吞吐量。但是,我嘗試使用具有多達 8 個 vCPU(M50 集群包)的專用 MongoDB 集群,而 MongoDB Atlas 在處理其他客戶端請求時仍然無法上傳檔案。
如果有人讓它與云解決方案一起作業,我想知道更多。謝謝你。
uj5u.com熱心網友回復:
你能管理架構/基礎設施嗎?如果是這樣,這個挑戰最好通過不同的方法來解決。這實際上是無服務器解決方案的完美候選者,即 Lambda。
Lambda 不會在一臺機器上并行運行任何請求。Lambda 將一個請求分配給一臺機器,直到請求完成,這臺機器將不會收到任何其他流量。因此,您將永遠不會達到您現在遇到的限制。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/476878.html
下一篇:我們如何從檔案的行中讀取浮點值?
