Node.js pada mesin multi-core

606

Node.js terlihat menarik, TAPI saya harus melewatkan sesuatu - bukankah Node.js hanya disetel untuk berjalan pada satu proses dan utas?

Lalu bagaimana skala untuk CPU multi-core dan server multi-CPU? Setelah semua, itu semua bagus untuk membuat server single-thread secepat mungkin, tetapi untuk beban tinggi saya ingin menggunakan beberapa CPU. Dan hal yang sama berlaku untuk membuat aplikasi lebih cepat - tampaknya saat ini cara menggunakan beberapa CPU dan memparalelkan tugas.

Bagaimana Node.js masuk ke dalam gambar ini? Apakah idenya untuk entah bagaimana mendistribusikan banyak contoh atau apa?

zaharpopov
sumber
4
Sepertinya Ryah mulai menjadi serius tentang termasuk dukungan multi-core bawaan
broofa
2
Manajer proses PM2 menggunakan modul kluster secara internal untuk menyebarkan aplikasi NodeJS Anda ke semua core yang tersedia: github.com/Unitech/pm2
Unitech
@broofa, Itu bukan utas nyata dan proses anak tidak memiliki memori bersama. Juga lihat Apa yang setara dengan Nodejs dari variabel nyata threading dan volatile-statis Java? .
Pacerier

Jawaban:

697

[ Posting ini terbaru pada 2012-09-02 (lebih baru dari yang di atas). ]

Node.js benar-benar melakukan skala pada mesin multi-core.

Ya, Node.js adalah one-thread-per-proses. Ini adalah keputusan desain yang sangat disengaja dan menghilangkan kebutuhan untuk berurusan dengan semantik penguncian. Jika Anda tidak setuju dengan ini, Anda mungkin belum menyadari betapa sulitnya melakukan debug kode multi-threaded. Untuk penjelasan lebih lanjut tentang model proses Node.js dan mengapa ia bekerja dengan cara ini (dan mengapa itu TIDAK PERNAH mendukung banyak utas), baca posting saya yang lain .

Jadi bagaimana saya mengambil keuntungan dari 16 core box saya?

Dua arah:

  • Untuk tugas komputasi besar yang berat seperti pengkodean gambar, Node.js dapat menjalankan proses anak atau mengirim pesan ke proses pekerja tambahan. Dalam desain ini, Anda akan memiliki satu utas yang mengelola aliran peristiwa dan proses N yang melakukan tugas komputasi yang berat dan mengunyah 15 CPU lainnya.
  • Untuk meningkatkan throughput pada layanan web, Anda harus menjalankan beberapa server Node.js pada satu kotak, satu per inti dan membagi lalu lintas permintaan di antara mereka. Ini memberikan afinitas CPU yang sangat baik dan skala proses akan hampir linier dengan jumlah inti.

Menskalakan throughput pada layanan web

Sejak v6.0.X Node.js telah menyertakan modul cluster langsung dari kotak, yang membuatnya mudah untuk mengatur beberapa pekerja simpul yang dapat mendengarkan pada satu port. Perhatikan bahwa ini BUKAN sama dengan modul "cluster" learningboost yang lebih lama tersedia melalui npm .

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  http.Server(function(req, res) { ... }).listen(8000);
}

Pekerja akan bersaing untuk menerima koneksi baru, dan proses yang paling sedikit dimuat kemungkinan besar akan menang. Ini bekerja cukup baik dan dapat meningkatkan throughput dengan cukup baik pada kotak multi-core.

Jika Anda memiliki beban yang cukup untuk peduli terhadap banyak inti, maka Anda juga ingin melakukan beberapa hal lagi:

  1. Jalankan layanan Node.js Anda di belakang proxy web seperti Nginx atau Apache - sesuatu yang dapat melakukan pelambatan koneksi (kecuali jika Anda ingin kondisi overload menurunkan kotak sepenuhnya), menulis ulang URL, menyajikan konten statis, dan proksi sub-layanan lainnya.

  2. Daur ulang proses pekerja Anda secara berkala. Untuk proses yang berjalan lama, bahkan kebocoran memori kecil pada akhirnya akan bertambah.

  3. Pengaturan pengumpulan / pemantauan log


PS: Ada diskusi antara Aaron dan Christopher dalam komentar-komentar dari postingan lain (pada tulisan ini, ini postingan teratas). Beberapa komentar tentang itu:

  • Model soket bersama sangat nyaman untuk memungkinkan beberapa proses mendengarkan pada satu port dan bersaing untuk menerima koneksi baru. Secara konseptual, Anda dapat membayangkan Apache yang melakukan operasi ini dengan peringatan signifikan bahwa setiap proses hanya akan menerima satu koneksi dan kemudian mati. Kehilangan efisiensi untuk Apache ada di atas proses proses baru dan tidak ada hubungannya dengan operasi soket.
  • Untuk Node.js, memiliki pekerja N bersaing pada satu soket adalah solusi yang sangat masuk akal. Alternatifnya adalah dengan mengatur front-end on-box seperti Nginx dan memiliki lalu lintas proxy untuk masing-masing pekerja, bergantian antara pekerja untuk menetapkan koneksi baru. Kedua solusi tersebut memiliki karakteristik kinerja yang sangat mirip. Dan karena, seperti yang saya sebutkan di atas, Anda mungkin ingin memiliki Nginx (atau alternatif) untuk mem-forward layanan simpul Anda, pilihan di sini adalah antara:

Port Bersama: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

vs.

Port Individual: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}

Ada beberapa manfaat untuk pengaturan masing-masing port (potensi untuk memiliki lebih sedikit kopling antar proses, memiliki keputusan load-balancing yang lebih canggih, dll.), Tetapi jelas lebih banyak pekerjaan untuk diatur dan modul klaster built-in rendah Alternatif -kompleksitas yang bekerja untuk kebanyakan orang.

Dave Dopson
sumber
1
dapatkah Anda menawarkan saran untuk menjalankan berbagai layanan berbasis node pada satu kotak? Misalkan saya punya 1 server, dan ingin menjalankan myservice1.js di CpuCore1, dan myservice2.js di CpuCore2. Bisakah saya menggunakan cluster untuk ini? atau hanya berguna untuk membuat layanan kloning?
UpTheCreek
6
Anda harus memposting pertanyaan untuk itu! (dan saya akan menyalin komentar ini sebagai jawaban pertama Anda). Apa yang ingin Anda lakukan sebenarnya sangat sederhana. Anda tidak akan benar-benar membutuhkan "cluster", Anda hanya akan menjalankan dua layanan simpul yang berbeda. Dua skrip, dua proses, dua port. Misalnya, Anda dapat meminta serviceA mendengarkan pada 3000 dan serviceB mendengarkan pada 3001. Masing-masing layanan tersebut mungkin menggunakan "cluster" untuk memiliki 1+ pekerja dan mendaur ulang mereka secara berkala, dll. Kemudian Anda dapat mengonfigurasi Nginx untuk mendengarkan pada port 80 dan untuk meneruskan ke layanan yang benar berdasarkan tajuk "Host" yang masuk dan / atau jalur URL.
Dave Dopson
1
Terima kasih. Saya telah memposting pertanyaan terkait - Anda menggambarkan cukup banyak apa yang ada dalam pikiran saya, tetapi saya tidak yakin tentang bagaimana menargetkan core CPU (ketika menggunakan sesuatu seperti selamanya).
UpTheCreek
Jawaban bagus ddopson. Apa cara terbaik untuk membuat dua proses simpul saling berkomunikasi di mesin yang sama? Apakah ada protokol yang lebih cepat daripada TCP ketika mereka berada di mesin yang sama?
winduptoy
1
@ Serob_b - yah, ya. Menjalankan aplikasi Node.js di beberapa mesin sangat umum. Tidak perlu perpustakaan untuk melakukannya. Anda cukup menjalankan kode di beberapa mesin dan mendistribusikan beban di antaranya. Merancang perangkat lunak Anda sehingga skala (yaitu, menyimpan keadaan dalam beberapa jenis layanan data eksternal daripada menjaga status dalam memori) - itulah tugas Anda.
Dave Dopson
45

Salah satu metode adalah menjalankan beberapa instance dari node.js di server dan kemudian meletakkan load balancer (lebih disukai yang non-blocking seperti nginx) di depannya.

Chandra Sekar
sumber
36
node.js kira-kira secepat nginx, Anda bisa meletakkan penyeimbang beban node.js di depan server node.js Anda jika Anda mau juga :)
mikeal
26
ryan secara khusus mengatakan tidak melakukan ini sampai node lebih stabil. Cara terbaik adalah menjalankan nginx di depan node.
resopolusi
2
Adapun nginx di depan node, itu tidak akan menyelesaikan masalah-masalah tertentu seperti jika Anda memiliki antrian di memori. Contoh 2 node tidak akan dapat mengakses antrian satu sama lain.
resopollution
5
Selain itu, nginx tidak mendukung HTTP 1.1 sepenuhnya, jadi hal-hal seperti WebSockets tidak dapat diproksi.
ashchristopher
2
@ Mike, resopollution - Saya sangat di sisi Nginx. Saya hard-crashed Node.js beberapa kali (tidak ada stacktrace, baru saja mati). Saya tidak pernah crash Nginx. Nginx out-of-the-box dikonfigurasi dengan segala macam throttle waras. Node.js secara default akan terus menerima koneksi baru dalam preferensi untuk melayani yang sudah ada sampai kotak turun ... ya, seluruh kotak; Saya menabrak kernel pada kotak CentOS5 oleh stress-testing Node (sekarang ITULAH tidak seharusnya terjadi). Saya telah datang sedikit, dan saya melihat masa depan yang cerah untuk Node, berpotensi termasuk peran tipe LB khusus. Hanya belum.
Dave Dopson
30

Ryan Dahl menjawab pertanyaan ini dalam pembicaraan teknologi yang dia berikan di Google musim panas lalu. Untuk parafrase, "jalankan saja beberapa proses simpul dan gunakan sesuatu yang masuk akal untuk memungkinkan mereka berkomunikasi. Misal sendmsg () - style IPC atau RPC tradisional".

Jika Anda ingin segera mengotori tangan Anda, lihat modul spark2 Forever . Itu membuat banyak proses pemijahan simpul mudah. Ini menangani pengaturan berbagi port, sehingga mereka masing-masing dapat menerima koneksi ke port yang sama, dan juga auto-respawning jika Anda ingin memastikan suatu proses dimulai kembali jika / ketika mati.

UPDATE - 10/11/11 : Konsensus dalam komunitas node tampaknya bahwa Cluster sekarang menjadi modul yang disukai untuk mengelola beberapa instance node per mesin. Selamanya juga patut dilihat.

broofa
sumber
8
Forever dan Cluster melakukan hal yang sangat berbeda. Anda bahkan dapat menggunakan keduanya. Selamanya memulai kembali proses ketika mati. Cluster mengelola banyak pekerja. Anda akan menggunakan Forever untuk mengelola proses master Anda ...
Dave Dopson
4
juga, modul learningboost sebagian besar digantikan oleh versi Cluster yang dimasukkan ke Node v0.6.x (peringatan: permukaan API memang berbeda)
Dave Dopson
@broofa Bagaimana IPC default dibandingkan dengan katakanlah menggunakan Redis atau Memcache hanya mengirim string / data / array di antara proses? Jalan mana yang lebih cepat?
NiCk Newman
1
@broofa, IPC memiliki overhead besar dibandingkan dengan memori bersama nyata yang mampu dilakukan oleh Java dan C.
Pacerier
@Pacerier Benar, tetapi memori bersama hanya memecahkan masalah bagaimana skala dalam konteks satu host, tanpa mengatasi masalah makro yang diperlukan untuk skala di banyak host. Yaitu Cara menjalankan di Cloud.
broofa
20

Anda dapat menggunakan modul cluster . Lihat ini .

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end("hello world\n");
    }).listen(8000);
}
Sergey Zhukov
sumber
13

Multi-simpul memanfaatkan semua inti yang mungkin Anda miliki.
Lihat http://github.com/kriszyp/multi-node .

Untuk kebutuhan yang lebih sederhana, Anda dapat memulai beberapa salinan node pada nomor port yang berbeda dan meletakkan penyeimbang beban di depannya.

CyberFonic
sumber
12

Node Js mendukung pengelompokan untuk memanfaatkan cpu Anda sepenuhnya. Jika Anda tidak menjalankannya dengan cluster, maka mungkin Anda menyia-nyiakan kemampuan perangkat keras Anda.

Clustering di Node.js memungkinkan Anda untuk membuat proses terpisah yang dapat berbagi port server yang sama. Misalnya, jika kita menjalankan satu server HTTP pada Port 3000, itu adalah satu Server yang berjalan pada utas tunggal pada inti prosesor tunggal.

Kode yang ditunjukkan di bawah ini memungkinkan Anda untuk mengelompokkan aplikasi Anda. Kode ini adalah kode resmi yang diwakili oleh Node.js.

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    Object.keys(cluster.workers).forEach(function(id) {
        console.log("I am running with ID : " + cluster.workers[id].process.pid);
    });

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {

    //Do further processing.
}

lihat artikel ini untuk tutorial lengkap

Toumi
sumber
11

Seperti yang disebutkan di atas, Cluster akan meningkatkan dan menyeimbangkan aplikasi Anda di semua core.

menambahkan sesuatu seperti

cluster.on('exit', function () {
  cluster.fork();
});

Akan memulai kembali pekerja yang gagal.

Saat ini, banyak orang juga lebih suka PM2 , yang menangani pengelompokan untuk Anda dan juga menyediakan beberapa fitur pemantauan keren .

Kemudian, tambahkan Nginx atau HAProxy di depan beberapa mesin yang berjalan dengan clustering dan Anda memiliki beberapa tingkat failover dan kapasitas beban yang jauh lebih tinggi.

Will Stern
sumber
3
PM2 sangat bagus untuk penggunaan produksi. Alat pemantauan telah membantu saya mengatasi masalah memori dengan aplikasi.
mbokil
7

Node versi masa depan akan memungkinkan Anda untuk melakukan proses dan menyampaikan pesan ke sana dan Ryan telah menyatakan bahwa ia ingin menemukan beberapa cara untuk juga berbagi file handler, sehingga itu tidak akan menjadi implementasi Web Worker yang mudah.

Pada saat ini tidak ada solusi yang mudah untuk ini tetapi masih sangat awal dan simpul adalah salah satu proyek open source bergerak tercepat yang pernah saya lihat sehingga mengharapkan sesuatu yang luar biasa dalam waktu dekat.

mikeal
sumber
7

Spark2 didasarkan pada Spark yang sekarang tidak lagi dipertahankan. Cluster adalah penggantinya, dan memiliki beberapa fitur keren, seperti menelurkan satu proses pekerja per inti CPU dan respawning pekerja mati.

Pengembang
sumber
Pertanyaan asli dan banyak jawaban ini berumur beberapa bulan dan dengan simpul yang bergerak sangat cepat, saya menghargai Anda menambahkan uraian tentang Cluster. Setelah melihat Cluster dan contoh-contohnya, kelihatannya persis seperti yang saya (atau OP?) Inginkan untuk Node, terima kasih!
Riyad Kalla
5

Saya menggunakan pekerja Node untuk menjalankan proses dengan cara sederhana dari proses utama saya. Tampaknya bekerja dengan baik sementara kami menunggu cara resmi untuk datang.

christkv
sumber
1
mengapa simpul pekerja example.js tidak dapat berjalan, simpul saya adalah versi pra 0.3.3
guilin 桂林
5

Anak baru di blok di sini adalah LearnBoost's "Naik" .

Ini memberikan "Zero-downtime reloads" dan juga menciptakan banyak pekerja (secara default jumlah CPU, tetapi dapat dikonfigurasi) untuk memberikan yang terbaik dari semua Dunia.

Ini baru, tetapi tampaknya cukup stabil, dan saya menggunakannya dengan bahagia di salah satu proyek saya saat ini.

Roy
sumber
5

The Cluster modul memungkinkan Anda untuk memanfaatkan semua core dari mesin Anda. Bahkan Anda dapat mengambil keuntungan dari ini hanya dalam 2 perintah dan tanpa menyentuh kode Anda menggunakan pm2 manajer proses yang sangat populer .

npm i -g pm2
pm2 start app.js -i max
Alister
sumber
4

Anda dapat menjalankan aplikasi node.js Anda di beberapa core dengan menggunakan modul cluster yang dikombinasikan dengan os modul yang dapat digunakan untuk mendeteksi berapa banyak CPU yang Anda miliki.

Sebagai contoh, mari kita bayangkan bahwa Anda memiliki servermodul yang menjalankan server http sederhana di backend dan Anda ingin menjalankannya untuk beberapa CPU:

// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');

 // If we're on the master thread start the forks.
if (cluster.isMaster) {
  // Fork the process.
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }
} else {
  // If we're not on the master thread start the server.
  server.init();
}

Oleksii Trekhleb
sumber
0

Mungkin juga untuk mendesain layanan web sebagai beberapa server yang berdiri sendiri yang mendengarkan soket unix, sehingga Anda dapat mendorong fungsi seperti pemrosesan data ke dalam proses terpisah.

Ini mirip dengan kebanyakan arsitektur web server scrpting / database di mana proses cgi menangani logika bisnis dan kemudian mendorong dan menarik data melalui soket unix ke database.

perbedaannya adalah bahwa pemrosesan data ditulis sebagai server web node mendengarkan pada port.

itu lebih kompleks tetapi pada akhirnya ke mana pengembangan multi-core harus pergi. arsitektur multiproses menggunakan beberapa komponen untuk setiap permintaan web.

Fire Crow
sumber
0

Dimungkinkan untuk skala NodeJS ke beberapa kotak menggunakan penyeimbang beban TCP murni (HAProxy) di depan beberapa kotak yang menjalankan satu proses NodeJS masing-masing.

Jika Anda kemudian memiliki pengetahuan umum untuk dibagikan di antara semua instance, Anda dapat menggunakan toko Redis pusat atau yang serupa yang kemudian dapat diakses dari semua instance proses (mis. Dari semua kotak)

Martin Tajur
sumber
Kecuali Anda memiliki CPU single core di server-server itu, itu tidak akan memanfaatkan semua kapasitas CPU Anda (kecuali jika Anda melakukan hal lain juga).
UpTheCreek