Jak skalować aplikacje Node.js?
Pokrótce omówimy, jak skalować jedną z najpopularniejszych obecnie platform do tworzenia aplikacji.
Zacznijmy więc od motywacji: jak stworzyć dobrze działające API i powielić tę logikę dla użytkowników X?
Mamy trzy sposoby skalowania naszej aplikacji: Pionowy , Poziomy i mieszany (pionowy i poziomy).
Skalowanie w poziomie
Skalowanie w poziomie oznacza, że w większości przypadków duplikowane są serwery lub węzły. W przypadku tej repliki lub replik będziemy potrzebować modułu równoważenia obciążenia, aby wysłać do nich wszystkie żądania w równy sposób.
Musimy wziąć pod uwagę, że to rozwiązanie wiąże się ze złożonością podczas wdrażania aplikacji, ponieważ nowy moduł równoważenia obciążenia powinien być dobrze skonfigurowany, w przeciwnym razie cały ruch mógłby trafić na jeden serwer i stracilibyśmy pieniądze.
Skalowanie w pionie
Pionowe oznacza dodanie większej mocy obliczeniowej lub pamięci RAM/dysków.
To całkiem proste, jeśli twój komputer w chmurze działa na maszynie z 16 GB pamięci RAM i 16 rdzeniami/32 wątkami, podwojmy to i możesz dostarczyć podwójną liczbę użytkowników .
Ale w tym celu musimy wziąć pod uwagę, że w pewnym momencie będziemy mieli limit, a także ceny wzrosną wykładniczo w ostatnich dostępnych konfiguracjach.
A więc zacznijmy!
To będzie krótka teczka dotycząca skalowania w poziomie .
Łatwym początkiem byłoby użycie The Cluster Module .
Za pomocą tego modułu możemy tworzyć procesy potomne, które współdzielą wszystkie porty serwera. Dość słów, oto kod!
import cluster from 'node:cluster';
import http from 'node:http';
import { availableParallelism } from 'node:os';
import process from 'node:process';
const numCPUs = availableParallelism();
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}
$ node server.js
Primary 3596 is running
Worker 4324 started
Worker 4520 started
Worker 6056 started
Worker 5644 started
Aby trochę lepiej zrozumieć ten proces roboczy , zróbmy przykład:
Przeczytaj duży plik json i dla każdej linii i dla każdego obiektu w nim zawartego przekonwertuj te informacje na XML.
Najpierw kod bez wątków roboczych =>
/* syncMode.js */
// Read all JSON file contents into an array
const contents = getContents()
/* Execution time start */
const start = hrtime.bigint()
// Convert each JSON file content to XML format
const result = contents.map((content) => {
content = JSON.parse(content)
return js2xmlparser.parse('user', content)
})
/* Execution time end */
const end = hrtime.bigint()
console.info(`Execution time: ${(end - start) / BigInt(10 ** 6)}ms`)
Załóżmy, że mamy katalog zawierający 1000 plików JSON i mamy za zadanie przekonwertować każdy plik JSON na plik XML.
Każdy plik JSON zawiera tablicę 1000 obiektów, z których każdy ma 6 par klucz-wartość, jak pokazano w poniższym przykładzie.
{
"id": 1,
"first_name": "abc",
"last_name": "xyz",
"email": "[email protected]",
"gender": "Male",
"ip_address": "163.213.59.129"
}
$ node syncMode.js
Execution time: 1036ms
Aby łatwiej zarządzać wątkami roboczymi, użyjemy biblioteki o nazwie Piscina , która jest idealna do tego zadania!
/* ThreadMode.js */
const Piscina = require('piscina')
// Read all JSON file contents into an array
const contents = getContents()
/* Execution time start */
// Divide the content into two chunks
const chunks = splitToChunks(contents, 2)
// Create a new thread pool
const pool = new Piscina()
const options = { filename: resolve(__dirname, 'worker-pool') }
// Run operation on the chunks parallely
const result = await Promise.all([pool.run(chunks[0], options), pool.run(chunks[1], options)])
/* Execution time end */
$node ThreadMode.js
Execution time: 687ms
Widzieliśmy niesamowity wzrost wydajności o ponad 66% !!! z zaledwie kilkoma liniami. Tutaj jest to bardzo specyficzny przypadek, ale zaczęliśmy widzieć, jak zwiększyć wydajność w Node.js za pomocą wbudowanych funkcjonalności.
W kolejnych krokach będziemy używać równoważenia obciążenia do rozdzielania obciążenia na kilka interfejsów API w węźle z dokerem, więc bądźcie czujni!!!

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































