pm2
이 패키지는 ‘개발할 때 nodemon을 쓴다면, 배포할 때는 pm2를 쓴다’는 말이 있을 정도로 유용합니다.
가장 큰 기능은 서버가 에러로 인해 꺼졌을 때 서버를 다시 켜주는 것입니다.
또 하나 중요한 기능은 바로 멀티 프로세싱입니다.
멀티 스레딩은 아니지만 멀티 프로세싱을 지원해 노드 프로세스 개수를 한 개 이상으로 늘릴 수 있습니다.
기본적으로는 CPU 코어를 하나만 사용하는데, pm2를 사용해서 프로세스를 여러 개 만들면 다른 코어들까지 사용할 수 있습니다.
클라이언트로부터 요청이 올 때 알아서 요청을 여러 노드 프로세스에 고르게 분배합니다.
그럼 하나의 프로세스가 받는 부하가 적어지므로 서비스를 더 원활하게 운영할 수 있습니다.
단점도 있습니다.
멀티 스레딩이 아니므로 서버의 메모리 같은 자원을 공유하지는 못합니다.
지금까지 세션을 메모리에 저장했는데, 메모리를 공유하지 못해서 프로세스 간에 세션이 공유되지 않게 됩니다.
로그인 후 새로 고침을 반복할 때 세션 메모리가 있는 프로세스로 요청이 가면 로그인된 상태가 되고,
세션 메모리가 없는 프로세스로 요청이 가면 로그인되지 않은 상태가 되는 것입니다.
이 문제를 극복하려면 세션을 공유할 수 있게 해주는 무언가가 필요합니다.
이를 위해 주로 멤캐시드(Memcached)나 레디스(Redis) 같은 서비스를 사용합니다.
npm i pm2
pm2는 nodemon처럼 콘솔에 입력하는 명령어입니다.
package.json을 수정합니다.
nodemon 대신 pm2를 쓰도록 npm start 스크립트를 수정할 것입니다.
start 스크립트에 node server 대신 pm2 start server.js를 입력했습니다.
pm2로 스크립트를 실행하는 명령어입니다.
pm2를 실행했더니 다른 점이 있습니다.
node나 nodemon 명령어와는 다르게 노드 프로세스가 실행된 후 콘솔에 다른 명령어를 입력할 수 있습니다.
pm2가 노드 프로세스를 백그라운드로 돌리므로 가능한 것입니다.
백그라운드에서 돌고 있는 노드 프로세스를 확인할 방법이 필요한데, npx pm2 list 명령어를 사용하면 됩니다.
npm start를 실행했을 때처럼 현재 프로세스 정보가 표시됩니다.
프로세스 아이디(pid), CPU와 메모리 사용량(mem) 등이 보여 편리합니다.
uptime과 status 사이에 재시작된 횟수가 나오는데, 0이 아니라면 서버가 재부팅된 적이 있다는 것을 의미합니다.
이 경우에는 왜 재시작되었는지 확인해봐야 합니다. npx pm2 logs로 로그를 확인할 수 있습니다.
에러 로그만 보고 싶다면 뒤에--err을 붙이면 됩니다.
출력 줄 수를 바꾸고 싶다면 --lines 숫자 옵션을 사용합니다.
나중에 pm2 프로세스를 종료하고 싶다면 콘솔에 npx pm2 kill을 입력하면 됩니다.
서버를 재시작하고 싶다면 npx pm2 reload all을 입력합니다.
다운타임(서버가 중지되어 클라이언트가 접속할 수 없는 시간)이 거의 없이 서버가 재시작되어 좋습니다.
노드의 cluster 모듈처럼 클러스터링을 가능하게 하는 pm2의 클러스터링 모드를 사용해봅시다.
pm2 start app.js 대신에 pm2 start app.js -i 0 명령어를 사용합니다.
취향에 따라 pm2 start app.js -i -1도 많이 사용합니다. -i 뒤에 생성하길 원하는 프로세스 개수를 기입하면 됩니다.
0은 현재 CPU 코어 개수만큼 프로세스를 생성한다는 뜻이고,
-1은 프로세스를 CPU 코어 개수보다 한 개 덜 생성하겠다는 뜻입니다.
남은 코어 하나는 노드 외의 다른 작업을 할 수 있게 하는 것입니다. 예제에서는 -i 0을 사용합니다.
npx pm2 kill로 서버를 종료한 뒤 변경된 명령어를 사용해봅시다.
&&를 사용해 여러 개의 명령어를 연달아 실행할 수 있습니다.
예제를 작성한 컴퓨터는 코어가 10개이므로 프로세스가 10개 생성되었고,
mode가 cluster로 되어 있어 클러스터링 중임을 알 수 있습니다.
현재 프로세스를 모니터링할 수도 있습니다. npx pm2 monit으로 가능합니다.
실제 서버를 운영할 때, 서비스 규모가 커질수록 비용이 발생할 가능성이 커지므로
놀고 있는 코어까지 클러스터링으로 작동하게 하는 것이 비용을 절약하는 길입니다.
하지만 프로세스 간에 메모리를 공유하지 못하는 문제도 있으므로 최대한 프로세스 간에 공유하는 것(세션 등)이 없도록 설계해야 합니다. 공유해야 하는 데이터가 있다면 데이터베이스를 사용해야 합니다.
winston
실제 서버를 운영할 때 console.log와 console.error를 대체하기 위한 모듈입니다.
console.log와 console.error를 사용하면 개발 중에는 편리하게 서버의 상황을 파악할 수 있지만,
실제 배포 시에는 사용하기 어렵습니다.
console 객체의 메서드들이 언제 호출되었는지 파악하기 힘들 뿐만 아니라 서버가 종료되는 순간 로그들도 사라져버리기 때문입니다.
에러가 발생하면 에러 메시지를 확인해야 하는데, 서버가 종료돼서 에러 메시지들이 날아가버리는 황당한 일이 일어나게 됩니다.
이와 같은 상황을 방지하려면 로그를 파일이나 다른 데이터베이스에 저장해야 합니다. 이때 winston을 사용합니다.
winston을 설치하고 사용 방법을 간단히 알아보겠습니다.
너무나 다양한 방식으로 활용할 수 있어 기본적인 것만 살펴봅니다.
npm i winston
winston을 설치한 뒤, logger.js를 작성합니다.
winston 패키지의 createLogger 메서드로 logger를 만듭니다.
인수로 logger에 대한 설정을 넣어줄 수 있습니다. 설정으로는 level, format, transports 등이 있습니다.
• level은 로그의 심각도를 의미합니다. error, warn, info, verbose, debug, silly가 있습니다.
심각도순(error가 가장 심각)이므로 위 순서를 참고해 기록하길 원하는 유형의 로그를 고르면 됩니다.
info를 고른 경우, info보다 심각한 단계의 로그(error, warn)도 함께 기록됩니다.
• format은 로그의 형식입니다. json, label, timestamp, printf, simple, combine 등의 다양한 형식이 있습니다.
기본적으로는 JSON 형식으로 기록하지만, 로그 기록 시간을 표시하려면 timestamp를 쓰는 것이 좋습니다.
combine은 여러 형식을 혼합해서 사용할 때 씁니다. 활용법이 다양하므로 공식 문서를 참고하길 바랍니다.
• transports는 로그 저장 방식을 의미합니다. new transports.File은 파일로 저장한다는 뜻이고,
new transports.Console은 콘솔에 출력한다는 뜻입니다. 여러 로깅 방식을 동시에 사용할 수도 있습니다.
배포 환경이 아닌 경우 파일뿐만 아니라 콘솔에도 출력하도록 되어 있습니다.
이 메서드들에도 level, format 등을 설정할 수 있습니다.
new transports.File인 경우에는 로그 파일의 이름인 filename도 설정할 수 있습니다.
이렇게 logger 객체를 만들어 다른 파일에서 사용하면 됩니다.
info, warn, error 등의 메서드를 사용하면 해당 심각도가 적용된 로그가 기록됩니다.
npm run dev 명령어로 개발용 서버를 실행한 후 http://localhost:8001/abcd에 접속해봅시다.
없는 주소이므로 404 Not Found 에러가 발생합니다.
info 이상 단계의 모든 로그를 기록하도록 되어 있는 combined.log 파일에는 info와 error 단계의 로그가 저장되었습니다.
error 단계의 로그만 기록하도록 되어 있는 error.log에는 error 단계의 로그만 저장되었습니다.
이렇게 로그를 콘솔에만 출력하는 것이 아니라, 파일로도 저장할 수 있어 실제 서비스를 운영할 때 유용합니다.
helmet, hpp
서버의 각종 취약점을 보완해주는 패키지들이며, 익스프레스 미들웨어로서 사용할 수 있습니다.
이 패키지들을 사용한다고 해서 모든 취약점을 방어해주는 것은 아니므로
서버를 운영할 때는 주기적으로 취약점을 점검해야 합니다.
npm i helmet hpp
개발 환경에서는 사용할 필요가 없으므로 배포 환경일 때만 적용하면 됩니다.
helmet과 hpp가 방어해주는 취약점 목록은 각각의 공식 문서(15.7절 참조)에 나와 있습니다.
기본적으로는 배포 전에 이 두 패키지를 넣어주는 것이 좋습니다.
다만, 때로는 보안 규칙을 너무 엄격하게 적용해서 서비스가 제대로 돌아가지 않는 경우도 있으니, 예제에서 contentSecurityPolicy, crossOriginEmbedderPolicy, crossOriginResourcePolicy를 false로 했듯이
공식 문서를 보면서 필요 없는 옵션은 해제해야 합니다.
'clone toy projects > node_express_sns' 카테고리의 다른 글
AWS light sail 사용해서 배포하기 (0) | 2023.08.31 |
---|---|
서비스 운영을 위한 패키지[redis, nvm] (0) | 2023.08.31 |
서비스 운영을 위한 패키지[morgan,express-session,시퀄라이즈,cross-env, sanitize-html, csurf] (0) | 2023.08.31 |
부하 테스트 (0) | 2023.08.29 |
통합 테스트 (0) | 2023.08.29 |