안정적인 Shutdown 대응을 위한 Health Check 전략은?

Health Check 기반 안정적인 Shutdown 대응


서문

이 글에서는 Health Check 기반 안정적인 Shutdown 대응에 대해 심도 있게 탐구해보겠습니다. 현대의 애플리케이션 아키텍처에서 안정적으로 서비스를 제공하기 위해서는 서버의 종료가 반드시 수반되어야 합니다. 특히, 서버를 종료할 때는 요청을 안전하게 처리하고 리소스를 정리하는 과정이 필요합니다. 따라서, 이 과정에서 사용되는 다양한 기술과 방법을 살펴보겠습니다.


아무도 서버가 갑자기 다운되는 것을 원하지 않죠. 특히 사용자는 하필 그때 종료해야 해?라고 속으로 한탄할 것입니다. 그러므로 건강 상태를 정확히 체크하고 안정적으로 서버를 종료할 수 있는 방법을 알아두는 것이 꼭 필요합니다.


정상적인 종료의 중요성

정상적인 종료는 애플리케이션의 안정성과 사용자 경험을 크게 향상시킵니다. 애플리케이션의 새 버전을 배포할 때 이전 버전을 안전하게 종료하는 과정은 특히 중요한데, 이를 위해 사용되는 신호인 SIGTERM에 대해 알아보겠습니다. 여기서 SIGTERM은 프로세스 종료를 요청하는 여러 신호 중 하나로, 서버는 이 신호를 받아 현재 수행 중인 작업을 마무리한 후 종료해야 합니다.

SIGTERM 신호의 처리

SIGTERM 신호를 수신하면 애플리케이션은 다음과 같은 절차를 수행해야 합니다:

  1. 새 요청 중단: 새로운 요청을 더 이상 수락하지 않으며, 이를 명시적으로 사용자에게 알리는 것이 바람직합니다.
  2. 진행 중인 요청 완료: 현재 처리 중인 요청들이 모두 완료될 때까지 기다립니다.
  3. 리소스 정리: 데이터베이스 연결 및 파일 잠금을 포함한 모든 리소스를 정리합니다.
  4. 서버 종료: 모든 작업이 완료되면 서버를 종료합니다.

여기에서 진행 중인 요청을 모두 완료하는 것이 가장 중요합니다. 만약 이를 무시하고 강제로 종료했다면, 사용자로 하여금 데이터 손실 및 불완전한 결과를 초래할 수 있습니다.

아래는 SIGTERM 신호를 처리하기 위한 코드의 간단한 예시입니다:

javascript
const server = app.listen(port)

process.on(SIGTERM, () => {
console.log(SIGTERM signal received: closing HTTP server);
server.close(() => {
console.log(HTTP server closed);
});
});

이러한 방식으로 서버는 정상적인 종료를 통해 더 나은 사용자 경험을 제공합니다.

단계 설명
1. 새로운 요청 중단 새로운 요청을 수락하지 않음
2. 진행 중 요청 완료 현재 요청을 완료할 때까지 대기
3. 리소스 정리 데이터베이스 연결 및 기타 리소스 해제
4. 서버 종료 모든 작업이 완료되면 서버 종료

상태 확인(Health Check)

상태 확인은 서버와 애플리케이션이 정상인지 체크하는 과정으로, 신뢰성과 가용성을 높여줍니다. 특히 로드 밸런서에서는 상태 확인을 통해 애플리케이션 인스턴스가 요청을 받을 준비가 되었는지 판단합니다. Kubernetes와 같은 오케스트레이션 플랫폼에서는 두 가지 종류의 상태 확인을 제공합니다.

  1. 활성 상태 확인 (Liveness Check): 애플리케이션이 살아있는지 확인합니다. 이 체크가 실패하면 Kubernetes는 컨테이너를 재시작합니다.
  2. 준비 상태 확인 (Readiness Check): 애플리케이션이 트래픽을 수용할 준비가 되었는지를 확인합니다. 이는 서비스 로드 밸런서에서 포드가 트래픽을 수용할 수 있는지를 결정합니다.

예를 들어, 상태 확인을 통해 응용 프로그램의 상태가 비정상으로 판단되면 요청을 중단하거나 장애 조치(failover) 방안을 고려할 수 있습니다. 이러한 프로세스가 없을 경우, 사용자는 불완전한 서비스에 직면할 수 있으며 이는 브랜드 이미지 손상으로 이어질 수 있습니다.

아래는 Kubernetes와 같은 플랫폼에서 이 두 가지 유형의 상태 확인을 설정하기 위한 YAML 예시입니다:

yaml
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10

readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10

상태 확인 유형 설명 실패 시 조치
활성 상태 확인 애플리케이션이 살아있는지 체크 컨테이너 재시작
준비 상태 확인 애플리케이션이 요청을 수용할 준비 여부 체크 서비스 로드 밸런서에서 제거

외부 솔루션: Terminus

Terminus는 Node.js 애플리케이션에 상태 확인과 정상 종료 논리를 추가하는 오픈 소스 프로젝트입니다. 이를 통해 개발자는 복잡한 상용구 코드를 작성할 필요 없이 쉽게 정상적인 종료와 상태 확인 기능을 사용할 수 있습니다. 사용자는 필요한 정리 및 상태 확인 로직만 제공하면 됩니다.

Terminus를 설치하는 방법은 아주 간단합니다. 다음 명령어로 설치할 수 있습니다:

bash
$ npm i @godaddy/terminus –save

이제 아래와 같은 기본 템플릿을 사용해 Terminus의 기능을 활용할 수 있습니다:

javascript
const http = require(http);
const express = require(express);
const { createTerminus } = require(@godaddy/terminus);

const app = express();

app.get(/, (req, res) => {
res.send(ok);
});

const server = http.createServer(app);

function onSignal() {
console.log(server is starting cleanup);
// 리소스 정리 로직
}

async function onHealthCheck() {
// 시스템 상태 체크 로직
}

createTerminus(server, {
signal: SIGINT,
healthChecks: { /healthcheck: onHealthCheck },
onSignal
});

server.listen(3000);

기능 설명
onSignal 서버 종료 시 호출되는 정리 로직
onHealthCheck 애플리케이션 상태를 체크하는 클린업 함수
createTerminus 옵션 다양한 신호와 상태 확인 경로 설정

이처럼 Terminus를 사용하면 명확하고도 안정적인 Shutdown을 맞이할 수 있습니다.


외부 솔루션: Lightship

Lightship은 애플리케이션의 상태, 준비 상태, 활성 상태 등을 체크하는 오픈 소스 프로젝트입니다. Lightship은 독립적으로 실행되는 HTTP 서비스로, 애플리케이션의 건강 상태를 체크할 수 있는 다양한 엔드포인트를 제공합니다. 이를 통해 도메인 공개 없이 건강 상태 체크와 관련된 HTTP 끝점을 효과적으로 생성할 수 있습니다.

Lightship 사용법은 다음과 같습니다:

bash
$ npm install lightship

사용 예시는 다음과 같습니다:

javascript
const http = require(http);
const express = require(express);
const { createLightship } = require(lightship);

const lightship = createLightship();
const app = express();

app.listen(3000, () => {
lightship.signalReady(); // 서비스 준비 완료 신호
});

기능 설명
signalReady 서비스가 준비되었음을 알리는 신호
signalNotReady 서비스가 현재 준비되지 않음을 알리는 신호

Lightship의 장점은 별도의 HTTP 서비스에서 비공식적인 상태를 체크할 수 있는 점입니다.


결론

결론적으로, Health Check 기반 안정적인 Shutdown 대응은 현대의 애플리케이션에서 필수적인 요소로 자리잡고 있습니다. 정상적인 종료를 구현함으로써 불필요한 오류를 줄이고 사용자에게 안정적인 환경을 제공할 수 있습니다. Terminus와 Lightship과 같은 외부 솔루션을 통해 개발자는 복잡한 논리 없이 손쉽게 구현할 수 있습니다.

이제 여러분도 애플리케이션의 상태 확인과 안정적인 종료를 위한 방법을 적용해보시기 바랍니다. 급작스러운 종료는 사용자에게 불편을 줄 수 있으므로 미리미리 준비해두는 것이 중요합니다. 망설이지 말고 여러분의 애플리케이션에 적용해 보세요!


자주 묻는 질문과 답변

Q1: Health Check란 무엇인가요?

A: Health Check는 애플리케이션이나 서버의 상태를 모니터링하는 방법으로, 시스템이 정상 상태인지 확인할 수 있도록 합니다.

Q2: SIGTERM 신호는 왜 사용하나요?

A: SIGTERM 신호는 애플리케이션에게 종료할 것을 요청합니다. 이 신호를 통해 애플리케이션은 현재 작업을 마무리하고 안전하게 종료할 수 있습니다.

Q3: Terminus와 Lightship은 어떤 차이가 있나요?

A: Terminus는 주로 Node.js 애플리케이션의 종료 및 상태 확인을 쉽게 하기 위한 도구이고, Lightship은 독립적으로 실행되어 HTTP 상태 체크를 수행하는 서비스입니다.

Q4: 정상적인 종료를 하지 않으면 어떤 문제가 발생하나요?

A: 정상적인 종료를 하지 않으면 데이터 흔적, 리소스 누수 및 사용자 경험 저하 등의 문제가 발생할 수 있습니다.

Q5: 상태 확인을 설정하는 방법은 무엇인가요?

A: 상태 확인은 다양한 기술을 통해 설정할 수 있으며, Kubernetes 같은 플랫폼을 사용하여 YAML 형식으로 정의할 수 있습니다.

안정적인 Shutdown 대응을 위한 Health Check 전략은?

안정적인 Shutdown 대응을 위한 Health Check 전략은?

안정적인 Shutdown 대응을 위한 Health Check 전략은?