안녕하세요 원래 기본적인 포스팅은 따로 안하려고 하는 편인데 자동화 플랫폼내에서는 필수적인 요소이기 때문에
기본부터 차근차근 넣어 놓으려고합니다.
실제 서버는 리눅스 환경이지만 현재는 윈도우즈에서 테스트를 하고있기 때문에 윈도우즈에서 우선 작성하도록 하겠습니다.
Node.js 가 설치된 상태로 PM2 를 글로벌 로 설치 후 테스트 시 아래와 같은 오류가 발생합니다.
npm i -g pm2
pm2 list
pm2 : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\Users\GDL\AppData\Roaming\npm\pm2.ps1 파일을 로드할 수 없습니다. 자세한 내용은 about_Execution_Policies(https://go.microsoft.com/fwlink/?LinkID=135170)를 참조하십시오.
위치 줄: 1 문자 :1
pm2 list
CategoryInfo : 보안 오류 : ( :) [], PSSecurityExeception
FullyQualifiedErrorId : UnauthorizedAccess
인터넷에서 간단하게 구글링을 해보면 파워 쉘을 킨 후에 ExecutionPolicy Unrestricted 을 통해서 해제를 하라는 이야기들이 많이 있습니다.
Get-ExecutionPolicy : 'Scope' 매개 변수를 바인딩할 수 없습니다. 값 "Unrestricted"을(를) "Microsoft.PowerShell.Execution
PolicyScope" 유형으로 변환할 수 없습니다. 오류: "식별자 이름 Unrestricted을(를) 유효한 열거자 이름과 일치시킬 수 없습니
다. 다음 열거자 이름 중 하나를 지정한 후 다시 시도하십시오.
Process, CurrentUser, LocalMachine, UserPolicy, MachinePolicy"
위치 줄:1 문자:17
+ ExecutionPolicy Unrestricted
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ExecutionPolicy], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetExecutionPolicyCommand
실제 실행시에는 위처럼 발생하며 아래와 같은 방식을 사용해야 합니다.
이제 pm2가 준비 되었으니 기본적으로 pm2 cluster 를 기본적으로 해보도록 하겠습니다.
const express = require('express')
const app = express()
app.get('/', function (req, res) {
res.send('Hello World ')
})
app.listen(3000,()=>{
console.log('Example Clustering App on Port 3000')
})
테스트에 사용할 express 기본 코드입니다.
npmjs.com 에서 pm2 의 cluster mode를 보면 아래를 참고하라고 되어있습니다.
https://pm2.keymetrics.io/docs/usage/cluster-mode/
npmjs 간단 설명입니다.
클러스터 모드는 Node.js 애플리케이션을 시작할 때의 특수 모드로, 여러 프로세스를 시작하고 이들 사이에서 HTTP/TCP/UDP 쿼리를 로드 밸런싱합니다. 이렇게 하면 전체 성능(16코어 시스템에서 10배)과 안정성(처리되지 않은 오류의 경우 더 빠른 소켓 재조정)이 향상됩니다.
const express = require('express')
const app = express()
let i=0;
function wait (time){
return new Promise(async(resolve)=>{
setTimeout(()=>{
resolve(true)
},time)
})
}
app.get('/',async function (req, res) {
try {
const randomNumber =Math.floor( Math.random()*1000 );
await wait(2000);
console.log(`Count ${i}`);
i++;
res.send('test '+ randomNumber)
} catch (error) {
console.error(error);
}
})
app.listen(3000,()=>{
console.log('Example Clustering App on Port 3000')
})
express 코드를 살짝 수정하였습니다. / 의 Router에서 임의로 2000ms 의 시간을 두었습니다. 이렇게 되면 서버 1대로 돌릴 경우 웹에서 접속시 아래와같이 대기 시간이 생길수 있습니다.
해당 딜레이를 pm2 모니터로 확인시
PM2 Cluster 를 통하여서 해당 로딩이 없이 바로 바로 응답을 줄수 있도록 변경해보겠습니다.
해당 Cluster를 최대한으로 쓰기전에 현재 CPU 의 개수 먼저 확인해보니
const os = require('os')
const cpuCount = os.cpus().length
16개로 나오네요 자 이제 클러스터 모드를 사용하기 위해 공식홈페이지 Usage를 따라 세팅하도록 하겠습니다.
pm2 start app.js -i max
기본적인 로컬 PC의 CPU 개수만큼을 전부 사용 하는 모습입니다. 실제로 서버에서 요청도 다 받아 지는지 보겠습니다.
4번의 요청을 해보았을시 pm2 모니터를 통해 확인해보니 process 가 여러개 동작하는건 맞지만 실제로 제가 생각했던건 알아서 로드밸런싱을 해주는 형태였는데 해당 형태로는 절대 동작하지 않음을 알수 있습니다. 15번 app이 Idle타임을 가질경우 다른 서버가 대신 처리를 해줬어야 하는건데 말이죠
해당 클러스터링 모드는 단순히 서버 한대가 돌아가다가 죽었을 경우 다음 서버가 일을 해주는 형태입니다.
여러 블로그들을 검색해서 찾아봤을 경우 대충 공식 홈페이지나 번역 하거나 의역하고 끝내는 경우가 많아서 좀더 찾아 보니 결국은 Node.js의 Cluster mode를 사용한 경우면 parent process에서 child_proces를 fork 로 여러대의 APP 을 띄워서 무중단 배포나 앞단에 서버가 죽었을 경우에 대한 처리를 이용하는 형태로 사용되며 결국 제가 원하는 로드밸런싱을 사용하기 위해서는 nginx의 로드밸런싱 기능을 같이 사용해야 합니다.
=> 오해가 있을수 있어 추가합니다. 해당 서버들의 CPU I/O 나 메모리의 사용률이 높아질 경우 알아서 클러스터링이 되지만 테스트 자동화의 경우 Idle타임을 사용하기 때문에 다른 클러스터를 사용해야한다고 인지 하지 못하여 클러스터링이 되지않는 것입니다. ( 실제 클러스터링 되는 경우 하단의 테스트결과를 넣었습니다.)
module.exports = {
apps : [
{
name :"clusterTest",
script : "app.js",
instances : "4",
exec_mode : "cluster",
wait_ready: true,
listen_timeout: 50000,
kill_timeout: 5000,
watch: true, // 파일이 변경되었을 때 재시작 할지 선택
}
]
}
마지막으로 테스트하였던 ecosystem.config.js 입니다. watch의 경우 파일 변경시 재시작인데 일반적으로는 쓰지 않는게 좋겠네요
nginx 연동으로 LB처리는 실제로 쓰고있는 자동화 플랫폼 앞단에 처리하도록 하면서 다시 포스팅하겠습니다.
감사합니다.
--> 위에 로드밸런싱의경우 오해할수 있는 내용이 있어서 수정 하려고 합니다.
PM2 Cluster 를 사용할 경우 CPU , 메모리 등의 점유율에 따라 클러스터링을 해주고 있기 때문에
테스트 자동화에 사용되는 Test Runner 들은 CPU , 메모리를 많이 쓴다기보단 Idle time 을 많이 사용하게 됩니다.
그렇기 때문에 pm2 로 클러스터링을 늘려놔도 Test Runner 를 사용하기 위한 Idle time에서는 해당 클러스터링을 위한 조건에 부합하지 않기 때문에 동작되지 않는 것 처럼 보입니다. Round Robin 같은 방식이 아니기 때문에 그렇게 보이는 것이며
동작 예시를 아래에 추가 하였습니다.
pm2 monit
그리고 해당 cluster_app은
새로 생성한 앱이라면 새로운 UUID를 response 로 주는 기본 서버입니다.
해당 코드로 비동기로 사용시
안되는 것처럼 보입니다.
하지만 100이 아니라 5000번을 사용한다면 아마 200ms (0.2초안에 5000번이 접속시도)
최대 3개의 서버에서 돌아가면서 클러스터링 됨을 알수 있습니다. ㅎㅎ 좀더 직관적으로 보기 위해서 gif로 보여드리겠습니다.
정상적으로 클러스터링 되어 동작 함을 확인할수 있습니다 ㅎㅎ
테스트 러너의 사용성에 살짝 부합하지 않을뿐 pm2 cluster 는 엄청 좋은 모듈입니다