Scaling
Node Apps
Darren DeRidder
@73rhodes
node
fast?
Simon Willison, "Evented I/O based web servers, explained using bunnies"
Multi-Threaded | Multi-Process |
---|---|
Single process * | Multiple processes |
Threads share same memory space | Each process has own memory space |
Fewer resources | More resources |
cluster
Module
const cluster = require('cluster');
if (cluster.isPrimary) {
// Primary process here.
// Fork workers.
// Handle messages from workers.
// Allocate work to worker processes.
// Finally tell workers to shut down.
// Print result when all workers exit.
} else {
// Worker process here.
// Handle messages from primary process.
// Send messages back to primary process.
}
// Fork workers
const numWorkers = require('os').cpus().length;
for (let i = 0; i < numWorkers; i++) {
cluster.fork();
}
// Primary sending messages to workers.
for (var id in cluster.workers) {
cluster.workers[id].send('Hello from primary');
}
// Primary handling events from workers.
cluster.on("message", myMessageHandler);
cluster.on("error", myErrorHandler);
cluster.on("exit", myExitHandler);
// Worker
process.on("message", (msg) => {
console.log(`Got message "${msg}" from primary.`);
process.send(`Hello from worker ${cluster.worker.id}`);
});
// Shutting down
cluster.on("exit", (worker, code, signal) => {
if(Object.keys(cluster.workers).length === 0) {
// finalization
}
});
worker_threads
Module
const {
Worker,
isMainThread,
parentPort,
workerData,
threadId
} = require('worker_threads');
if (isMainThread) {
// Main thread here.
// Spawn worker threads.
// Set up message handlers.
// Allocate work to workers.
} else {
// Worker process.
// Set up message handlers.
// Do work, send messages to main thread.
}
let threads = new Set();
for (let i=0; i < numCpus; i++) {
threads.add(new Worker(__filename, { workerData: 3 }));
}
for (let worker of threads) {
worker.on("message", (msg) => { // handle it });
worker.on("exit", (code) => { // handle it });
worker.on("error", console.error);
}
// `worker thread ${threadId}`
for (let i=0; i < workerData; i++) {
let result = fibonacci(40);
parentPort.postMessage(result);
}
lscpu
sysctl
node require('os').cpus()