클러스터링으로 Node.js 애플리케이션을 확장하는 방법


저자는 Write for DOnations 프로그램을 선택했습니다.

소개

CPU가 여러 개인 시스템에서 Node.js 프로그램을 실행하면 기본적으로 단일 CPU만 사용하여 실행하는 프로세스가 생성됩니다. Node.js는 단일 스레드를 사용하여 JavaScript 코드를 실행하므로 애플리케이션에 대한 모든 요청은 단일 CPU에서 실행되는 해당 스레드에서 처리해야 합니다. 응용 프로그램에 CPU 집약적인 작업이 있는 경우 운영 체제는 작업이 완료될 때까지 단일 CPU를 공유하도록 예약해야 합니다. 이로 인해 너무 많은 요청을 받으면 단일 프로세스가 과부하되어 성능이 저하될 수 있습니다. 프로세스가 충돌하면 사용자는 애플리케이션에 액세스할 수 없습니다.

해결책으로 Node.js는 라운드 로빈 알고리즘을 도입했습니다. 단일 인스턴스가 충돌하는 경우 사용자는 여전히 실행 중인 나머지 프로세스에서 서비스를 받을 수 있습니다. 여러 프로세스 간에 로드를 균등하게 공유하여 단일 인스턴스가 과부하되지 않도록 하므로 애플리케이션의 성능이 크게 향상됩니다.

이 자습서에서는 CPU가 4개 이상인 시스템에서 클러스터 모듈을 사용하여 Node.js 애플리케이션을 확장합니다. 클러스터링을 사용하지 않는 애플리케이션을 만든 다음 클러스터링을 사용하도록 앱을 수정합니다. 또한 pm2 모듈을 사용하여 여러 CPU에서 애플리케이션을 확장합니다. 부하 테스트 도구를 사용하여 클러스터링을 사용하는 앱과 그렇지 않은 앱의 성능을 비교하고 pm2 모듈을 평가합니다.

전제 조건

이 자습서를 따르려면 다음이 필요합니다.

  • CPU가 4개 이상인 시스템.
    • Ubuntu 22.04와 함께 원격 서버를 사용하는 경우 초기 서버 설정에 따라 시스템을 설정할 수 있습니다.

    1단계 - 프로젝트 디렉토리 설정

    이 단계에서는 프로젝트의 디렉터리를 만들고 이 자습서의 뒷부분에서 빌드할 애플리케이션의 종속성을 다운로드합니다. 5단계에서.

    시작하려면 디렉토리를 만드십시오. cluster_demo 또는 원하는 디렉토리 이름으로 부를 수 있습니다.

    1. mkdir cluster_demo

    다음으로 디렉터리로 이동합니다.

    1. cd cluster_demo

    그런 다음 프로젝트를 초기화하면 package.json 파일도 생성됩니다.

    1. npm init -y

    -y 옵션은 NPM이 모든 기본 옵션을 수락하도록 지시합니다.

    명령이 실행되면 다음과 일치하는 출력이 생성됩니다.

    Output
    Wrote to /home/sammy/cluster_demo/package.json: { "name": "cluster_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

    특정 프로젝트와 일치하는 다음 속성에 유의하십시오.

    • name: npm 패키지의 이름입니다.
    • version: 패키지의 버전 번호입니다.
    • main: 프로젝트의 진입점입니다.

    다른 속성에 대해 자세히 알아보려면 NPM 설명서의 package.json 섹션을 검토하세요.

    다음으로 원하는 편집기로 package.json 파일을 엽니다(이 자습서에서는 nano를 사용함).

    1. nano package.json

    package.json 파일에서 강조 표시된 텍스트를 추가하여 패키지를 가져올 때 ES 모듈 지원을 활성화합니다.

    {
      ...
      "author": "",
      "license": "ISC",
      "type": "module"
    }
    

    CTRL+X를 사용하여 파일을 저장하고 닫습니다.

    다음으로 다음 패키지를 다운로드합니다.

    • express: Node.js에서 웹 애플리케이션을 구축하기 위한 프레임워크입니다.
    • loadtest: 성능을 측정하기 위해 앱에 대한 트래픽을 생성하는 데 유용한 부하 테스트 도구입니다.
    • pm2: 앱을 여러 CPU로 자동 확장하는 도구입니다.

    다음 명령을 실행하여 Express 패키지를 다운로드합니다.

    1. npm install express

    다음으로 명령을 실행하여 전역적으로 loadtestpm2 패키지를 다운로드합니다.

    1. npm install -g loadtest pm2

    이제 필요한 종속성을 설치했으므로 클러스터링을 사용하지 않는 애플리케이션을 생성합니다.

    2단계 - 클러스터를 사용하지 않고 애플리케이션 만들기

    이 단계에서는 각 사용자가 방문할 때 CPU를 많이 사용하는 작업을 시작하는 단일 경로가 포함된 샘플 프로그램을 만듭니다. 프로그램은 클러스터 모듈을 사용하지 않으므로 하나의 CPU에서 앱의 단일 인스턴스를 실행하는 성능 영향에 액세스할 수 있습니다. 튜토리얼 뒷부분에서 이 접근 방식을 클러스터 모듈의 성능과 비교할 것입니다.

    nano 또는 좋아하는 텍스트 편집기를 사용하여 index.js 파일을 만듭니다.

    1. nano index.js

    index.js 파일에서 다음 줄을 추가하여 Express를 가져오고 인스턴스화합니다.

    import express from "express";
    
    const port = 3000;
    const app = express();
    
    console.log(`worker pid=${process.pid}`);
    

    첫 번째 줄에서 express 패키지를 가져옵니다. 두 번째 줄에서 port 변수를 애플리케이션 서버가 수신할 포트 3000으로 설정합니다. 다음으로 app 변수를 Express 인스턴스로 설정합니다. 그런 다음 내장 프로세스 모듈을 사용하여 콘솔에 애플리케이션 프로세스의 프로세스 ID를 기록합니다.

    다음으로 다음 줄을 추가하여 CPU 바운드 루프를 포함할 경로 /heavy를 정의합니다.

    ...
    app.get("/heavy", (req, res) => {
      let total = 0;
      for (let i = 0; i < 5_000_000; i++) {
        total++;
      }
      res.send(`The result of the CPU intensive task is ${total}\n`);
    });
    

    /heavy 경로에서 total 변수를 500만 번 증가시키는 루프를 정의합니다. 그런 다음 res.send() 메서드를 사용하여 total 변수의 값을 포함하는 응답을 보냅니다. CPU 바운드 작업의 예는 임의적이지만 복잡성을 추가하지 않고 CPU 바운드 작업을 보여줍니다. 경로에 다른 이름을 사용할 수도 있지만 이 자습서에서는 /heavy를 사용하여 고성능 작업을 나타냅니다.

    다음으로 Express 모듈의 listen() 메서드를 호출하여 서버가 port 변수에 저장된 포트 3000에서 수신하도록 합니다.

    ...
    app.listen(port, () => {
      console.log(`App listening on port ${port}`);
    });
    

    전체 파일은 다음과 일치합니다.

    import express from "express";
    
    const port = 3000;
    const app = express();
    
    console.log(`worker pid=${process.pid}`);
    
    app.get("/heavy", (req, res) => {
      let total = 0;
      for (let i = 0; i < 5_000_000; i++) {
        total++;
      }
      res.send(`The result of the CPU intensive task is ${total}\n`);
    });
    
    app.listen(port, () => {
      console.log(`App listening on port ${port}`);
    });
    

    코드 추가를 마쳤으면 파일을 저장하고 종료합니다. 그런 다음 node 명령을 사용하여 파일을 실행합니다.

    1. node index.js

    명령을 실행하면 출력이 다음과 일치합니다.

    Output
    worker pid=11023 App listening on port 3000

    출력에는 실행 중인 프로세스의 프로세스 ID와 서버가 3000 포트에서 수신 중임을 확인하는 메시지가 표시됩니다.

    애플리케이션이 작동하는지 테스트하려면 다른 터미널을 열고 다음 명령을 실행합니다.

    1. curl http://localhost:3000/heavy

    참고: 원격 서버에서 이 자습서를 수행하는 경우 다른 터미널을 열고 다음 명령을 입력하십시오.

    1. ssh -L 3000:localhost:3000 your_non_root_user@your_server_ip

    연결 시 다음 명령을 입력하여 curl을 사용하여 앱에 요청을 보냅니다.

    1. curl http://localhost:3000/heavy

    출력은 다음과 일치합니다.

    Output
    The result of the CPU intensive task is 5000000

    출력은 CPU 집약적 계산의 결과를 제공합니다.

    이때 CTRL+C로 서버를 중지할 수 있습니다.

    node 명령으로 index.js 파일을 실행하면 운영 체제(OS)가 프로세스를 생성합니다. 프로세스는 운영 체제가 실행 중인 프로그램을 위해 만드는 추상화입니다. OS는 프로그램에 대한 메모리를 할당하고 모든 OS 프로세스를 포함하는 프로세스 목록에 항목을 만듭니다. 해당 항목은 프로세스 ID입니다.

    그런 다음 프로그램 바이너리를 찾아 프로세스에 할당된 메모리에 로드합니다. 거기에서 실행을 시작합니다. 실행될 때 시스템의 다른 프로세스를 인식하지 못하며 프로세스에서 발생하는 모든 사항은 다른 프로세스에 영향을 미치지 않습니다.

    CPU가 여러 개인 서버에서 실행되는 Node.js 애플리케이션에 대한 단일 프로세스가 있으므로 수신되는 모든 요청을 수신하고 처리합니다. 이 다이어그램에서 들어오는 모든 요청은 다른 CPU가 유휴 상태인 동안 단일 CPU에서 실행되는 프로세스로 전달됩니다.

    이제 클러스터 모듈을 사용하지 않고 앱을 만들었으므로 클러스터 모듈을 사용하여 다음에 여러 CPU를 사용하도록 애플리케이션을 확장합니다.

    3단계 - 애플리케이션 클러스터링

    이 단계에서는 클러스터 모듈을 추가하여 동일한 프로그램의 여러 인스턴스를 생성하여 더 많은 로드를 처리하고 성능을 향상시킵니다. 클러스터 모듈로 프로세스를 실행할 때 머신의 각 CPU에서 여러 프로세스를 실행할 수 있습니다.

    이 다이어그램에서 요청은 기본 프로세스의 로드 밸런서를 통과한 다음 라운드 로빈 알고리즘을 사용하여 프로세스 간에 요청을 분배합니다.

    이제 cluster 모듈을 추가합니다. 터미널에서 primary.js 파일을 생성합니다.

    1. nano primary.js

    primary.js 파일에서 다음 줄을 추가하여 종속성을 가져옵니다.

    import cluster from "cluster";
    import os from "os";
    import { dirname } from "path";
    import { fileURLToPath } from "url";
    
    const __dirname = dirname(fileURLToPath(import.meta.url));
    

    처음 두 줄에서 clusteros 모듈을 가져옵니다. 다음 두 줄에서 dirnamefileURLToPath를 가져오며 __dirname 변수 값을 디렉토리의 절대 경로로 설정하는 데 사용합니다. index.js 파일이 실행 중입니다. ES 모듈을 사용할 때 __dirname이 정의되지 않고 CommonJS 모듈에서만 기본적으로 정의되기 때문에 이러한 가져오기가 필요합니다.

    다음으로 index.js 파일을 참조하는 다음 코드를 추가합니다.

    ...
    const cpuCount = os.cpus().length;
    
    console.log(`The total number of CPUs is ${cpuCount}`);
    console.log(`Primary pid=${process.pid}`);
    cluster.setupPrimary({
      exec: __dirname + "/index.js",
    });
    

    먼저 cpuCount 변수를 시스템의 CPU 수(4개 이상이어야 함)로 설정합니다. 다음으로 콘솔에 CPU 수를 기록합니다. 그런 다음 모든 요청을 수신할 기본 프로세스의 프로세스 ID를 기록하고 부하 분산 장치를 사용하여 작업자 프로세스 간에 배포합니다.

    그런 다음 각 작업자에서 실행되도록 cluster 모듈의 setupPrimary() 메서드를 사용하여 index.js 파일을 참조합니다. 프로세스가 생성되었습니다.

    다음으로 다음 코드를 추가하여 프로세스를 만듭니다.

    ...
    for (let i = 0; i < cpuCount; i++) {
      cluster.fork();
    }
    cluster.on("exit", (worker, code, signal) => {
      console.log(`worker ${worker.process.pid} has been killed`);
      console.log("Starting another worker");
      cluster.fork();
    });
    

    루프는 cpuCount에 있는 값만큼 반복되며 각 반복 동안 cluster 모듈의 fork() 메서드를 호출합니다. cluster 모듈의 on() 메서드를 사용하여 exit 이벤트를 연결하여 프로세스가 exit를 내보냈을 때 수신 대기합니다. code> 이벤트, 일반적으로 프로세스가 죽을 때 발생합니다. exit 이벤트가 트리거되면 죽은 작업자의 프로세스 ID를 기록한 다음 fork() 메서드를 호출하여 죽은 작업자 프로세스를 대체할 새 작업자 프로세스를 만듭니다. 프로세스.

    이제 전체 코드는 다음과 일치합니다.

    import cluster from "cluster";
    import os from "os";
    import { dirname } from "path";
    import { fileURLToPath } from "url";
    
    const __dirname = dirname(fileURLToPath(import.meta.url));
    
    const cpuCount = os.cpus().length;
    
    console.log(`The total number of CPUs is ${cpuCount}`);
    console.log(`Primary pid=${process.pid}`);
    cluster.setupPrimary({
      exec: __dirname + "/index.js",
    });
    
    for (let i = 0; i < cpuCount; i++) {
      cluster.fork();
    }
    cluster.on("exit", (worker, code, signal) => {
      console.log(`worker ${worker.process.pid} has been killed`);
      console.log("Starting another worker");
      cluster.fork();
    });
    

    줄 추가를 완료하면 파일을 저장하고 종료합니다.

    다음으로 파일을 실행합니다.

    1. node primary.js

    출력은 다음과 거의 일치합니다(프로세스 ID 및 정보 순서는 다를 수 있음).

    Output
    The total number of CPUs is 4 Primary pid=7341 worker pid=7353 worker pid=7354 worker pid=7360 App listening on port 3000 App listening on port 3000 App listening on port 3000 worker pid=7352 App listening on port 3000

    출력에는 CPU 4개, 로드 밸런서를 포함하는 기본 프로세스 1개, 포트 3000에서 수신 대기 중인 작업자 프로세스 4개가 표시됩니다.

    그런 다음 두 번째 터미널로 돌아가서 /heavy 경로로 요청을 보냅니다.

    1. curl http://localhost:3000/heavy

    출력은 프로그램이 작동하는지 확인합니다.

    Output
    The result of the CPU intensive task is 5000000

    지금 서버를 중지할 수 있습니다.

    이 시점에서 컴퓨터의 모든 CPU에서 실행 중인 4개의 프로세스가 있습니다.

    응용 프로그램에 클러스터링을 추가하면 cluster 모듈을 사용하는 것과 cluster 모듈을 사용하지 않는 것의 프로그램 성능을 비교할 수 있습니다.

    4단계 - 부하 테스트 도구를 사용한 성능 비교

    이 단계에서는 loadtest 패키지를 사용하여 구축한 두 프로그램에 대한 트래픽을 생성합니다. cluster 모듈을 사용하는 primary.js 프로그램의 성능과 사용하지 않는 index.js 프로그램의 성능을 비교할 것입니다. 클러스터링. 클러스터 모듈을 사용하는 프로그램이 클러스터링을 사용하지 않는 프로그램보다 더 빠르게 수행되고 특정 시간 내에 더 많은 요청을 처리할 수 있음을 알 수 있습니다.

    먼저 cluster 모듈을 사용하지 않고 단일 인스턴스에서만 실행되는 index.js 파일의 성능을 측정합니다.

    첫 번째 터미널에서 index.js 파일을 실행하여 서버를 시작합니다.

    1. node index.js

    앱이 실행 중이라는 출력을 받게 됩니다.

    Output
    worker pid=7731 App listening on port 3000

    그런 다음 두 번째 터미널로 돌아가서 loadtest 패키지를 사용하여 서버에 요청을 보냅니다.

    1. loadtest -n 1200 -c 200 -k http://localhost:3000/heavy

    -n 옵션은 패키지가 보내야 하는 요청 수를 허용하며 여기서는 1200 요청입니다. -c 옵션은 서버에 동시에 보내야 하는 요청 수를 허용합니다.

    요청이 전송되면 패키지는 다음과 유사한 출력을 반환합니다.

    Output
    Requests: 0 (0%), requests per second: 0, mean latency: 0 ms Requests: 430 (36%), requests per second: 87, mean latency: 1815.1 ms Requests: 879 (73%), requests per second: 90, mean latency: 2230.5 ms Target URL: http://localhost:3000/heavy Max requests: 1200 Concurrency level: 200 Agent: keepalive Completed requests: 1200 Total errors: 0 Total time: 13.712728601 s Requests per second: 88 Mean latency: 2085.1 ms Percentage of the requests served within a certain time 50% 2234 ms 90% 2340 ms 95% 2385 ms 99% 2406 ms 100% 2413 ms (longest request)

    이 출력에서 다음 메트릭을 기록해 두십시오.

    • 총 시간은 모든 요청이 처리되는 데 걸린 시간을 측정합니다. 이 출력에서 모든 1200 요청을 처리하는 데 13초가 조금 넘게 걸렸습니다.
    • 초당 요청은 서버가 초당 처리할 수 있는 요청 수를 측정합니다. 이 출력에서 서버는 초당 88 요청을 처리합니다.
    • 평균 대기 시간은 요청을 보내고 응답을 받는 데 걸린 시간을 측정하며 샘플 출력에서 2085.1ms입니다.

    이러한 메트릭은 네트워크 또는 프로세서 속도에 따라 다르지만 이러한 예에 가깝습니다.

    index.js 파일의 성능을 측정했으므로 이제 서버를 중지할 수 있습니다.

    다음으로 cluster 모듈을 사용하는 primary.js 파일의 성능을 측정합니다.

    그렇게 하려면 첫 번째 터미널로 돌아가 primary.js 파일을 다시 실행합니다.

    1. node primary.js

    이전과 동일한 정보가 포함된 응답을 받게 됩니다.

    Output
    The total number of CPUs is 4 Primary pid=7841 worker pid=7852 App listening on port 3000 worker pid=7854 App listening on port 3000 worker pid=7853 worker pid=7860 App listening on port 3000 App listening on port 3000

    두 번째 터미널에서 loadtest 명령을 다시 실행합니다.

    1. loadtest -n 1200 -c 200 -k http://localhost:3000/heavy

    완료되면 유사한 출력을 받게 됩니다(시스템의 CPU 수에 따라 다를 수 있음).

    Output
    Requests: 0 (0%), requests per second: 0, mean latency: 0 ms Target URL: http://localhost:3000/heavy Max requests: 1200 Concurrency level: 200 Agent: keepalive Completed requests: 1200 Total errors: 0 Total time: 3.412741962 s Requests per second: 352 Mean latency: 514.2 ms Percentage of the requests served within a certain time 50% 194 ms 90% 2521 ms 95% 2699 ms 99% 2710 ms 100% 2759 ms (longest request)

    cluster 모듈과 함께 실행되는 primary.js 앱에 대한 출력은 총 시간이 실행되지 않는 프로그램의 13초에서 3초로 줄었음을 나타냅니다. 클러스터링을 사용하지 마십시오. 서버가 초당 처리할 수 있는 요청 수가 이전 88에서 352로 3배 증가하여 서버에 엄청난 부하가 걸릴 수 있습니다. 또 다른 중요한 메트릭은 2085.1ms에서 514.2ms로 크게 감소한 평균 대기 시간입니다.

    이 응답은 조정이 작동했으며 애플리케이션이 지연 없이 짧은 시간에 더 많은 요청을 처리할 수 있음을 확인합니다. 더 많은 CPU를 갖도록 컴퓨터를 업그레이드하면 앱이 CPU 수에 맞게 자동으로 확장되어 성능이 더욱 향상됩니다.

    참고로 터미널 출력의 메트릭은 네트워크 및 프로세서 속도로 인해 달라집니다. 총 시간과 평균 대기 시간이 크게 감소하고 총 시간이 빠르게 증가합니다.

    비교를 수행하고 클러스터 모듈을 사용할 때 앱의 성능이 더 좋다는 점을 확인했으므로 이제 서버를 중지할 수 있습니다. 다음 단계에서는 cluster 모듈 대신 pm2를 사용합니다.

    5단계 - 클러스터링에 pm2 사용

    지금까지 클러스터 모듈을 사용하여 시스템의 CPU 수에 따라 작업자 프로세스를 생성했습니다. 작업자 프로세스가 종료되면 다시 시작하는 기능도 추가했습니다. 이 단계에서는 클러스터 모듈에 구축된 pm2 프로세스 관리자를 사용하여 앱 크기 조정을 자동화하는 대안을 설정합니다. 이 프로세스 관리자는 로드 밸런서를 포함하며 컴퓨터의 CPU만큼 많은 작업자 프로세스를 자동으로 생성할 수 있습니다. 또한 프로세스를 모니터링할 수 있으며 하나가 죽으면 새 작업자 프로세스를 자동으로 생성할 수 있습니다.

    이를 사용하려면 확장해야 하는 파일(이 자습서의 index.js 파일)과 함께 pm2 패키지를 실행해야 합니다.

    초기 터미널에서 다음 명령을 사용하여 pm2 클러스터를 시작합니다.

    1. pm2 start index.js -i 0

    -i 옵션은 pm2가 생성할 작업자 프로세스 수를 허용합니다. 0 인수를 전달하면 pm2는 시스템에 있는 CPU 수만큼 작업자 프로세스를 자동으로 생성합니다.

    명령을 실행하면 pm2가 작업자 프로세스에 대한 자세한 정보를 표시합니다.

    Output
    ... [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/cluster_demo/index.js in cluster_mode (0 instance) [PM2] Done. ┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │ ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0 │ index │ default │ 1.0.0 │ cluster │ 7932 │ 0s │ 0 │ online │ 0% │ 54.5mb │ nod… │ disabled │ │ 1 │ index │ default │ 1.0.0 │ cluster │ 7939 │ 0s │ 0 │ online │ 0% │ 50.9mb │ nod… │ disabled │ │ 2 │ index │ default │ 1.0.0 │ cluster │ 7946 │ 0s │ 0 │ online │ 0% │ 51.3mb │ nod… │ disabled │ │ 3 │ index │ default │ 1.0.0 │ cluster │ 7953 │ 0s │ 0 │ online │ 0% │ 47.4mb │ nod… │ disabled │ └─────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

    이 테이블에는 각 작업자의 프로세스 ID, 상태, CPU 사용률 및 메모리 사용량이 포함되어 있어 프로세스 작동 방식을 이해하는 데 사용할 수 있습니다.

    pm2로 클러스터를 시작하면 패키지가 백그라운드에서 실행되며 시스템을 재부팅해도 자동으로 다시 시작됩니다.

    작업자 프로세스에서 로그를 읽으려면 다음 명령을 사용할 수 있습니다.

    1. pm2 logs

    로그 출력을 받게 됩니다.

    Output
    [TAILING] Tailing last 15 lines for [all] processes (change the value with --lines option) /home/sammy/.pm2/pm2.log last 15 lines: ... PM2 | 2022-12-25T17:48:37: PM2 log: App [index:3] starting in -cluster mode- PM2 | 2022-12-25T17:48:37: PM2 log: App [index:3] online /home/sammy/.pm2/logs/index-error.log last 15 lines: /home/sammy/.pm2/logs/index-out.log last 15 lines: 0|index | worker pid=7932 0|index | App listening on port 3000 0|index | worker pid=7953 0|index | App listening on port 3000 0|index | worker pid=7946 0|index | worker pid=7939 0|index | App listening on port 3000 0|index | App listening on port 3000

    마지막 8줄에서 로그는 프로세스 ID 및 포트 번호 3000을 포함하여 실행 중인 작업자 프로세스 4개 각각의 출력을 제공합니다. 이 출력은 모든 프로세스가 실행 중임을 확인합니다.

    다음 명령을 사용하여 프로세스의 상태를 확인할 수도 있습니다.

    1. pm2 ls

    출력은 다음 표와 일치합니다.

    Output
    ┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │ ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0 │ index │ default │ 1.0.0 │ cluster │ 7932 │ 5m │ 0 │ online │ 0% │ 56.6mb │ nod… │ disabled │ │ 1 │ index │ default │ 1.0.0 │ cluster │ 7939 │ 5m │ 0 │ online │ 0% │ 55.7mb │ nod… │ disabled │ │ 2 │ index │ default │ 1.0.0 │ cluster │ 7946 │ 5m │ 0 │ online │ 0% │ 56.5mb │ nod… │ disabled │ │ 3 │ index │ default │ 1.0.0 │ cluster │ 7953 │ 5m │ 0 │ online │ 0% │ 55.9mb │ nod… │ disabled │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

    이제 클러스터가 실행 중이므로 동일한 터미널에 다음 명령을 입력하여 성능을 테스트합니다.

    1. loadtest -n 1200 -c 200 -k http://localhost:3000/heavy

    출력은 다음과 거의 일치합니다.

    Output
    Requests: 0 (0%), requests per second: 0, mean latency: 0 ms Target URL: http://localhost:3000/heavy Max requests: 1200 Concurrency level: 200 Agent: keepalive Completed requests: 1200 Total errors: 0 Total time: 3.771868785 s Requests per second: 318 Mean latency: 574.4 ms Percentage of the requests served within a certain time 50% 216 ms 90% 2859 ms 95% 3016 ms 99% 3028 ms 100% 3084 ms (longest request)

    총 시간, 초당 요청평균 대기 시간클러스터를 사용할 때 생성된 측정항목에 가깝습니다. 기준 치수. 이 정렬은 pm2 스케일링이 유사하게 작동함을 보여줍니다.

    pm2로 작업 흐름을 개선하기 위해 애플리케이션에 대한 구성 설정을 전달하는 구성 파일을 생성할 수 있습니다. 이 접근 방식을 사용하면 옵션을 전달하지 않고 클러스터를 시작하거나 다시 시작할 수 있습니다.

    구성 파일을 사용하려면 현재 클러스터를 삭제합니다.

    1. pm2 delete index.js

    사라 졌다는 응답을 받게 됩니다.

    Output
    [PM2] Applying action deleteProcessId on app [index.js](ids: [ 0, 1, 2, 3 ]) [PM2] [index](2) ✓ [PM2] [index](1) ✓ [PM2] [index](0) ✓ [PM2] [index](3) ✓ ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

    다음으로 구성 파일을 생성합니다.

    1. pm2 ecosystem

    출력에서 파일이 생성되었음을 확인할 수 있습니다.

    Output
    File /home/sammy/cluster_demo/ecosystem.config.js generated

    ES 모듈 지원을 활성화하려면 .js.cjs로 이름을 바꿉니다.

    1. mv ecosystem.config.js ecosystem.config.cjs

    편집기를 사용하여 구성 파일을 엽니다.

    1. nano ecosystem.config.cjs

    ecosystem.config.cjs 파일에서 아래 강조 표시된 코드를 추가합니다.

    module.exports = {
      apps : [{
        script: 'index.js',
        watch: '.',
        name: "cluster_app",
        instances: 0,
        exec_mode: "cluster",
      }, {
        script: './service-worker/',
        watch: ['./service-worker']
      }],
    
      deploy : {
        production : {
          user : 'SSH_USERNAME',
          host : 'SSH_HOSTMACHINE',
          ref  : 'origin/master',
          repo : 'GIT_REPOSITORY',
          path : 'DESTINATION_PATH',
          'pre-deploy-local': '',
          'post-deploy' : 'npm install && pm2 reload ecosystem.config.cjs --env production',
          'pre-setup': ''
        }
      }
    };
    

    script 옵션은 pm2 패키지가 생성할 각 프로세스에서 실행할 파일을 허용합니다. name 속성은 클러스터를 식별할 수 있는 모든 이름을 허용하므로 중지, 다시 시작 또는 다른 작업을 수행해야 하는 경우 도움이 될 수 있습니다. instances 속성은 원하는 인스턴스 수를 허용합니다. 인스턴스0으로 설정하면 pm2가 CPU만큼 많은 프로세스를 생성합니다. exec_modepm2가 클러스터에서 실행되도록 지시하는 cluster 옵션을 허용합니다.

    완료되면 파일을 저장하고 닫습니다.

    클러스터를 시작하려면 다음 명령을 실행합니다.

    1. pm2 start ecosystem.config.cjs

    다음과 같은 응답을 받게 됩니다.

    Output
    [PM2][WARN] Applications cluster_app, service-worker not running, starting... [PM2][ERROR] Error: Script not found: /home/node-user/cluster_demo/service-worker [PM2] App [cluster_app] launched (4 instances)

    마지막 줄은 4 프로세스가 실행 중임을 확인합니다. 이 자습서에서는 service-worker 스크립트를 만들지 않았으므로 service-worker를 찾을 수 없다는 오류는 무시해도 됩니다.

    클러스터가 작동 중인지 확인하려면 상태를 확인하십시오.

    1. pm2 ls

    4개의 프로세스가 실행 중임을 확인하는 응답을 받게 됩니다.

    Output
    ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ cluster_app │ cluster │ 0 │ online │ 0% │ 56.9mb │ │ 1 │ cluster_app │ cluster │ 0 │ online │ 0% │ 57.6mb │ │ 2 │ cluster_app │ cluster │ 0 │ online │ 0% │ 55.9mb │ │ 3 │ cluster_app │ cluster │ 0 │ online │ 0% │ 55.9mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

    클러스터를 다시 시작하려면 ecosystem.config.cjs 파일에서 정의한 앱 이름을 사용할 수 있습니다. 이 경우 cluster_app입니다.:

    1. pm2 restart cluster_app

    클러스터가 다시 시작됩니다.

    Output
    Use --update-env to update environment variables [PM2] Applying action restartProcessId on app [cluster_app](ids: [ 0, 1, 2, 3 ]) [PM2] [cluster_app](0) ✓ [PM2] [cluster_app](1) ✓ [PM2] [cluster_app](2) ✓ [PM2] [cluster_app](3) ✓ ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ cluster_app │ cluster │ 1 │ online │ 0% │ 48.0mb │ │ 1 │ cluster_app │ cluster │ 1 │ online │ 0% │ 47.9mb │ │ 2 │ cluster_app │ cluster │ 1 │ online │ 0% │ 38.8mb │ │ 3 │ cluster_app │ cluster │ 1 │ online │ 0% │ 31.5mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

    클러스터 관리를 계속하려면 다음 명령을 실행할 수 있습니다.

    Command Description
    pm2 start app_name Starts the cluster
    pm2 restart app_name Kills the cluster and starts it again
    pm2 reload app_name Restarts the cluster without downtime
    pm2 stop app_name Stops the cluster
    pm2 delete app_name Deletes the cluster

    이제 pm2 모듈과 cluster 모듈을 사용하여 애플리케이션을 확장할 수 있습니다.

    결론

    이 자습서에서는 클러스터 모듈을 사용하여 애플리케이션을 확장했습니다. 먼저 cluster 모듈을 사용하지 않는 프로그램을 만들었습니다. 그런 다음 클러스터 모듈을 사용하여 앱을 컴퓨터의 여러 CPU로 확장하는 프로그램을 만들었습니다. 그런 다음 클러스터 모듈을 사용하는 앱과 그렇지 않은 앱의 성능을 비교했습니다. 마지막으로 클러스터 모듈 대신 pm2 패키지를 사용하여 여러 CPU에서 앱을 확장했습니다.

    더 진행하려면 클러스터 모듈 설명서 페이지를 방문하여 모듈에 대해 자세히 알아볼 수 있습니다.

    pm2를 계속 사용하려면 Ubuntu 22.04에서 프로덕션용 Node.js 애플리케이션을 설정하는 방법을 참조하세요.

    Node.js는 또한 Node.js 및 BullMQ로 비동기 작업을 처리하는 방법과 함께 제공됩니다.