Health Check 기반 안정적인 Shutdown 대응

$ npm i @godaddy/terminus --save

이번 글에서는 Health Check를 통한 Shutdown 대응 방법에 대해 알아보도록 하겠습니다.

정상적인 종료

애플리케이션의 새 버전을 배포할 때 이전 버전을 교체해야 합니다. 사용 중인 프로세스 관리자는 먼저 응용 프로그램에 SIGTERM 신호를 보내 응용 프로그램이 종료될 것임을 알립니다.

애플리케이션이 이 신호를 받으면 새 요청 수락을 중지하고 진행 중인 모든 요청을 완료하고 데이터베이스 연결 및 파일 잠금을 포함하여 사용한 리소스를 정리한 다음 종료해야 합니다.

const server = app.listen(port)

process.on('SIGTERM', () => {
  debug('SIGTERM signal received: closing HTTP server')
  server.close(() => {
    debug('HTTP server closed')
  })
})

상태 확인

로드 밸런서는 상태 확인을 사용하여 애플리케이션 인스턴스가 정상이고 요청을 수락할 수 있는지 확인합니다. 예를 들어 Kubernetes에는 두 가지 상태 확인이 있습니다.

  • 컨테이너를 다시 시작할 시기를 결정하는 활동성.
  • 컨테이너가 트래픽 수락을 시작할 준비가 된 시점을 결정하는 준비 상태. 포드가 준비되지 않은 경우 서비스 로드 밸런서에서 제거됩니다.

외부 솔루션

Terminus

Terminus는 상용구 코드를 작성할 필요가 없도록 애플리케이션에 상태 확인 및 정상적인 종료를 추가하는 오픈 소스 프로젝트입니다. 정상적인 종료를 위한 정리 논리와 상태 확인을 위한 상태 확인 논리만 제공하면 터미널이 나머지를 처리합니다.

다음과 같이 터미널을 설치합니다.

$ npm i @godaddy/terminus --save

다음은 터미널 사용을 설명하는 기본 템플릿입니다. 자세한 내용은 https://github.com/godaddy/terminus를 참조하십시오.

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')
  // start cleanup of resource, like databases or file descriptors
}

async function onHealthCheck () {
  // checks if the system is healthy, like the db connection is live
  // resolves, if health, rejects if not
}

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

server.listen(3000)

Lightship

Lightship은 애플리케이션에 상태, 준비 및 활성 검사를 추가하는 오픈 소스 프로젝트입니다. Lightship은 별도의 HTTP 서비스로 실행되는 독립형 HTTP 서비스입니다. 이를 통해 공개 인터페이스에 노출하지 않고도 health-readiness-liveness HTTP 끝점을 가질 수 있습니다.

다음과 같이 Lightship을 설치합니다.

$ npm install lightship

Lightship 사용을 설명하는 기본 템플릿:

const http = require('http')
const express = require('express')
const {
  createLightship
} = require('lightship')

// Lightship will start a HTTP service on port 9000.
const lightship = createLightship()

const app = express()

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

app.listen(3000, () => {
  lightship.signalReady()
})

// You can signal that the service is not ready using `lightship.signalNotReady()`.

Lightship 설명서는 해당 Kubernetes 구성의 예와 Express.js와의 완전한 통합 예를 제공합니다.

http-terminator

http-terminator는 express.js 서버를 정상적으로 종료하기 위한 논리를 구현합니다. Node.js에서 HTTP 서버를 종료하려면 열려 있는 모든 연결을 추적하고 서버가 종료된다는 신호를 보내야 합니다.

http-terminator는 시간 초과 시 모든 연결 및 종료를 추적하는 논리를 구현합니다. 또한 http-terminator는 현재 이 서버로부터 응답을 받고 있는 모든 클라이언트를 종료하려는 서버 의도의 정상적인 통신을 보장합니다.

다음과 같이 http-terminator를 설치합니다.

$ npm install http-terminator

http-terminator 사용을 설명하는 기본 템플릿:

const express = require('express')
const { createHttpTerminator } = require('http-terminator')

const app = express()

const server = app.listen(3000)

const httpTerminator = createHttpTerminator({ server })

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

// A server will terminate after invoking `httpTerminator.terminate()`.
// Note: Timeout is used for illustration of delayed termination purposes only.
setTimeout(() => {
  httpTerminator.terminate()
}, 1000)

http-terminator 문서는 API 문서 및 기존 타사 솔루션과의 비교를 제공합니다.

express-actuator

express-actuator는 애플리케이션을 모니터링하고 관리하는 데 도움이 되는 엔드포인트를 추가하는 미들웨어입니다.

다음과 같이 익스프레스 액추에이터를 설치합니다.

$ npm install --save express-actuator

express-actuator 사용을 설명하는 기본 템플릿:

const express = require('express')
const actuator = require('express-actuator')

const app = express()

app.use(actuator())

app.listen(3000)

express-actuator 설명서는 사용자 지정을 위한 다양한 옵션을 제공합니다.

error: Content is protected !!