==🚀 무중단 배포와 안정적인 서비스 종료==

1. 💡 무중단 배포의 개념과 필요성

  • ==무중단 배포==란 서비스 중단 없이 새로운 버전의 소프트웨어를 배포하는 것
  • ==다운타임==: 사용자가 서비스를 사용하지 못하는 시간
    • 기존 어플리케이션 종료 후 새 버전 배포 과정에서 발생
  • ==무중단 배포 필요성==: 다운타임 없이 사용자에게 지속적인 서비스 제공

2. ⚙️ 무중단 배포 방식

2.1. 🔄 롤링 배포 (Rolling Deployment)

  • 새 버전을 ==점진적으로 교체==하는 방식
    • 서버 요청 중단 → 새 버전 배포 → 요청 재개 (반복)
  • ==장점==:
    • 추가 자원 불필요 (가용 자원 제한 시 유용)
  • ==단점==:
    • 배포 중인 서버 트래픽 증가
    • 버전 간 호환성 문제 발생 가능성
  • ==적용 사례==:
    • 작은 변화나 충분히 테스트된 기능 업데이트

2.2. 🔵/🟢 블루/그린 배포 (Blue/Green Deployment)

  • ==신규 서버 추가 배포 방식==
    • ==블루 환경==: 기존 서버
    • ==그린 환경==: 신규 서버 (새 버전 배포)
    • 트래픽을 블루 → 그린 환경으로 전환
  • ==장점==:
    • 실제 서비스 환경에서 신 버전 테스트 가능
    • 롤백 시 트래픽 전환만으로 빠르게 복구 가능
  • ==단점==:
    • 충분한 시스템 자원 필요

2.3. Canary 카나리 배포 (Canary Deployment)

  • 새 버전으로 ==점진적으로 트래픽 전환==
    • 일부 사용자에게 먼저 새 버전 제공
    • 피드백 기반으로 안정성 평가 후 트래픽 증가
  • ==장점==:
    • 소수 사용자에게만 영향 (안정성 중요한 시스템에 적합)
    • 문제 상황 초기 발견 용이
  • ==적용 사례==:
    • 금융권 등 안정성 중시 시스템
    • 기업 이미지에 영향 줄 수 있는 실험적 기능 도입

3. 🚫 안정적인 서비스 종료

3.1. ⚠️ Hard Shutdown vs. Graceful Shutdown

  • ==Hard Shutdown==:
    • 요청 처리 중에도 즉시 어플리케이션 종료
    • 미완료 요청에 대한 응답 X
  • ==Graceful Shutdown==:
    • 요청 완료 후 어플리케이션 종료
    • 스프링에서 지원 (application.yml 설정)
    • 새 요청은 거부, 기존 요청은 완료 보장

3.2. ⏳ Graceful Shutdown 설정

  • ==application.yml==:

    server:
      shutdown: graceful # immediate (Hard Shutdown)
    spring:
      lifecycle:
        timeout-per-shutdown-phase: 10s # 기본 30초

3.3. ❗ Graceful Shutdown 사용 시 고려사항

  • ==kill -9 PID==: 강제 종료, Graceful Shutdown 무시
  • ==타임아웃 설정==:
    • 너무 길면 불필요한 대기시간 발생
    • 너무 짧으면 요청 처리 전 종료될 수 있음

대본

네 안녕하세요무중단 배포를 주제로 발표할 백엔드 테니입니다이번 발표에서는 무중단 배포를 설정하는구체적인 방법에 대해서 설명하지는 않습니다그러나 사용자에게 어떻게 안정적인 서비스를제공할 수 있을지에 대해무중단 배포와사용자에게 안정적인 서비스를 제공하는 방법에 대해서배포와 종료의 관점으로 설명드리고자 합니다목차는 무중단 배포의 개념, 무중단 배포의 방식,그리고 안정적으로 서비스 종료하기 순으로 진행이 됩니다무중단 배포는 단어 그대로서비스의 중단 없이새로운 버전의 소프트웨어를 배포하는 것입니다그러면 서비스의 중단은 왜 발생할까요?그리고 무중단 배포는 왜 필요할까요?먼저 행성이의 이야기를 들어보겠습니다지금 모우다 서비스에서 조만간 안 내면 진다라는기능을 출시하려고 하는데요이게 안 내면 진다가크루들끼리 즐길 수 있는랜덤 뽑기 기능을 제공한다고 해요벌써 재밌어 보이는데요마침 커피 내기의 안 내면 진다가 있는데행성이가 빨리 참여해 보고 싶다고 하네요마감 1분 전이라서빠르게 참여해 보도록 할게요참여를 하려고 하는데갑자기 오류가 발생하면서행성이는 아무것도 할 수가 없었습니다마감이 1분 전이라서 시간이 별로 없는데 말이죠조금 기다려보니 다시 서비스는 정상적으로 작동을 하지만참여하려고 했던 커피 내기가 마감이 되어버렸습니다이렇게 행성이는 서비스의 중단 때문에하고 싶었던 기능을 제대로 이용하지 못했는데요이렇게 사용자가 서비스를 사용하지 못하는 시간을다운타임이라고 합니다다운타임은 기존의 어플리케이션을 종료하고새로운 버전의 어플리케이션을배포하는 과정에서 발생하게 되는데요무중단 배포는 이런 다운타임 없이사용자에게 서비스를 제공하기 위해 필요합니다그럼 무중단 배포는 어떻게 다운타임을 없애는 걸까요?기본적으로 무중단 배포를 위해서는어플리케이션 서버가 2대 이상 필요합니다2대 이상의 서버가 하나는 기존의 서버를 배포하고또 하나는 새로운 버전의 서버를 배포하면서그 중간에 빈 텀이 없도록 하여다운타임을 제거할 수 있습니다다음으로 무중단 배포 방식을 세 가지를 말씀드리겠습니다더 많지만 대표적인 세 가지를 가져왔습니다Rolling, Blue/Green, Canary 배포가 있습니다먼저 롤링 배포는새 버전을 점진적으로 교체하는 방식입니다먼저 첫 번째 서버에 있는첫 번째 서버로 보내는 요청을 중단하고새로운 버전을 배포하겠습니다그리고 요청을 중단했던 것을 다시 재개하고요청을 처리합니다이때 버전 1과 버전 2가 공존하는 시점이 있는데요그래서 이때 호환성 문제가 발생할 수 있으므로주의해야 합니다다음 서버 똑같이 요청을 중단하고새롭게 배포하고 요청을 재개하도록 합니다이렇게 점진적으로 모든 서버의 버전을 교체하는 것을롤링 배포 방식이라고 합니다롤링 배포 방식은 아까 보셨다시피새로운 자원을 필요로 하지 않기 때문에가용 자원이 제한적일 경우유용하게 사용할 수 있습니다그러나 배포 진행 서버는 요청을 받을 수 없기 때문에각 서버가 부담하는 트래픽이 증가한다는 특징이 있습니다또 점진적으로 배포를 하는 것처럼롤백이 필요한 경우에도 점진적으로 하기 때문에큰 변화가 없거나이미 충분히 테스트한 기능을 업데이트하는 경우적절하게 사용할 수 있습니다다음으로 블루그린 방식입니다아마 다들 많이 들어보셨을 것 같은데요이는 신규 서버를 추가로 배포하는 방식입니다기존에 있던 서버를 블루 환경그리고 새로운 환경을 그린 환경이라고 부르는데요이 그린 환경에새로운 버전의 어플리케이션을 배포를 하고블루 환경으로 보내던 트래픽을그린 환경으로 전환하기만 하면 완료가 됩니다이렇게 간단하지만 그린 환경을 새로 배포를 해야 하는 만큼시스템 자원이 충분한 경우에 사용할 수 있습니다그리고 트래픽을 전환하기 전에 올려놨던 그린 환경이이제 곧 사용할 실제 환경이기 때문에실제 서비스 환경에서신 버전을 테스트할 수 있다는 장점이 있습니다그리고 기존의 블루 환경을 내리지 않고 유지하고 있으므로만약에 그린 환경에서 롤백할,롤백을 해야 할 만한 문제가 발생했을 때트래픽만 전환한다면빠르고 안전하게 롤백을 할 수 있습니다다음으로 카나리 방식입니다이 방식은 새 버전의 점진적으로트래픽을 전환을 하는데요새로운 버전의 서버가 있습니다이때 일부의 사용자들만 새로운 버전으로트래픽을 전환합니다그리고 이 소수의 사용자들에게 피드백을 받아이 서버가 안정적인지 판단을 합니다만약에 안정적이라는 평가를 받으면점진적으로 그 트래픽을 증가시킵니다이렇게 모든 트래픽이 새로운 버전을 향해 있다면나머지 서버들도새 버전을 배포할 수 있습니다이 카나리 방식은 아까 점진적으로 사용자를 늘리기 때문에초반에 소수의 사용자들 문제가 생겨도소수의 사용자들에게만 영향을 미치게 됩니다그래서 금융권처럼 안정성이 중요한 시스템인 경우유용하게 사용할 수 있습니다그리고 문제 상황을 초기에 발견이 가능하기 때문에기업의 이미지에 영향을 미칠 만한 새로운 기능이나실험적 기능을 도입하는 경우에 사용하기 좋습니다지금까지 무중단 서비스를 안정적으로 배포하기 위해무중단 배포의 종류와 그리고 그 특징을 알아봤는데요이제는 그러면 어떻게 해야서비스를 안정적으로 종료할 수 있을지에 대해 알아보겠습니다만약에 처리 중에 어플리케이션을 종료하면 어떻게 될까요?이를 설명하기 위해 Hard Shutdown과Graceful shutdown이라는 키워드를 준비해왔습니다Hard Shutdown은저희가 스프링에 딱히 다른 설정을 하지 않았다면기본적으로 사용하게 되는 방식인데요요청을 처리하고 있더라도요청을 처리하고 있는 와중에어플리케이션을 종료하겠다고 하면그 즉시 종료를 해버립니다그러면 요청은 제대로 응답을 반환하지 못하겠죠그리고 Graceful shutdown은 Hard Shutdown의 반대말인데직역하면 우아한 종료 정도로 해석할 수 있습니다이 방식은 요청을 처리 중이라면어플리케이션을 종료하라는 방식으로 명령이 떨어져도그 즉시 종료하는 것이 아니라처리하던 요청을 끝까지 처리한 후 종료하게 됩니다그러면 Hard Shutdown과 Graceful shutdown을예시로 한번 비교해 보면서 살펴보겠습니다여기 간단한 테스트 API를 하나 가지고 왔는데요요청이 들어오면 start 로그를 찍고10초간 기다리고 finish 로그를 찍고success를 반환하게 됩니다먼저 Hard Shutdown부터 살펴보겠습니다테스트 경로로 먼저 요청을 보냅니다그런데 응답을 반환하기 전에어플리케이션을 종료하게 된다면저희가 원하던 응답을 받을 수가 없겠죠로그도 한번 확인해 볼게요그러면 start는 잘 찍혀 있지만 finish는 잘 찍히지 않은 상태로어플리케이션이 종료된 것을 확인할 수 있습니다아까 행성이처럼 같은 응답을 받게 되겠죠다음으로 Graceful Shutdown에 대해서조금 더 설명하고 테스트를 해보겠습니다Spring은 Graceful Shutdown을 지원을 하는데요기존 요청은 완료할 수 있지만새로운 요청은 허용하지 않습니다이를 설정하는 방법은 굉장히 간단한데요application.yml 파일에서server shutdown을 graceful로 설정하면완료가 됩니다default 값은 immediate로즉시 바로 받는다는 의미인데요이는 Hard Shutdown이라고 이해하시면 되겠습니다그리고 이 요청을 받았을 때무한으로 대기한다고 해서이게 해결되는 문제는 아니잖아요그래서 어느 정도 유예기간을 두고그 기간 내에 요청이 처리된다면 응답을 반환하지만그 이상으로 대기가 길어진다면스프링도 바로 종료를 해버립니다그 시간을 설정하는 부분이 spring, lifecycle,timeout-per-shutdown-phase 이 부분입니다디폴트는 30초지만저희는 10초를 해서 테스트를 진행해 볼게요아까와 마찬가지로 테스트 경로로 요청을 보냅니다그리고 응답이 오기 전에 어플리케이션을 종료를 한다면종료를 해도 저희가 원하던 success 응답을받을 수가 있습니다로그도 확인해 보면 start가 잘 찍혀 있고finish도 잘 찍혀 있습니다그리고 그 사이에 Graceful Shutdown을 시작을 했고요청을 완료하기 위해 대기 중이다라는 메시지도 확인할 수 있어요마지막으로 Graceful Shutdown을 사용했을 때고려할 점을 말씀드리면서 마무리하려고 하는데요저희 Kill -9 PID 많이들 사용하시는 명령어죠그런데 이 명령어는 프로세스를 강제 종료하기 때문에Graceful Shutdown 설정도 무시해버리고즉시 종료하게 됩니다그리고 타임아웃의 경우그럼 길면 좋은 거 아닌가요? 라고 생각할 수 있지만불필요한 대기시간이 발생할 수 있으며너무 짧게 설정해도 요청이 처리되기 전에 종료되므로Graceful shutdown의 의미를 잘 가질 수 없다는 점기억해 주시길 바랍니다여기까지 발표 마무리하겠습니다 감사합니다