> 웹 프론트엔드 > JS 튜토리얼 > 클러스터링 및 작업자 스레드 - Node JS

클러스터링 및 작업자 스레드 - Node JS

Patricia Arquette
풀어 주다: 2024-11-26 00:22:11
원래의
514명이 탐색했습니다.

Clustering and Worker Threads - Node JS

이전 기사 " Node JS 내부 "에서 Node JS 내부 아키텍처에 대해 논의하고 여러 요청을 동시에 처리하기 위해 노드가 스레드 풀 크기를 늘려야 하는 이유에 대해서도 논의했습니다. 확장성과 성능은 Thread Pool 크기와 관련이 없다고 말씀드렸습니다.

확장성과 고성능을 위해 클러스터링과 작업자 스레드를 사용할 수 있습니다.

클러스터링

당신이 성대한 결혼식에 참석하고 있고 수천 명의 하객이 결혼식에 참석하고 있다고 가정해 보겠습니다. 주방은 하나이며 요리사 한 명이 모든 손님을 위해 음식을 준비하고 있습니다. 예측할 수 없는 것 같죠? 요리사가 한 명뿐이라면 주방의 모든 자원을 활용하지 못하는 것입니다.

이는 모든 요청을 처리하는 데 하나의 코어만 사용될 때 멀티코어 CPU에서 실행되는 Node JS 애플리케이션에서 정확히 일어나는 일입니다. 따라서 우리 컴퓨터에 멀티코어 성능이 있더라도 클러스터링 없이 애플리케이션은 단일 코어에서만 실행됩니다. 하나의 코어가 모든 작업을 담당합니다.

주방에서 여러 명의 요리사가 작업하는 경우가 바로 클러스터링입니다.

클러스터링은 단일 Node JS 애플리케이션이 여러 CPU 코어를 효과적으로 활용할 수 있도록 하는 데 사용되는 기술입니다.

클러스터링을 구현하려면 Node JS의 클러스터 모듈을 사용해야 합니다.

const cluster = require('cluster');
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 클러스터 모듈을 사용하면 Node JS 애플리케이션의 여러 인스턴스를 생성할 수 있습니다. 이러한 인스턴스를 작업자라고 합니다. 모든 작업자는 동일한 서버 포트를 공유하고 들어오는 요청을 동시에 처리합니다.

클러스터 아키텍처에는 두 가지 유형의 프로세스가 있습니다.

1.마스터 프로세스:

마스터 프로세스는 주방에서 직원들을 관리하는 메인 요리사와 같습니다. 애플리케이션을 초기화하고 클러스터링 환경을 설정하며 작업을 작업자 프로세스에 위임합니다. 애플리케이션 요청을 직접 처리하지 않습니다.

마스터 프로세스는 어떤 역할을 하나요?

  • cluster.fork() 메서드를 사용하여 여러 작업자 프로세스를 생성합니다. 또한 작업자가 충돌하거나 예기치 않게 종료되는 경우에도 작업자를 다시 시작합니다.

  • 들어오는 요청이 모든 작업자 프로세스에 분산되도록 합니다. Linux에서는 이를 운영 체제에서 처리하고, Windows에서는 Node JS 자체가 로드 밸런서 역할을 합니다.

  • IPC(Inter-Process Communication)를 통해 작업자 간 통신이 가능합니다.

2.작업자 프로세스:

작업자 프로세스는 마스터 프로세스에서 생성된 Node JS 애플리케이션의 인스턴스입니다. 각 프로세스는 별도의 CPU 코어에서 독립적으로 실행되며 들어오는 요청을 처리합니다.

작업자 프로세스는 서로 직접 통신할 수 없으며 마스터를 통해 통신합니다.

작업자 프로세스는 들어오는 요청을 처리하고 데이터베이스 쿼리, 계산 또는 애플리케이션 로직과 같은 일부 작업을 수행합니다.

const cluster = require('cluster');
로그인 후 복사
로그인 후 복사
로그인 후 복사

여기서 먼저 이것이 마스터 프로세스인지 확인하고 있습니다. 그렇다면 작업자 프로세스가 생성됩니다.

우리 코드에서는 Cluster.fork()를 사용하여 작업자 프로세스를 생성합니다.

그러나 이는 작업자 프로세스를 만드는 이상적인 방법은 아닙니다.

4개의 작업자 프로세스를 생성하고 시스템에 2개의 코어가 있다고 가정해 보겠습니다.

이 문제를 해결하려면 하드코딩된 작업자 프로세스를 생성하는 대신 먼저 CPU 코어를 찾은 다음 데이터가 작업자 프로세스를 생성하는 것을 고려하세요.

const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers
    cluster.fork();
    cluster.fork();
    cluster.fork();
    cluster.fork();

} else {
  console.log(`Worker ${process.pid} is running`);
  // Worker logic (e.g., server setup) goes here
}
로그인 후 복사

듀얼코어 시스템을 사용하고 있어서 출력은 이런 모습입니다.

const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);
  const numCPUs = os.cpus().length;

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  console.log(`Worker ${process.pid} is running`);
  // Worker logic (e.g., server setup) goes here
}
로그인 후 복사

이제 듀얼 코어 CPU를 사용하는 경우 왜 4개의 작업자 프로세스가 생성되었는지 궁금합니다.

논리 코어 수가 4개이기 때문에 내 CPU는 하이퍼스레딩이나 SMT(Simultaneous Multi-Threading)를 지원합니다.

작업자 스레드

레스토랑에서는 요리하는 데 시간이 좀 걸리기 때문에 웨이터가 주문을 받아 요리사 팀에게 그 주문을 전달합니다. 테이블 청소나 기타 웨이터 관련 작업이 오면 웨이터가 이를 수행합니다. 주문이 준비되면 요리사는 웨이터에게 음식을 돌려주고 웨이터는 이 음식을 고객에게 서빙합니다.

작업자 스레드와 관련된 동일한 시나리오입니다. 대규모 데이터 처리, 복잡한 계산 또는 무거운 알고리즘과 같이 계산 비용이 많이 드는 작업이 발생하는 경우 기본 스레드는 이 작업을 작업자 스레드에 위임합니다. 이 작업은 메인 스레드가 아닌 작업자가 수행합니다.

*왜 도움이 되나요? *

우리는 Node JS 이벤트 루프가 단일 스레드라는 것을 알고 있으며 이러한 과도한 계산 작업이 메인 스레드에서 수행되면 이벤트 루프가 차단됩니다. 이러한 작업자 스레드를 사용하면 이러한 무거운 작업이 작업자 스레드에 주어지고 작업자 스레드는 기본 스레드가 아닌 이러한 작업을 수행하므로 이벤트 루프가 차단되지 않습니다.

작업자 스레드는 메시지 전달 시스템을 통해 메인 스레드와 통신할 수 있으며 구조적 복제(전체 복사)를 사용하여 스레드 간에 데이터를 전송할 수 있습니다.

이제 작업자 스레드의 작동을 모방하려고 합니다.

main.js(메인 스레드)

Master 12345 is running
Worker 12346 is running
Worker 12347 is running
Worker 12348 is running
Worker 12349 is running
로그인 후 복사

worker.js(작업자 스레드)

const { Worker } = require('worker_threads');

function startWorker() {
  const worker = new Worker('./worker.js'); // Create a worker using worker.js

  // Listen for messages from the worker
  worker.on('message', (message) => {
    console.log('Message from worker:', message);
  });

  // Handle errors in the worker
  worker.on('error', (error) => {
    console.error('Worker error:', error);
  });

  // Handle worker exit
  worker.on('exit', (code) => {
    console.log(`Worker exited with code ${code}`);
  });

  // Send a message to the worker
  worker.postMessage({ num: 100 });
}

startWorker();
로그인 후 복사

데이터에 큰 구조가 포함된 경우에는 깊게 복제되어 전달되므로 성능 오버헤드가 발생할 수 있습니다.

코드 작업

  • Worker 클래스는 새 스레드를 생성하는 데 사용됩니다.

  • worker.postMessage를 사용하여 작업자에게 데이터를 보내고, Worker.on('message', callback)을 사용하여 메시지를 수신할 수 있습니다.

  • 작업자 스레드에서 parentPort는 기본 스레드와 통신하는 기본 인터페이스입니다.

  • 메인 스레드(parentPort.on('message'))에서 메시지를 수신하고 parentPort.postMessage를 사용하여 메시지를 다시 보낼 수 있습니다.

출력은 다음과 같습니다.

const cluster = require('cluster');
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 질문이 하나 있습니다. 수백 개의 작업자 스레드를 생성해 보는 것은 어떨까요?

그러나 그 이유는 코어 수보다 더 많은 스레드를 생성하면 스레드가 CPU 시간을 놓고 경쟁하게 되어 컨텍스트 전환으로 이어져 비용이 많이 들고 전체 성능이 저하되기 때문입니다.

Node.js에서 클러스터링, 작업자 스레드 또는 둘 다를 언제 사용해야 합니까?

1. 작업자 스레드는 언제 사용합니까?

  • CPU 바인딩 작업:

이미지/동영상 처리, 데이터 압축 또는 암호화, 기계 학습 추론, 과학적 계산 등 과도한 계산이 필요한 작업

  • 공유 메모리가 필요합니다:

데이터를 중복하지 않고 스레드 간에 효율적으로 공유해야 합니다.

  • 단일 코어 사용:

애플리케이션이 단일 프로세스 내에서만 확장되어야 하지만 여전히 CPU 집약적인 작업을 위해 병렬 처리가 필요한 경우.

2.클러스터링은 언제 사용하나요?

  • I/O 바운드:

웹, 서버, 채팅 애플리케이션, API 등 수많은 클라이언트 요청을 처리하는 작업이 포함됩니다. 클러스터링은 모든 CPU 코어에 요청을 분산시켜 수평적으로 확장하는 데 도움이 됩니다.

  • 격리된 메모리:

애플리케이션은 프로세스 간에 많은 데이터를 공유할 필요가 없습니다.

  • 멀티 코어 활용:

여러 Node.js 프로세스를 생성하여 사용 가능한 모든 코어를 활용하려고 합니다.

3.클러스터링과 작업자 스레드를 언제 모두 사용해야 합니까?

  • I/O 바인딩된 CPU 바인딩 작업:

애플리케이션은 HTTP 요청을 처리하지만 계산 집약적인 작업은 오프로드합니다. 예: 웹 서버는 파일 업로드를 처리하고 이미지 크기 조정이나 비디오 트랜스코딩을 수행합니다.

  • 높은 확장성:

높은 처리량을 위해서는 프로세스 수준 및 스레드 수준 병렬 처리가 모두 필요합니다. 전자 상거래 사이트에서 클러스터링은 여러 프로세스가 들어오는 요청을 처리하도록 보장합니다. 작업자 스레드는 개인화된 추천 생성과 같은 백그라운드 작업을 처리합니다.

감사합니다.

질문이나 제안 사항을 자유롭게 남겨주세요.

이 정보가 유익하셨다면 좋아요를 눌러주세요.

위 내용은 클러스터링 및 작업자 스레드 - Node JS의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿