Çok çekirdekli makinelerde Node.js


606

Node.js ilginç görünüyor, AMA şey kaçırmalıyım - Node.js sadece tek bir işlem ve iş parçacığında çalışacak şekilde ayarlanmamış mı?

Peki çok çekirdekli işlemciler ve çok işlemcili sunucular için nasıl ölçeklenir? Sonuçta, mümkün olduğunca hızlı tek iş parçacıklı sunucu yapmak harika, ancak yüksek yükler için birkaç CPU kullanmak istiyorum. Aynı şey uygulamaları daha hızlı hale getirmek için de geçerli - bugün birden fazla CPU kullanmak ve görevleri paralelleştirmek gibi görünüyor.

Node.js bu resme nasıl uyuyor? Bir şekilde birden fazla örneği dağıtma fikri mi yoksa ne?


4
Ryah, düğümde yerleşik çok çekirdekli destek dahil etmek konusunda ciddi olmaya başlıyor gibi görünüyor: github.com/joyent/node/commit/…
broofa

2
PM2 işlem yöneticisi, NodeJS uygulamalarınızı mevcut tüm çekirdeklere yaymak için dahili olarak küme modülünü kullanır: github.com/Unitech/pm2
Unitech

@broofa, Bunlar gerçek evreler değil ve alt süreçlerin paylaşılan hafızası yok. Ayrıca bkz . Java'nın gerçek iş parçacığı ve geçici statik değişkenlerinin Nodejs eşdeğeri nedir? .
Pacerier

Yanıtlar:


697

[ Bu yayın 2012-09-02 tarihinden itibaren günceldir (yukarıdakinden daha yeni).]

Node.js kesinlikle çok çekirdekli makinelerde ölçeklendirir.

Evet, Node.js işlem başına bir iş parçacığıdır. Bu çok kasıtlı bir tasarım kararıdır ve kilitleme semantiği ile başa çıkma ihtiyacını ortadan kaldırır. Buna katılmıyorsanız, muhtemelen çok iş parçacıklı kodda hata ayıklamanın ne kadar çılgınca olduğunu fark etmiyorsunuzdur. Node.js süreç modelinin daha derin bir açıklama için ve bu şekilde çalışır (ve neden birden konuları destekleyen ASLA) neden okumak benim diğer yazı .

Peki 16 çekirdekli kutumdan nasıl yararlanabilirim?

İki yol:

  • Görüntü kodlama gibi büyük yoğun bilgi işlem görevleri için Node.js, alt işlemleri tetikleyebilir veya ek çalışan işlemlere ileti gönderebilir. Bu tasarımda, ağır bilgi işlem görevleri yapan ve diğer 15 CPU'yu çiğneyen olayların akışını ve N işlemlerini yöneten bir iş parçanız olur.
  • Bir web hizmetindeki verimi ölçeklemek için, çekirdek başına bir kutu ve aralarında bölünmüş istek trafiği olmak üzere tek bir kutuda birden fazla Node.js sunucusu çalıştırmalısınız. Bu, mükemmel bir CPU benzeşimi sağlar ve verimi çekirdek sayımıyla neredeyse doğrusal olarak ölçeklendirir.

Bir web hizmetinde ölçekleme verimi

V6.0.X Node.js, küme modülünü kutudan çıkardığı için tek bir bağlantı noktasında dinleyebilecek birden çok düğüm çalışanı kurmayı kolaylaştırır. Bunun, npm aracılığıyla kullanılabilen eski learnboost "küme" modülü ile aynı OLMADIĞINI unutmayın .

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

İşçiler yeni bağlantıları kabul etmek için yarışacak ve en az yüklenen işlem büyük olasılıkla kazanacak. Oldukça iyi çalışıyor ve çok çekirdekli bir kutuda verimi oldukça iyi artırabilir.

Birden çok çekirdeği önemsemek için yeterli yükünüz varsa, o zaman birkaç şey daha yapmak istersiniz:

  1. Node.js hizmetinizi Nginx veya Apache gibi bir web proxy'nin arkasında çalıştırın (aşırı yük koşullarının kutuyu tamamen aşağıya çekmesini istemiyorsanız), URL'leri yeniden yazın, statik içerik sunun ve diğer alt hizmetleri proxy yapın.

  2. Çalışan işlemlerinizi periyodik olarak geri dönüştürün. Uzun süren bir işlem için, sonunda küçük bir bellek sızıntısı bile artacaktır.

  3. Kurulum günlüğü toplama / izleme


Not: Aaron ve Christopher arasında başka bir yazının yorumlarında bir tartışma var (bu yazıdan itibaren en üstteki yazı). Bununla ilgili birkaç yorum:

  • Paylaşılan bir soket modeli, birden çok işlemin tek bir bağlantı noktasını dinlemesine ve yeni bağlantıları kabul etmek için rekabet etmesine izin vermek için çok uygundur. Kavramsal olarak, her sürecin sadece tek bir bağlantıyı kabul edip sonra öleceği önemli bir uyarıyla bunu yapan önceden eğitilmiş Apache'yi düşünebilirsiniz. Apache için verimlilik kaybı, yeni süreçler istemekle yükümlüdür ve soket işlemleriyle hiçbir ilgisi yoktur.
  • Node.js için, N işçinin tek bir sokette rekabet etmesi son derece makul bir çözümdür. Alternatif, Nginx gibi bir kutu üzerinde ön uç oluşturmak ve çalışanlara yeni bağlantılar atamak için çalışanlar arasında dönüşümlü olarak vekil trafiğe sahip olmaktır. İki çözüm de benzer performans özelliklerine sahiptir. Ve yukarıda da belirttiğim gibi, muhtemelen Nginx'in (veya bir alternatifin) düğüm hizmetinizi zaten ön plana çıkarmak isteyeceğinizden, buradaki seçim gerçekten arasında:

Paylaşılan Bağlantı Noktaları: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

vs

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

Bireysel bağlantı noktaları kurulumunun tartışmasız bazı faydaları vardır (işlemler arasında daha az bağlantıya sahip olma potansiyeli, daha karmaşık yük dengeleme kararları vb.), Ancak kesinlikle daha fazla çalışma yapılması ve yerleşik küme modülünün düşük olması - çoğu insan için çalışan karmaşıklık alternatifi.


1
tek bir kutu üzerinde farklı nodejs tabanlı hizmetleri çalıştırmak için herhangi bir öneri sunabilir misiniz? Örneğin, 1 sunucum olduğunu ve CpuCore1 üzerinde myservice1.js ve CpuCore2 üzerinde myservice2.js çalıştırmak istediğinizi varsayalım. Bunun için küme kullanabilir miyim? yoksa yalnızca klonlanmış hizmetler oluşturmak için faydalı mıdır?
UpTheCreek

6
Bunun için bir soru göndermelisin! (ve bu yorumu ilk cevabınız olarak kopyalayacağım). Yapmak istediğiniz şey aslında gerçekten çok basit. Gerçekten "kümeye" ihtiyacınız olmaz, sadece iki farklı düğüm servisi çalıştırırsınız. İki komut dosyası, iki işlem, iki bağlantı noktası. Örneğin 3000'den ve serviceB'den 3001'i dinleyebilirsiniz. Bu hizmetlerin her biri 1 küme çalışanı olmak ve periyodik olarak geri dönüştürmek için "küme" kullanabilir. Sonra Nginx'i 80 numaralı bağlantı noktasını dinleyecek ve gelen "Ana Bilgisayar" başlığına ve / veya URL yoluna dayalı olarak doğru hizmet.
Dave Dopson

1
Teşekkürler. Ben ettik İlgili bir soru haberi hemen hemen aklımda ne vardı anlatılan, ama ben (sonsuza gibi bir şey kullanılırken) CPU çekirdeği hedef konusunda emin değilim - zaten.
UpTheCreek

Harika cevap ddopson. İki düğüm işleminin aynı makinede birbiriyle iletişim kurmasının en iyi yolu nedir? Aynı makinedeyken TCP'den daha hızlı bir protokol var mı?
2013

1
@Serob_b - evet, evet. Bir Node.js uygulamasını birden çok makinede çalıştırmak çok yaygındır. Bunun için kütüphane gerekmez. Kodunuzu birden fazla makinede çalıştırır ve aralarında yük dağıtırsınız. Yazılımınızı ölçeklendirecek şekilde tasarlama (yani, durumu hafızada tutmak yerine bir tür harici veri hizmetinde depolar) - bu sizin işiniz.
Dave Dopson

45

Bir yöntem, sunucuda birden fazla node.js örneğini çalıştırmak ve daha sonra bunların önüne bir yük dengeleyici (tercihen nginx gibi bloke olmayan bir tane) koymak olacaktır.


36
node.js yaklaşık nginx kadar hızlıdır, isterseniz node.js sunucularınızın önüne bir node.js yük dengeleyici koyabilirsiniz :)
mikeal

26
ryan özellikle düğüm daha kararlı olana kadar bunu yapmamasını söyledi. En iyi yol, nginx'i düğümün önünde çalıştırmaktır.
resopollution

2
Düğümün önündeki nginx için olduğu gibi, bir bellek içi kuyruğunuz gibi bazı sorunları çözmez. 2 düğüm örneği birbirlerinin kuyruğuna erişemez.
resopollution

5
Ayrıca, nginx HTTP 1.1'i tam olarak desteklemediğinden, WebSockets gibi şeylere proxy uygulanamaz.
ashchristopher

2
@mikeal, resopollution - Nginx tarafındayım. Node.js'yi birden çok kez zorladım (yığın izlemesi yok, sadece ölüyor). Nginx'i hiç çarpmadım. Nginx hazırdır, her türlü aklı gaz kelebeği ile yapılandırılmıştır. Node.js varsayılan olarak, kutu kapanana kadar mevcut olanlara hizmet vermek yerine yeni bağlantıları kabul etmeye devam edecektir ... evet, tüm kutu; Stres testi düğümü ile bir CentOS5 kutusundaki çekirdeği çökerttim (şimdi gerçekten olması gerekmiyor). Biraz geldim ve potansiyel olarak özel LB tipi roller de dahil olmak üzere Node için parlak bir gelecek görüyorum. Henüz değil.
Dave Dopson

30

Ryan Dahl bu soruyu geçen yaz Google'da yaptığı teknik konuşmada yanıtladı . Paraphrase için, "sadece birden fazla düğüm işlemi çalıştırın ve iletişim kurmasına izin vermek için mantıklı bir şey kullanın. Örneğin sendmsg () tarzı IPC veya geleneksel RPC".

Ellerinizi hemen kirletmek istiyorsanız, spark2 Forever modülüne bakın. Birden fazla düğüm işlemini yumurtlamayı son derece kolay hale getirir. Bağlantı noktası paylaşımını ayarlamayı yönetir, böylece her biri aynı bağlantı noktasına olan bağlantıları kabul edebilir ve ayrıca bir işlemin ölmesi durumunda / yeniden başlatıldığından emin olmak istiyorsanız otomatik olarak yeniden doğabilir.

GÜNCELLEME - 10/11/11 : Düğüm topluluğundaki fikir birliği, Küme'nin artık makine başına birden çok düğüm örneğini yönetmek için tercih edilen modül olduğu görülüyor . Sonsuza kadar bir göz atmaya değer.


8
Forever ve Cluster çok farklı şeyler yaparlar. Her ikisini de kullanabilirsiniz. Öldüğünde sonsuza dek bir süreci yeniden başlatır. Küme, birden çok çalışanı yönetir. Master sürecinizi yönetmek için Forever'ı kullanırsınız ...
Dave Dopson

4
ayrıca, learnboost modülü büyük ölçüde Düğüm v0.6.x içine pişmiş Küme sürümü ile desteklenir (uyarı: API yüzeyi farklıdır)
Dave Dopson

@broofa Varsayılan IPC, Redis veya Memcache kullanarak sadece işlemler arasında dize / veri / diziler göndermeyi söyleyelim. Hangi yol daha hızlı olurdu?
NiCk Newman

1
@broofa, IPC, Java ve C'nin yapabildiği gerçek paylaşılan belleğe kıyasla çok büyük yüklere sahiptir.
Pacerier

@Pacerier Doğru, ancak paylaşılan bellek, birçok ana bilgisayarda ölçeklendirmek için gereken makro sorunlarını ele almadan, yalnızca tek bir ana bilgisayar bağlamında nasıl ölçekleneceği sorununu çözer. Yani bulutta nasıl çalıştırılır.
Broofa

20

Küme modülünü kullanabilirsiniz . Bunu kontrol et .

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);
}

13

Çok düğümlü, sahip olabileceğiniz tüm çekirdekleri kullanır.
Göz at http://github.com/kriszyp/multi-node .

Daha basit ihtiyaçlar için, farklı bağlantı noktası numaralarında düğümün birden çok kopyasını başlatabilir ve bunların önüne bir yük dengeleyici koyabilirsiniz.


12

Düğüm Js, CPU'nuzun tüm avantajlarından yararlanmak için kümelemeyi destekliyor. Küme ile çalıştırmıyorsanız, muhtemelen donanım yeteneklerinizi boşa harcıyorsunuz demektir.

Node.js'de kümeleme, aynı sunucu bağlantı noktasını paylaşabilen ayrı işlemler oluşturmanıza olanak tanır. Örneğin, Bağlantı Noktası 3000'de bir HTTP sunucusu çalıştırırsak, işlemcinin tek çekirdeğinde Tek iş parçacığında çalışan bir sunucudur.

Aşağıda gösterilen kod, uygulamanızı kümelemenize olanak tanır. Bu kod Node.js tarafından temsil edilen resmi koddur.

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.
}

eğitimin tamamı için bu makaleye göz atın


11

Yukarıda belirtildiği gibi, Küme uygulamanızı tüm çekirdeklerde ölçeklendirecek ve yük dengeleyecektir.

gibi bir şey eklemek

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

Başarısız olan işçileri yeniden başlatır.

Bu günlerde, birçok insan sizin için kümelenmeyi idare eden ve bazı harika izleme özellikleri sağlayan PM2'yi de tercih ediyor .

Ardından, kümeleme ile çalışan birkaç makinenin önüne Nginx veya HAProxy ekleyin ve birden fazla yük devretme seviyesine ve çok daha yüksek yük kapasitesine sahip olursunuz.


3
PM2 üretim kullanımı için mükemmeldir. İzleme araçları, uygulamalarla ilgili bellek sorunlarını çözmeme yardımcı oldu.
mbokil

7

Düğümün gelecekteki sürümü, bir süreci çatallamanızı ve ona iletmenizi sağlar ve Ryan, dosya işleyicilerini de paylaşmanın bir yolunu bulmak istediğini belirtmiştir, bu yüzden düz bir Web Çalışanı uygulaması olmayacaktır.

Şu anda bunun için kolay bir çözüm yok ama hala çok erken ve düğüm şimdiye kadar gördüğüm en hızlı hareket eden açık kaynak projelerinden biri, bu yüzden yakın gelecekte harika bir şey bekliyoruz.


7

Spark2, artık korunmayan Spark'a dayanıyor. Küme onun halefidir ve CPU çekirdeği başına bir işçi işlemi oluşturmak ve ölü işçileri yeniden doğmak gibi bazı harika özelliklere sahiptir.


Orijinal soru ve bu cevapların birçoğu birkaç aylık ve düğüm çok hızlı hareket ederken, Küme hakkındaki bulanıklığı eklediğiniz için teşekkür ederim. Küme ve örneklere bakarak sonra, görünüşe aynen , ben (veya OP?) Düğüm için istediğiniz gibi sayesinde!
Riyad Kalla


5

Buradaki bloktaki yeni çocuk LearnBoost'un "Yukarı" sı .

"Sıfır kesinti süresi yeniden yüklemeleri" sağlar ve ayrıca tüm Dünyaların en iyisini sağlamak için birden fazla işçi (varsayılan olarak CPU sayısı, ancak yapılandırılabilir) oluşturur.

Yeni, ama oldukça kararlı görünüyor ve mevcut projelerimden birinde mutlu bir şekilde kullanıyorum.


5

Küme modülü size makinenin tüm çekirdeklerini kullanmasına olanak sağlar. Aslında bundan sadece 2 komutla ve çok popüler bir süreç yöneticisi pm2 kullanarak kodunuza dokunmadan yararlanabilirsiniz .

npm i -g pm2
pm2 start app.js -i max

4

Node.js uygulamanızı os ile birlikte küme modülünü kullanarak birden çok çekirdek üzerinde çalıştırabilirsiniz olduğunu tespit etmek için kullanılabilen modülü .

Örneğin server, arka uçta basit http sunucusu çalıştıran bir modülünüz olduğunu ve bunu birkaç CPU için çalıştırmak istediğinizi düşünelim :

// 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();
}


0

Web hizmetini, unix soketlerini dinleyen birkaç bağımsız sunucu olarak tasarlamak da mümkündür, böylece veri işleme gibi işlevleri ayrı işlemlere itebilirsiniz.

Bu, bir cgi işleminin iş mantığını işlediği ve daha sonra verileri bir unix soketi aracılığıyla bir veritabanına ittiği ve çektiği çoğu scrpting / veritabanı web sunucusu mimarisine benzer.

fark, veri işlemenin bir bağlantı noktasını dinleyen bir düğüm web sunucusu olarak yazılmasıdır.

daha karmaşık ama sonuçta çok çekirdekli gelişimin gitmesi gereken yer burası. her web isteği için birden çok bileşen kullanan çok işlemli bir mimari.


0

Her biri bir NodeJS işlemi çalıştıran birden çok kutunun önünde saf TCP yük dengeleyicisi (HAProxy) kullanarak NodeJS'yi birden çok kutuya ölçeklendirmek mümkündür.

Daha sonra tüm örnekler arasında paylaşılacak bazı ortak bilginiz varsa, merkezi bir Redis deposu veya benzeri bir şey kullanabilirsiniz;


Bu sunucularda tek çekirdekli CPU'larınız yoksa, bu işlem tüm CPU kapasitenizi kullanmaz (başka bir şey yapmazsanız).
UpTheCreek
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.