You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
애플리케이션이나 서버가 종료될 때, 실행 중인 작업을 안전하게 처리하고 리소스를 정리하며 종료하는 과정을 말합니다. 이는 단순히 강제로 프로세스를 종료하는 것과는 달리, 시스템이 정상적인 상태에서 종료되도록 도와줍니다.
❔ Graceful Shutdown의 필요성
데이터 손실 방지: 실행 중인 요청이나 트랜잭션이 갑작스럽게 중단되면 데이터가 손실되거나 손상될 수 있습니다. Graceful Shutdown은 이를 방지합니다.
일관성 유지: 애플리케이션이 예상치 못한 종료로 인해 시스템 상태가 불일치하게 되는 것을 방지합니다.
리소스 정리: 파일, 데이터베이스 연결, 네트워크 소켓 등 사용 중인 리소스를 정리하여 메모리 누수나 리소스 잠금을 방지합니다.
사용자 경험 향상: 서비스가 종료되더라도 사용자 요청을 가능한 한 마무리하여 부정적인 영향을 최소화합니다.
🏗️ Graceful Shutdown의 작동 방식
종료 신호 수신:
운영 체제에서 종료 신호(SIGTERM, SIGINT 등)를 받습니다.
새 작업 수락 중단:
새 요청을 수락하지 않고, 기존 요청 처리에 집중합니다.
예를 들어, 웹 서버는 더 이상 클라이언트 요청을 받지 않습니다.
기존 작업 완료:
현재 진행 중인 작업(예: 데이터 저장, 파일 처리, API 응답 등)을 완료합니다.
제한 시간을 두어 너무 오래 걸리지 않도록 설정할 수도 있습니다.
리소스 정리:
열려 있는 파일, 데이터베이스 연결, 네트워크 소켓 등을 닫습니다.
캐시나 임시 데이터를 정리합니다.
프로세스 종료:
모든 작업이 완료되면 프로세스를 안전하게 종료합니다.
Node.js 기반의 Express 서버 구현 예시 코드
constexpress=require('express');constapp=express();letserver;app.get('/',(req,res)=>{res.send('Hello World!');});// 서버 시작server=app.listen(3000,()=>{console.log('Server is running on port 3000');});// Graceful Shutdown 구현process.on('SIGTERM',()=>{console.log('SIGTERM signal received: closing HTTP server');server.close(()=>{console.log('HTTP server closed');// 추가적인 리소스 정리 작업 (예: DB 연결 종료)process.exit(0);});});process.on('SIGINT',()=>{console.log('SIGINT signal received: closing HTTP server');server.close(()=>{console.log('HTTP server closed');process.exit(0);});});
next.js에서 적용하기
#8 에서 작성한 server.js 에 graceful shutdown 코드를 추가하였다.
//server.jsconst{ createServer }=require('http');const{ parse }=require('url');constnext=require('next');constv8=require('v8');constdev=process.env.NODE_ENV!=='production';constapp=next({ dev });consthandle=app.getRequestHandler();constactiveConnections=newSet();// 활성 연결을 추적하기 위한 Setapp.prepare().then(()=>{constserver=createServer((req,res)=>{constparsedUrl=parse(req.url,true);handle(req,res,parsedUrl);});console.log(`App started with PID: ${process.pid}`);server.listen(3000,(err)=>{if(err)throwerr;console.log('> Ready on frontend server');});// 활성 연결 추적server.on('connection',(socket)=>{activeConnections.add(socket);socket.on('close',()=>{activeConnections.delete(socket);});});// Graceful shutdown 처리process.on('SIGTERM',async()=>{console.log('SIGTERM received. Closing server...');server.close(()=>{console.log('Server closed. Closing active connections...');// 모든 활성 연결 강제 종료activeConnections.forEach((socket)=>socket.destroy());setTimeout(()=>{console.log('Shutdown after sleep.');process.exit(0);// 정상 종료},70000);});});// SIGINT 처리 (Ctrl+C)process.on('SIGINT',()=>{console.log('SIGINT received. Performing graceful shutdown...');server.close(()=>{console.log('Server closed.');process.exit(0);// 정상 종료});});});// 종료 시 code 출력process.on('exit',(code)=>{console.log(`Process exited with code: ${code}`);});
SIGTERM 발생을 위한 종료 명령어
ps aux | grep node
해당 명령어를 통해 PID를 알아낸다.
kill -SIGTERM [PID]
알아낸 PID을 kill.
🔥 SIGINT 신호는 인식하나, SIGTERM은 인식하지 못하는 현상
로컬에서 위의 명령어를 통해 SIGTERM kill을 시도했으나 SIGTERM 로그가 남지 않고 143 코드를 남기며 종료 되었다.
SIGINT (ctrl+c)를 통한 kill의 경우에는 의도한 바 대로 로그를 남기며 정상 종료되었다.
👩🏻🚒 왜 SIGTERM 신호는 인식하지 못하는가?
stack overflow와 node.js 깃헙 이슈 답에 따르면 window환경에서 unix 스타일의 신호 (SIGTERM, SIGNUP등)를 기본적으로 지원하지 않아, Node.js에서 이런 신호를 수신하거나 처리하는 것이 제한적입니다.
Node.js는 Windows에서 process.kill() 및 ChildProcess.kill() 메서드를 통해 일부 신호를 에뮬레이트합니다. 그러나 이는 완전한 신호 지원이 아니며, 특정 신호(SIGTERM, SIGHUP 등)는 Windows에서 지원되지 않습니다.
현재 Node.js는 프론트엔드로 사용중이지 백엔드 서버로는 사용하는게 아니라서 저 부분이 적용되고 안되고에 따라 표면적으로는 큰 차이가 나지않겠지만 쿠버네티스 환경의 POD로 배포를 진행할 경우 꼭 생각해야하는 부분이니 한번 보시면서 큰 공부가 되었을 것이라고 생각됩니다.
추가로 궁금한 부분이 있는데요. SIGTERM을 받은 후 진행하는 코드에서 현재 진행중인 것들을 다 처리하고 종료하는게 아니고 강제 종료를 하는것 같다고 느낌이 드는데 맞나요? 프론트엔드에서 graceful shutdown이라하면 어떤 로직들이나 요소들을 무사히 종료시켜야하는건지 한번 더 찾아보면 좋을 것 같습니다!
현재 Node.js는 프론트엔드로 사용중이지 백엔드 서버로는 사용하는게 아니라서 저 부분이 적용되고 안되고에 따라 표면적으로는 큰 차이가 나지않겠지만 쿠버네티스 환경의 POD로 배포를 진행할 경우 꼭 생각해야하는 부분이니 한번 보시면서 큰 공부가 되었을 것이라고 생각됩니다.
추가로 궁금한 부분이 있는데요. SIGTERM을 받은 후 진행하는 코드에서 현재 진행중인 것들을 다 처리하고 종료하는게 아니고 강제 종료를 하는것 같다고 느낌이 드는데 맞나요? 프론트엔드에서 graceful shutdown이라하면 어떤 로직들이나 요소들을 무사히 종료시켜야하는건지 한번 더 찾아보면 좋을 것 같습니다!
말씀해주신대로 제가 작성해둔 방식은 로직이 활성된 것들에 대해 강제 종료(destroy())되는 명령어입니다. 다시 살펴보니 일정 시간이 지난 후에도 종료가 안되었을 때 강제 종료 시키는 전략으로 위의 코드는 수정이 필요할 거 같습니다!
일단 server.close()의 경우 새로운 연결을 받지 않도록 서버를 닫지만, 이미 존재하는 연결은 유지 시키는 역할을 합니다. 기존 연결이 모두 닫히면 서버가 완전히 종료됩니다.
node.js 공식 문서를 통해 알아본 바 node.js의 socket 연결 종료에 관한 방법은 2가지입니다.
남아 있는 데이터를 전송한 후, FIN 패킷을 보내 클라이언트와 연결을 정상적으로 종료함.
서버 또는 클라이언트가 호출할 수 있음.
클라이언트가 데이터 전송을 마치면 close 이벤트 발생.
결론
본문의 코드는 end() 와 destroy() 두 방법을 채택하여 사용하는 것이 좋을 . 거같습니다.
코드 예시
server.on('connection',(socket)=>{activeConnections.add(socket);socket.on('close',()=>{activeConnections.delete(socket);});});process.on('SIGTERM',()=>{console.log('SIGTERM received. Closing server...');server.close(()=>{console.log('Server closed. Closing active connections...');// 1️⃣ 정상 종료 시도activeConnections.forEach((socket)=>{socket.end();//Graceful Shutdown});// 2️⃣ 일정 시간 후에도 닫히지 않는다면 강제 종료setTimeout(()=>{activeConnections.forEach((socket)=>{if(!socket.destroyed){socket.destroy();// 강제 종료}});console.log('All connections closed. Exiting process.');process.exit(0);},10000);// 10초 대기 후 강제 종료});});
📝 node.js에서 graceful shutdown 적용하기
📚 주제:
📖 핵심 내용:
❓ Graceful Shutdown이란?
애플리케이션이나 서버가 종료될 때, 실행 중인 작업을 안전하게 처리하고 리소스를 정리하며 종료하는 과정을 말합니다. 이는 단순히 강제로 프로세스를 종료하는 것과는 달리, 시스템이 정상적인 상태에서 종료되도록 도와줍니다.
❔ Graceful Shutdown의 필요성
🏗️ Graceful Shutdown의 작동 방식
Node.js 기반의 Express 서버 구현 예시 코드
next.js에서 적용하기
#8 에서 작성한
server.js
에 graceful shutdown 코드를 추가하였다.SIGTERM 발생을 위한 종료 명령어
ps aux | grep node
해당 명령어를 통해 PID를 알아낸다.
kill -SIGTERM [PID]
알아낸 PID을 kill.
🔥 SIGINT 신호는 인식하나, SIGTERM은 인식하지 못하는 현상
로컬에서 위의 명령어를 통해 SIGTERM kill을 시도했으나 SIGTERM 로그가 남지 않고 143 코드를 남기며 종료 되었다.
SIGINT (ctrl+c)를 통한 kill의 경우에는 의도한 바 대로 로그를 남기며 정상 종료되었다.
👩🏻🚒 왜 SIGTERM 신호는 인식하지 못하는가?
👩🏻🚒 mac OS에서 테스트 - 성공
💡 참고 자료:
https://www.ryuollojy.com/articles/nodejs-graceful-shutdown
vercel/next.js#19693
https://velog.io/@hwisaac/NextJS-Depoyment#%EC%88%98%EB%8F%99-graceful-shutdown
vercel/next.js#60059
https://nextjs-ko.org/docs/app/building-your-application/deploying#manual-graceful-shutdowns
https://dtrunin.github.io/2022/04/05/nodejs-graceful-shutdown.html
https://stackoverflow.com/questions/63241807/nodejs-process-kill-doesnt-seem-to-work-on-windows-when-i-try-to-programaticall
https://stackoverflow.com/questions/63241807/nodejs-process-kill-doesnt-seem-to-work-on-windows-when-i-try-to-programaticall
The text was updated successfully, but these errors were encountered: