Во-первых, вы никогда не захотите использовать fs.writefileSync()
при обработке запросов в реальном времени, потому что это блокирует весь цикл событий node.js до тех пор, пока не будет завершена запись в файл.
OK, основываясь на записи каждого блокаданных в другой файл, то вы хотите разрешить одновременную запись нескольких дисков, но не неограниченную запись на диск.Таким образом, все еще уместно использовать очередь, но на этот раз очередь не просто выполняет одну запись за раз, она имеет некоторое количество записей одновременно:
const EventEmitter = require('events');
class Queue extends EventEmitter {
constructor(basePath, baseIndex, concurrent = 5) {
this.q = [];
this.paused = false;
this.inFlightCntr = 0;
this.fileCntr = baseIndex;
this.maxConcurrent = concurrent;
}
// add item to the queue and write (if not already writing)
add(data) {
this.q.push(data);
write();
}
// write next block from the queue (if not already writing)
write() {
while (!paused && this.q.length && this.inFlightCntr < this.maxConcurrent) {
this.inFlightCntr++;
let buf = this.q.shift();
try {
fs.writeFile(basePath + this.fileCntr++, buf, err => {
this.inFlightCntr--;
if (err) {
this.err(err);
} else {
// write more data
this.write();
}
});
} catch(e) {
this.err(e);
}
}
}
err(e) {
this.pause();
this.emit('error', e)
}
pause() {
this.paused = true;
}
resume() {
this.paused = false;
this.write();
}
}
let q = new Queue("file-", 0, 5);
// This fires 30 times/sec and runs for 30-45 min
dataSender.on('gotData', function(data){
q.add(data);
}
q.on('error', function(e) {
// go some sort of write error here
console.log(e);
});
Что нужно учесть:
Поэкспериментируйте со значением concurrent
, которое вы передадите в конструктор Queue.Начните со значения 5. Затем посмотрите, увеличивает ли это значение более высокую или худшую производительность.Подсистема ввода / вывода файла node.js использует пул потоков для реализации асинхронных операций записи на диск, поэтому существует максимальное количество одновременных записей, что позволит очень быстро увеличить число одновременных записей, вероятно, не заставит дела идти быстрее.
Вы можете поэкспериментировать с увеличением размера пула потоков ввода-вывода, установив переменную среды UV_THREADPOOL_SIZE
перед запуском приложения node.js.
Ваш самый большой друг здесь скорость записи на диск .Итак, убедитесь, что у вас быстрый диск с хорошим контроллером диска.Лучше было бы использовать быстрый SSD на быстрой шине.
Если вы можете распределить записи по нескольким реальным физическим дискам, это, вероятно, также увеличит пропускную способность записи (больше дисковых головок в работе).
Это предварительный ответ, основанный на первоначальной интерпретации вопроса (перед редактированием, которое изменило его).
Поскольку, как представляется, вам необходимо выполнитьваш диск записывает по порядку (все в один и тот же файл), тогда я бы посоветовал вам либо использовать поток записи, и позволить объекту потока сериализовать и кэшировать данные для вас, либо вы можете создать очередь самостоятельно, например так:
const EventEmitter = require('events');
class Queue extends EventEmitter {
// takes an already opened file handle
constructor(fileHandle) {
this.f = fileHandle;
this.q = [];
this.nowWriting = false;
this.paused = false;
}
// add item to the queue and write (if not already writing)
add(data) {
this.q.push(data);
write();
}
// write next block from the queue (if not already writing)
write() {
if (!nowWriting && !paused && this.q.length) {
this.nowWriting = true;
let buf = this.q.shift();
fs.write(this.f, buf, (err, bytesWritten) => {
this.nowWriting = false;
if (err) {
this.pause();
this.emit('error', err);
} else {
// write next block
this.write();
}
});
}
}
pause() {
this.paused = true;
}
resume() {
this.paused = false;
this.write();
}
}
// pass an already opened file handle
let q = new Queue(fileHandle);
// This fires 30 times/sec and runs for 30-45 min
dataSender.on('gotData', function(data){
q.add(data);
}
q.on('error', function(err) {
// got disk write error here
});
Вы можете использовать writeStream вместо этого пользовательского класса Queue, но проблема в том, что writeStream может заполниться, и тогда вам потребуется отдельный буфер в качестве места для размещенияданные в любом случае.Использование собственной настраиваемой очереди, как указано выше, решает обе проблемы одновременно.
Другие комментарии о масштабируемости / производительности
Поскольку вы, кажется, пишетеЕсли данные последовательно поступают в один и тот же файл, запись на диск не принесет пользы от кластеризации или параллельного выполнения нескольких операций, поскольку они в основном должны быть сериализованы.
Если на вашем сервере node.js естькроме выполнения этих операций записи, может быть небольшое преимущество (должно быть проверено тестированием) для создания второго процесса node.js и выполнения всей записи на диск в этом другом процессе.Ваш основной процесс node.js получит данные, а затем передаст их дочернему процессу, который будет поддерживать очередь и выполнять запись.
Еще одна вещь, с которой вы можете поэкспериментировать, - это объединение записей.Если в очереди более одного элемента, вы можете объединить их в одну запись.Если записи уже имеют значительный размер, это, вероятно, не имеет большого значения, но если записи были небольшими, это могло бы иметь большое значение (объединение большого количества записей на маленький диск в одну большую запись обычно более эффективно).
Ваш самый большой друг здесь скорость записи на диск .Итак, убедитесь, что у вас быстрый диск с хорошим контроллером диска.Лучше бы быстрый SSD.