Главная проблема javascript это то что он однопоточный. Эта же проблема есть и в приложения написанных на NodeJS.
Итак нам понадобится:
- виртуальная машина с Windows Server 2012 или выше
- установленная IIS
- приложение на NodeJS (в примере будет использоваться фреймворк Express)
- и «магия»
Инструкцию по установке Windows и настройке IIS описывать не буду, это можно найти в интернете. Приступаем сразу к запуску NodeJS приложения.
Краткая предыстория
Имеется проект написанный на NodeJS, которому требуется обрабатывать большие JSON файлы (около 100-200 клиентских приложений, которые передаю и принимают файлы объемом 40-80 Мб). В один момент времени может возникнуть ситуация, когда несколько пользователей одновременно сделают запрос. И в это время количество ОЗУ может не хватить (по моему по умолчанию ограничение 2 Гб). NodeJS вызовет ошибку, а IIS перезапустит пул. Можно конечно увеличить это ограничение, но рано или поздно будут возникать проблемы с производительностью.
Решение: распределение нагрузки при помощи виртуальных каталогов
Простое приложение на NodeJS
Мы будем использовать приложение, которое будет написано при помощи фреймворка express.
Файл: app.js
var express = require('express');
var app = express();
var join = require('path').join;
/*** Порт для работы приложения */
var port = normalizePort(process.env.PORT);
/*** Виртуальный каталог */
var vPath = process.env.virtualDirPath || '';
app.use(vPath + '/', express.static(join(__dirname, 'public')));
app.get(vPath + '/', function (req, res) {
res.send(vPath);
});
app.listen(port, function () {
console.log('Example app listening on port ' + port + '!');
});
/**
* Normalize a port into a number, string, or false.
* @param {any} val номер порта
* @returns {number|boolean}
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
Файл: packge.json
{
"name": "simple-express",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"args-parser": "^1.1.0",
"express": "^4.17.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Файл: web.config
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="app.js" verb="" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="myapp">
<match url="/" />
<action type="Rewrite" url="app.js" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Располагаем наше приложение в корневом каталоге IIS (можно расположить, где угодно, но нужно будет дополнительно настраивать). У меня оно называется arm

Настройка IIS
Примечание: NodeJS приложению требуются дополнительные права на исполнение, для этого нужно убедиться, что есть полный доступ для пользователя IIS_IUSRS

Далее создаем столько пулов на сколько потоков мы хотим «разделить» наше приложение. В моем примере это будет 2.
При создании пулов не требуется исполнение CLR, нам нужен сам факт наличия, т.к. пул IIS нам и обеспечивает параллельность выполнения.


После создания пулов переходим к настройки виртуальных каталогов. Для этого в приложении по умолчанию «Default Web Site» выбираем «Добавить виртуальный каталог»

- в «псевдониме» указываем наименование приложения. Я указывал arm, arm2
- «физический путь» указывает на каталог wwwroot/arm
- после создания требуется преобразовать в приложение и указать соответствующий пул



Последним «штрихом» является web.config на уровне корневого каталога
<configuration>
<location path="arm">
<appSettings>
<add key="virtualDirPath" value="/arm" />
</appSettings>
</location>
<location path="arm2">
<appSettings>
<add key="virtualDirPath" value="/arm2" />
</appSettings>
</location>
</configuration>
virtualDirPath — дополнительная настройка, которая используется в приложении на NodeJS
... var vPath = process.env.virtualDirPath || ''; app.use(vPath + '/', express.static(join(__dirname, 'public'))); ...

Примечание: особенность настройки заключается в том, что физически в файловой системе у нас будет храниться один каталог с приложением, но IIS при помощи «виртуализации» создаст несколько
Результат

Ниже мы видим как IIS под каждый экземпляр виртуального каталога создала отдельный процесс
