[ Esta postagem está atualizada em 02/09/2012 (mais recente que acima). ]
O Node.js é totalmente escalável em máquinas com vários núcleos.
Sim, o Node.js é um thread por processo. Essa é uma decisão de projeto muito deliberada e elimina a necessidade de lidar com a semântica de bloqueio. Se você não concorda com isso, provavelmente ainda não percebe o quão insanamente difícil é depurar código multiencadeado. Para uma explicação mais aprofundada do modelo de processo do Node.js. e por que ele funciona dessa maneira (e por que NUNCA suporta vários threads), leia meu outro post .
Então, como aproveito minha caixa de 16 núcleos?
Dois caminhos:
- Para grandes tarefas de computação pesada, como codificação de imagens, o Node.js pode iniciar processos filho ou enviar mensagens para processos de trabalho adicionais. Nesse design, você teria um thread gerenciando o fluxo de eventos e N processos executando tarefas pesadas de computação e mastigando as outras 15 CPUs.
- Para dimensionar a taxa de transferência em um serviço da Web, você deve executar vários servidores Node.js. em uma caixa, uma por núcleo e dividir o tráfego de solicitação entre eles. Isso fornece excelente afinidade da CPU e aumentará a produtividade quase linearmente com a contagem de núcleos.
Escalando a taxa de transferência em um serviço da web
Desde a v6.0.X, o Node.js incluiu o módulo de cluster imediatamente, o que facilita a configuração de vários trabalhadores do nó que podem escutar em uma única porta. Observe que este NÃO é o mesmo que o módulo "cluster" do learnboost mais antigo disponível no npm .
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.Server(function(req, res) { ... }).listen(8000);
}
Os trabalhadores competirão para aceitar novas conexões, e o processo menos carregado provavelmente vencerá. Funciona muito bem e pode aumentar bastante a produtividade em uma caixa com vários núcleos.
Se você tiver carga suficiente para se preocupar com vários núcleos, também precisará fazer mais algumas coisas:
Execute o serviço Node.js atrás de um proxy da Web como Nginx ou Apache - algo que pode acelerar a conexão (a menos que você queira que as condições de sobrecarga reduzam completamente a caixa), reescreva URLs, sirva conteúdo estático e faça proxy de outros sub-serviços.
Recicle periodicamente seus processos de trabalho. Para um processo de longa execução, até um pequeno vazamento de memória acabará aumentando.
Coleta / monitoramento de logs de instalação
PS: Há uma discussão entre Aaron e Christopher nos comentários de outro post (até o momento em que este artigo foi escrito, é o post principal). Alguns comentários sobre isso:
- Um modelo de soquete compartilhado é muito conveniente para permitir que vários processos escutem em uma única porta e competam para aceitar novas conexões. Conceitualmente, você pode pensar no Apache pré-bifurcado fazendo isso com a ressalva significativa de que cada processo só aceita uma única conexão e depois morre. A perda de eficiência do Apache está na sobrecarga de criar novos processos e não tem nada a ver com as operações do soquete.
- Para o Node.js, fazer com que N trabalhadores concorram em um único soquete é uma solução extremamente razoável. A alternativa é configurar um front-end na caixa, como o Nginx, e ter esse tráfego proxy para os trabalhadores individuais, alternando entre os trabalhadores para atribuir novas conexões. As duas soluções têm características de desempenho muito semelhantes. E como, como mencionei acima, você provavelmente desejará que o Nginx (ou uma alternativa) esteja de frente para o serviço do nó, a escolha aqui é realmente entre:
Portas compartilhadas: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)
vs
Portas individuais: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}
É possível que haja alguns benefícios na configuração de portas individuais (potencial para ter menos acoplamento entre processos, tomar decisões de balanceamento de carga mais sofisticadas etc.), mas é definitivamente mais trabalho para configurar e o módulo de cluster embutido é baixo. alternativa de complexidade que funciona para a maioria das pessoas.